#+PROPERTY: header-args:emacs-lisp :tangle "~/.emacs.d/config-org.el" :comments both * The all-mighty org configuration #+begin_src emacs-lisp (require 'my-org) (require 'my-org-agenda-files) #+end_src * Plugins ** fstree #+BEGIN_SRC (add-to-list 'load-path (ef "submodule/org-fstree")) (require 'org-fstree) #+END_SRC ** org-bullets #+BEGIN_SRC (use-package org-bullets) (when (not (eq system-type 'windows-nt)) (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))) #+END_SRC ** calfw-org #+BEGIN_SRC emacs-lisp (use-package calfw) (use-package calfw-ical) (use-package calfw-gcal) (use-package calfw-org) (global-set-key (kbd "C-c A") 'cfw:open-org-calendar) (setq cfw:org-overwrite-default-keybinding t) #+END_SRC ** sync with google calendar #+BEGIN_SRC emacs-lisp# (defvar url-http-method) (defvar url-http-data) (defvar url-http-extra-headers) (defvar oauth--token-data) (defvar url-callback-function) (require 'url-http) (unless (package-installed-p 'org-caldav) (use-package oauth2) (use-package org-caldav)) (setq epa-pinentry-mode 'loopback) (setq plstore-cache-passphrase-for-symmetric-encryption t) (save-excursion (let ((filename (ef "google-calendar-secret.el"))) (when (file-exists-p filename) (set-buffer (find-file-noselect filename)) (let ((var (eval (read (buffer-string))))) (setq org-caldav-oauth2-client-id (car var) org-caldav-oauth2-client-secret (cadr var))) (kill-buffer)))) ;; (setq org-caldav-url 'google ;; org-caldav-calendar-id "jqeua8pamjrclakq3bg8mpnlis@group.calendar.google.com" ;; org-caldav-inbox "~/MEGA/org/agenda/test.org" ;; org-caldav-files '("~/MEGA/org/agenda/agenda.org") ;; org-icalendar-include-todo nil ;; org-icalendar-include-sexps t ;; org-icalendar-categories '(all-tags category) ;; org-icalendar-use-deadline '(event-if-todo event-if-not-todo todo-due) ;; org-icalendar-use-scheduled '(event-if-todo event-if-not-todo todo-start) ;; org-icalendar-with-timestamps nil ;; org-caldav-delete-org-entries 'never) (setq org-caldav-url "https://99.57.234.31/remote.php/dav/calendars/bchu" org-caldav-calendar-id "orgmode" org-caldav-inbox "~/MEGA/org/agenda/test.org" org-caldav-files '("~/MEGA/org/agenda/agenda.org" "~/MEGA/org/agenda/classes_caldav_workaround.org")) (setq org-icalendar-alarm-time 30 org-icalendar-include-todo nil org-icalendar-include-sexps t org-icalendar-categories '(all-tags category) org-icalendar-use-deadline '(event-if-todo event-if-not-todo todo-due) org-icalendar-use-scheduled '(todo-start event-if-todo) org-icalendar-with-timestamps nil org-caldav-delete-org-entries 'never) (setq org-caldav-skip-conditions '(nottodo ("TODO" "NEXT")) org-caldav-exclude-tags '("ARCHIVE" "_nosync_")) #+END_SRC ** Reveal.js #+begin_src (use-package org-re-reveal) (setq org-re-reveal-root "file:///home/benson/.reveal.js") #+end_src *** Old ox-reveal package #+BEGIN_SRC (add-to-list 'load-path (ef "submodule/org-reveal")) (require 'ox-reveal) (setq org-reveal-root "file:///home/benson/.reveal.js") (setq org-structure-template-alist (remove-if (lambda (c) (string= (car c) "n")) org-structure-template-alist)) #+END_SRC ** org-timeline #+BEGIN_SRC emacs-lisp (use-package org-timeline) (remove-hook 'org-agenda-finalize-hook 'org-timeline-insert-timeline) #+END_SRC ** Code-blocks #+BEGIN_SRC emacs-lisp (require 'ob-core) (require 'ob-clojure) (require 'ob-plantuml) (use-package plantuml-mode) (setq org-babel-clojure-backend 'cider) (org-babel-do-load-languages 'org-babel-load-languages '((clojure . t) (plantuml . t) (emacs-lisp . t) (shell . t) (dot . t))) (defun my-org-confirm-babel-evaluate (lang body) (not (member lang '("plantuml")))) (setq org-confirm-babel-evaluate 'my-org-confirm-babel-evaluate) (setq org-plantuml-jar-path "/usr/share/java/plantuml/plantuml.jar") #+END_SRC ** helm-org-rifle #+begin_src emacs-lisp (use-package helm-org-rifle) (global-set-key (kbd "C-c o r") 'helm-org-rifle) (setq helm-org-rifle-test-against-path t) #+end_src ** org-mru-clock #+begin_src emacs-lisp (use-package org-mru-clock) #+end_src ** org-clock-convenience #+begin_src emacs-lisp (defun my/org-clock-move-to-other () (interactive) (forward-char 6) (while (condition-case nil (progn (previous-line) (org-clock-convenience-goto-ts) nil) (error t)))) (defun my/org-clock-move-up () (interactive) (org-clock-convenience-timestamp-up) (my/org-clock-move-to-other) (org-clock-convenience-timestamp-up)) (use-package org-clock-convenience :ensure t :bind (:map org-agenda-mode-map ("" . org-clock-convenience-timestamp-up) ("" . org-clock-convenience-timestamp-down) ("" . org-clock-convenience-timestamp-up) ("" . org-clock-convenience-timestamp-down) ("ö" . org-clock-convenience-fill-gap) ("é" . org-clock-convenience-fill-gap-both))) #+end_src ** org-clock-consisitency #+begin_src emacs-lisp (setq org-agenda-clock-consistency-checks '(:max-duration "10:00" :min-duration 0 :max-gap 0 :gap-ok-around ("4:00") ;; :default-face ((:background "DarkRed") ;; (:foreground "white")) ;; :overlap-face nil ;; :gap-face ((:background "DarkRed") ;; (:foreground "white")) ;; :no-end-time-face nil ;; :long-face nil ;; :short-face nil )) #+end_src ** org-clock stuff #+begin_src emacs-lisp (org-clock-persistence-insinuate) (setq org-clock-in-resume t) (setq org-clock-mode-line-total 'today) (setq org-clock-persist t) (org-clock-persistence-insinuate) (setq org-clock-continuously t) #+end_src ** org-brain #+begin_src (use-package org-brain :ensure t :init (global-set-key (kbd "M-'") 'org-brain-visualize) (setq org-brain-path "~/MEGA/org/brain/") ;; For Evil users (with-eval-after-load 'evil (evil-set-initial-state 'org-brain-visualize-mode 'emacs)) :config (setq org-id-track-globally t) (setq org-id-locations-file (ef ".org-id-locations")) (push '("b" "Brain" plain (function org-brain-goto-end) "* %i%?" :empty-lines 1) org-capture-templates) (setq org-brain-visualize-default-choices 'all) (setq org-brain-title-max-length 0) (define-key org-brain-visualize-mode-map (kbd "^") 'org-brain-visualize-back)) #+end_src ** Open links with firefox #+begin_src emacs-lisp (when (not my-ec/is-wsl) (setq browse-url-browser-function 'browse-url-firefox)) #+end_src ** org-export #+begin_src emacs-lisp (require 'ox-latex) (require 'ox-beamer) #+end_src ** org-jira #+BEGIN_SRC emacs-lisp (use-package org-jira) (setq jiralib-url "https://wenningbai.atlassian.net/") #+END_SRC ** org-now #+begin_src emacs-lisp (add-to-list 'load-path (ef "submodule/org-now")) (require 'org-now) (setq org-now-location nil) #+end_src * More alternative views #+begin_src emacs-lisp (defun cfw:open-org-calendar-no-projects (&args) "Open an org schedule calendar in the new buffer." (interactive) (save-excursion (let ((buf (get-buffer "*cfw-calendar*"))) (if buf (switch-to-buffer buf) (let* ((org-agenda-skip-function 'my/agenda-custom-skip) (source1 (cfw:org-create-source)) (curr-keymap (if cfw:org-overwrite-default-keybinding cfw:org-custom-map cfw:org-schedule-map)) (cp (cfw:create-calendar-component-buffer :view 'two-weeks :contents-sources (list source1) :custom-map curr-keymap :sorter 'cfw:org-schedule-sorter))) (switch-to-buffer (cfw:cp-get-buffer cp)) (set (make-variable-buffer-local 'org-agenda-skip-function) 'my/agenda-custom-skip) (when (not org-todo-keywords-for-agenda) (message "Warn : open org-agenda buffer first."))) )))) #+end_src * Stuff :FIX: #+begin_src (setq org-agenda-tags-todo-honor-ignore-options t) (defun bh/org-auto-exclude-function (tag) "Automatic task exclusion in the agenda with / RET" (when (string= tag "online") (concat "-" tag))) (org-defkey org-agenda-mode-map "A" 'org-agenda) (setq org-agenda-auto-exclude-function 'bh/org-auto-exclude-function) (setq org-agenda-skip-deadline-prewarning-if-scheduled 'pre-scheduled) (setq org-agenda-skip-scheduled-if-deadline-is-shown nil) (setq org-agenda-log-mode-items '(clock closed)) (defun org-agenda-add-separater-between-project () (setq buffer-read-only nil) (save-excursion (goto-char (point-min)) (let ((start-pos (point)) (previous t)) (re-search-forward " +agenda: +[^\\. ]" nil t) (while (re-search-forward " +agenda: +[^\\. ]" nil t) (beginning-of-line) (insert "=============================================\n") (forward-line))))) ;; I don't think this code is necessary ;; (add-to-list 'org-agenda-entry-types :deadlines*) (setq org-agenda-hide-tags-regexp "NOT_TASKS\\|PROJECT") (use-package htmlize) (org-super-agenda-mode) (setq org-super-agenda-header-separator "") #+end_src * Checkbox hack #+BEGIN_SRC emacs-lisp (defun my/org-checkbox-todo () "Switch header TODO state to DONE when all checkboxes are ticked, to TODO otherwise" (let ((todo-state (org-get-todo-state)) beg end) (unless (not todo-state) (save-excursion (org-back-to-heading t) (setq beg (point)) (end-of-line) (setq end (point)) (goto-char beg) (if (re-search-forward "\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]" end t) (if (match-end 1) (if (equal (match-string 1) "100%") (unless (string-equal todo-state "DONE") (org-todo 'done)) (unless (string-equal todo-state "TASK") (org-todo 'todo))) (if (and (> (match-end 2) (match-beginning 2)) (equal (match-string 2) (match-string 3))) (unless (string-equal todo-state "DONE") (org-todo 'done)) (unless (string-equal todo-state "TASK") (org-todo "TASK"))))))))) (add-hook 'org-checkbox-statistics-hook 'my/org-checkbox-todo) #+END_SRC * View org files #+BEGIN_SRC emacs-lisp (defun make-org-file (filename) "Make an org buffer in folder for all new incoming org files" (interactive "MName: ") (switch-to-buffer (find-file-noselect (concat "~/MEGA/org/random/" filename ".org")))) (defun make-encrypted-org-file (filename) (interactive "MName: ") (switch-to-buffer (find-file-noselect (concat "~/MEGA/org/random/" filename ".gpg"))) (insert "# -*- mode:org; epa-file-encrypt-to: (\"bensonchu457@gmail.com\") -*-\n\n") (org-mode)) (defun view-org-files () "Convenient way for openning up org folder in dired" (interactive) (dired "~/MEGA/org/")) #+END_SRC * Parallel org-tags-views #+begin_src emacs-lisp ;; TODO #+end_src * refile to datetree #+begin_src emacs-lisp (defun my/org-read-datetree-date (d) "Parse a time string D and return a date to pass to the datetree functions." (let ((dtmp (nthcdr 3 (parse-time-string d)))) (list (cadr dtmp) (car dtmp) (caddr dtmp)))) (defun my/org-refile-to-archive-datetree (&optional bfn) "Refile an entry to a datetree under an archive." (interactive) (require 'org-datetree) (let* ((org-read-date-prefer-future nil) (bfn (or bfn (find-file-noselect (expand-file-name (my/agenda-file "datetree.org"))))) (datetree-date (my/org-read-datetree-date (org-read-date t nil)))) (org-refile nil nil (list nil (buffer-file-name bfn) nil (with-current-buffer bfn (save-excursion (org-datetree-find-date-create datetree-date) (point)))))) (setq this-command 'my/org-refile-to-journal)) #+end_src * org-link use qutebrowser #+begin_src emacs-lisp (defun my/browse-url-qutebrowser (url &optional new-window) (interactive) (start-process (concat "qutebrowser " url) nil "qutebrowser" url)) ;;(setq browse-url-browser-function #'my/browse-url-qutebrowser) ;;(setq browse-url-browser-function #'browse-url-firefox) #+end_src * new headline set property #+begin_src emacs-lisp (defun my/org-set-created-property (&rest args) (when-let (f (buffer-file-name)) (let ((fname (expand-file-name f))) (when (remove-if-not (lambda (x) (string= fname (expand-file-name x))) org-agenda-files) (let ((ts (format-time-string "[%Y-%m-%d %a %H:%M]"))) (org-set-property "CREATED" ts)))))) (advice-add #'org-insert-heading :after #'my/org-set-created-property) #+end_src * Code for deleting empty blocks #+begin_src emacs-lisp (defvar my/delete-blocks t) (defun org-agenda-delete-empty-compact-blocks () "Function removes empty compact blocks. If two lines next to each other have the org-agenda-structure face, then delete the previous block." (unless org-agenda-compact-blocks (user-error "Compact blocks must be on")) (when my/delete-blocks (setq buffer-read-only nil) (save-excursion (goto-char (point-min)) (let ((start-pos (point)) (previous nil)) (while (not (eobp)) (cond ((let ((face (get-char-property (point) 'face))) (or (eq face 'org-agenda-structure) (eq face 'org-agenda-date-today))) (if previous (delete-region start-pos (point)) (setq start-pos (point))) (unless (org-agenda-check-type nil 'agenda) (setq previous t))) (t (setq previous nil))) (forward-line)))) (setq buffer-read-only t))) (add-hook 'org-agenda-finalize-hook #'org-agenda-delete-empty-compact-blocks) #+end_src * Highlight top priority projects #+begin_src emacs-lisp (defvar my/highlight-top-priority t) (defun org-agenda-highlight-top-priority () (when my/highlight-top-priority (setq buffer-read-only nil) (save-excursion (goto-char (point-min)) (let ((start-pos (point)) (previous nil)) (while (re-search-forward "\\[#A\\]" nil t) (add-face-text-property (point-at-bol) (point-at-eol) '(:background "color-19"))))) (setq buffer-read-only t))) (add-hook 'org-agenda-finalize-hook #'org-agenda-highlight-top-priority) #+end_src * org-notmuch #+begin_src emacs-lisp (use-package notmuch :config (use-package ol-notmuch)) #+end_src * remove inherited tags #+begin_src emacs-lisp (defun my/org-remove-inherited-tag-strings () "Removes inherited tags from the headline-at-point's tag string. Note this does not change the inherited tags for a headline, just the tag string." (interactive) (org-set-tags (seq-remove (lambda (tag) (get-text-property 0 'inherited tag)) (org-get-tags)))) (defun my/org-clean-tags () "Visit last refiled headline and remove inherited tags from tag string." (save-window-excursion (org-refile-goto-last-stored) (my/org-remove-inherited-tag-strings))) (defun my/org-refile-preserve-tags (orig &rest args) (let ((tags (org-get-tags))) (apply orig args))) (add-hook 'org-after-refile-insert-hook 'my/org-clean-tags) #+end_src * archive sibling remove sub archive sibling #+begin_src emacs-lisp (defun my/is-archive-tree () (and (string= "Archive" (org-get-heading t t t t)) (member "ARCHIVE" (org-get-tags)))) (defun my/archive-remove-all-sibling (&rest args) (save-excursion (let (points) (ol/descendants (when (my/is-archive-tree) (push (point) points))) (mapcar (lambda (p) (goto-char p) (my/org-delete-promote)) points)))) (advice-add #'org-archive-to-archive-sibling :before #'my/archive-remove-all-sibling) #+end_src * Learning chinese, setup org-drill #+begin_src emacs-lisp (use-package org-drill) (defun org-drill-present-one-side-always (session) (org-drill-with-hidden-comments (org-drill-with-hidden-cloze-hints (org-drill-with-hidden-cloze-text (let ((drill-sections (org-drill-hide-all-subheadings-except nil))) (when drill-sections (save-excursion (goto-char (nth 0 drill-sections)) (org-show-subtree))) (org-drill--show-latex-fragments) (ignore-errors (org-display-inline-images t)) (org-cycle-hide-drawers 'all) (prog1 (org-drill-presentation-prompt session) (org-drill-hide-subheadings-if 'org-drill-entry-p))))))) (add-to-list 'org-drill-card-type-alist '("oneside" org-drill-present-one-side-always nil t)) ;; (pop org-drill-card-type-alist) #+end_src * Insert inactive timestamp after last org-datetree--find-create #+begin_src emacs-lisp (defun org-datetree--find-create-add-timestamp (&rest args) (save-excursion (when day (let ((lnum (line-number-at-pos))) (next-line) (when (= lnum (line-number-at-pos)) (end-of-line) (insert "\n"))) (unless (looking-at-p (rx "[" (repeat 4 digit) "-" (repeat 2 digit) "-" (repeat 2 digit) " " (repeat 3 alpha) "]")) (insert (format-time-string "[%Y-%m-%d %a]")))))) (advice-add #'org-datetree--find-create :after #'org-datetree--find-create-add-timestamp) #+end_src * I'm bored #+begin_src emacs-lisp (defun im-bored () (interactive) (org-ql-search (append org-agenda-files (list (my/agenda-file "when_im_bored.org") (my/agenda-file "eternal.org"))) '(and (tags-local "bored")))) #+end_src * org-noter #+begin_src emacs-lisp (use-package org-noter :config ;; (unless (eq 'hash-table (type-of face-new-frame-defaults)) ;; (require 'face-copier) ;; (def-face-copier x-show-tip-faces (sym) ;; nil ;; tooltip) ;; (defun dont-copy-faces-for-x-show-tip (orig &rest args) ;; (override1-face x-show-tip-faces ;; (apply orig args))) ;; (advice-add #'x-show-tip ;; :around ;; #'dont-copy-faces-for-x-show-tip)) ) (use-exwm :config (setq org-noter-always-create-frame nil)) #+end_src * turn into tickle #+begin_src emacs-lisp (defun my/tickle-todo () (interactive) (org-agenda-todo "TICKLER") (org-agenda-schedule)) (define-key org-agenda-mode-map (kbd "T") #'my/tickle-todo) #+end_src * org-wiki :FIX: #+begin_src (require 'org-wiki) (setq org-wiki-location-list '("~/MEGA/org/wiki")) (setq org-wiki-template "#+TITLE: %n\n#+DESCRIPTION:\n#+KEYWORDS:\n#+STARTUP: content\n\n\n- Related: \n\n* Backlinks\n#+STARTUP: folded\n\n* %n\n") (defun org-wiki-insert-backlink (back-from back-to) (let ((wiki-link (format "[[wiki:%s][%s]]" back-to back-to)) (file (save-window-excursion (org-wiki--open-page back-from) (current-buffer)))) (with-current-buffer file (beginning-of-buffer) (when (not (save-excursion (search-forward wiki-link nil t))) (search-forward "* Backlinks") (forward-line 2) (beginning-of-line) (insert "- " wiki-link "\n") (save-buffer))))) (defun my/org-wiki-insert-new () (interactive) (let ((page-name (read-string "Page: "))) (save-excursion (insert (org-make-link-string (concat "wiki:" page-name) page-name ))) (org-wiki-insert-backlink page-name (org-wiki--current-page)))) (advice-add #'org-wiki-insert-new :override #'my/org-wiki-insert-new) (defun my/org-wiki-insert-link () "Insert a Wiki link at point for a existing page." (interactive) (org-wiki--helm-selection (lambda (page) (insert (org-wiki--make-link page)) (org-wiki-insert-backlink page (org-wiki--current-page))))) (advice-add #'org-wiki-insert-link :override #'my/org-wiki-insert-link) #+end_src * Variable pitch org-mode #+begin_src emacs-lisp ;; (mapcar ;; (lambda (face) ;; (set-face-attribute face nil :inherit 'fixed-pitch)) ;; '(org-block org-block-begin-line org-block-end-line org-code ;; org-document-info-keyword org-done org-formula org-indent ;; org-meta-line org-special-keyword org-table org-todo ;; org-verbatim org-date org-drawer)) #+end_src * Restriction from org-agenda #+begin_src emacs-lisp (define-key org-agenda-mode-map (kbd "N") #'(lambda () (interactive) (org-agenda-set-restriction-lock-from-agenda nil) (org-agenda-redo))) (define-key org-agenda-mode-map (kbd "U") #'org-agenda-remove-restriction-lock) #+end_src * Org mode magit update commands #+begin_src (when (executable-find "~/bin/gitwatch") (defun start-gitwatch () (interactive) (if (and gitwatch-process (process-live-p gitwatch-process)) (message "gitwatch already exists") (setq gitwatch-process (start-process-shell-command "gitwatch" nil "~/bin/gitwatch -r origin -b laptop -m 'Gitwatch commit: %d' ~/MEGA/org/agenda")))) (defun kill-gitwatch () (interactive) (when (and gitwatch-process (process-live-p gitwatch-process)) (kill-process gitwatch-process))) (defvar gitwatch-process nil) (add-to-list 'emacs-startup-hook #'start-gitwatch)) (defvar magit-sentinel-after-function nil) (defun magit-sentinel-after (&rest args) (while (when-let (fun (pop magit-sentinel-after-function)) (funcall fun) t))) (advice-add #'magit-process-sentinel :after #'magit-sentinel-after) (defun org-update-main () (interactive) (let ((default-directory "~/MEGA/org/agenda")) (kill-gitwatch) ;; Make sure local changes are committed (when (magit-changed-files "HEAD") (magit-stage-modified t) (magit-commit-create `("-m" ,(format "Pre-merge commit: %s" (format-time-string "%D %T"))))) ;; Update all submodules (shell-command "git submodule foreach git pull origin master") (when (magit-changed-files "HEAD") (magit-stage-modified t) (magit-commit-create `("-m" ,(format "Updated submodules: %s" (format-time-string "%D %T"))))) ;; Do a fetch (push #'org-update-initiate-merge magit-sentinel-after-function) (magit-run-git-async '("fetch" "--all")))) (defun org-update-initiate-merge () ;; Check if mobile has updated (let ((base (vc-git-mergebase "laptop" "origin/mobile")) (laptop (vc-git--rev-parse "laptop")) (origin-mobile (vc-git--rev-parse "origin/mobile"))) ;; If so, turn off gitwatch and initiate a merge. (when (and (not (string= base laptop)) (not (string= base origin-mobile))) (add-hook 'git-commit-post-finish-hook ;;magit-post-commit-hook #'org-update-post-commit) (magit-merge-plain "origin/mobile")))) (defun org-update-post-commit () ;; After merge, do a push to both laptop and mobile ;; Also restart gitwatch (call-interactively #'magit-push-current-to-upstream) (magit-push-current "origin/mobile" nil) (start-gitwatch) (remove-hook 'git-commit-post-finish-hook #'org-update-post-commit)) (magit-run-git-async '("fetch" "--all")) ;; (setq debug-the-process (magit-run-git-async '("fetch" "--all") ;; :sentinel '(lambda (process event) (message "Done")))) #+end_src * elgantt #+begin_src emacs-lisp (add-to-list 'load-path (ef "submodule/elgantt")) (require 'elgantt) #+end_src * org-kanban #+begin_src emacs-lisp (use-package org-kanban) (defun my/org-dblock-write:kanban (params) "Create the kanban dynamic block. PARAMS may contain `:mirrored`, `:match`, `:scope`, `:layout`, `:range`, `:depth` and `:compressed`." (insert (let* ( (mirrored (plist-get params :mirrored)) (compressed (plist-get params :compressed)) (match (plist-get params :match)) (range (plist-get params :range)) (depth (org-kanban--params-depth params)) (layout (org-kanban//params-layout params)) (files (org-kanban//params-files params)) (scope (org-kanban//params-scope params files)) (todo-keywords (split-string (plist-get params :todo) "|")) (sort-spec-string (plist-get params :sort)) (sort-spec (org-kanban--prepare-comparator sort-spec-string todo-keywords)) (todo-infos (org-map-entries 'org-kanban//todo-info-extract match scope)) (sorted-todo-infos (if sort-spec (-sort sort-spec todo-infos) todo-infos)) (filtered-todo-infos (-filter (lambda (todo-info) (org-kanban//range-fun (org-kanban--todo-info-get-keyword todo-info) (org-kanban//todo-info-get-keywords todo-info) (car range) (cdr range))) sorted-todo-infos)) (filtered-todo-infos (-filter (lambda (todo-info) (if (eq scope 'tree) (let* ( (tree-info (nth 0 todo-infos)) (tree-level (org-kanban--todo-info-get-level tree-info))) (< (org-kanban--todo-info-get-level todo-info) (+ depth tree-level))) (<= (org-kanban--todo-info-get-level todo-info) depth))) filtered-todo-infos)) (filtered-todo-infos (-filter (lambda (todo-info) (nth 4 (org-kanban//todo-info-get-heading todo-info))) filtered-todo-infos)) (row-for (lambda (todo-info) (org-kanban//row-for todo-info todo-keywords layout))) (table-title (string-join todo-keywords "|")) (filtered (-filter (lambda (todo-info) (-intersection (list (org-kanban//heading-get-todo-keyword (org-kanban//todo-info-get-heading todo-info))) (org-kanban//todo-info-get-keywords todo-info))) filtered-todo-infos)) (table (if compressed (org-kanban//compressed-rows (-map row-for filtered)) (let* ((rows (-map row-for filtered))) (if rows (--reduce (format "%s\n%s" acc it) rows) "" ))))) (format "|%s|\n|--|\n%s" table-title table))) (org-table-align)) (advice-add #'org-dblock-write:kanban :override #'my/org-dblock-write:kanban) #+end_src * Modern views #+begin_src emacs-lisp (quelpa `(org-timeblock :repo "ichernyshovvv/org-timeblock" :fetcher github)) (use-package org-hyperscheduler) #+end_src * Pretty symbols #+begin_src emacs-lisp ;; (add-hook 'org-mode-hook (lambda () ;; "Beautify Org Checkbox Symbol" ;; (push '("[ ]" . "☐") prettify-symbols-alist) ;; (push '("[X]" . "☑" ) prettify-symbols-alist) ;; (push '("[-]" . "❍" ) prettify-symbols-alist) ;; (prettify-symbols-mode))) #+end_src