mirror of
https://github.com/pestctrl/emacs-config.git
synced 2026-02-16 08:14:15 +00:00
845 lines
31 KiB
Org Mode
845 lines
31 KiB
Org Mode
#+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 emacs-lisp
|
|
(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)))
|
|
|
|
(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
|
|
("<S-up>" . org-clock-convenience-timestamp-up)
|
|
("<S-down>" . org-clock-convenience-timestamp-down)
|
|
("<S-M-up>" . org-clock-convenience-timestamp-up)
|
|
("<S-M-down>" . 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 (regex-template year &optional month day insert)
|
|
(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
|
|
* org-roam
|
|
#+begin_src emacs-lisp
|
|
(require 'org-ql)
|
|
(defvar bootstrap-version)
|
|
(let ((bootstrap-file
|
|
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
|
|
(bootstrap-version 5))
|
|
(unless (file-exists-p bootstrap-file)
|
|
(with-current-buffer
|
|
(url-retrieve-synchronously
|
|
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
|
|
'silent 'inhibit-cookies)
|
|
(goto-char (point-max))
|
|
(eval-print-last-sexp)))
|
|
(load bootstrap-file nil 'nomessage))
|
|
|
|
(setq straight-vc-git-default-protocol 'ssh)
|
|
|
|
(use-package org-roam
|
|
:after org
|
|
:custom
|
|
(org-roam-directory (my/org-file "org-roam"))
|
|
(org-roam-use-completion-everywhere t)
|
|
:bind (("C-c n h" . org-roam-buffer-toggle)
|
|
("C-c n f" . org-roam-node-find)
|
|
("C-c n T" . org-roam-dailies-goto-today)
|
|
("C-c n t" . org-roam-dailies-capture-today)
|
|
("C-c n i" . org-roam-node-insert)
|
|
("C-c n w" . org-roam-refile)
|
|
("C-c n j" . my/org-roam-logger-capture-current)
|
|
:map org-mode-map
|
|
("C-M-i" . completion-at-point))
|
|
:init
|
|
(setq org-roam-v2-ack t)
|
|
:config
|
|
(org-roam-setup)
|
|
(setq org-roam-dailies-directory "daily/")
|
|
(setq org-roam-dailies-capture-templates
|
|
'(("d" "Journal" entry "* %<%H:%M> %?"
|
|
:unnarrowed t
|
|
:target (file+head+olp "%<%Y-%m-%d>.org"
|
|
"#+title: %<%Y-%m-%d>\n#+filetags: %<:%Y:%B:>\n"
|
|
("Journal")))
|
|
;; ("m" "Most Important Thing" entry "* TODO %? :mit:"
|
|
;; :target (file+head+olp "%<%Y-%m-%d>.org"
|
|
;; "#+title: %<%Y-%m-%d>\n#+filetags: %<:%Y:%B:>\n"
|
|
;; ("Most Important Thing(s)")))
|
|
))
|
|
|
|
(require 'my-org-roam-logger)
|
|
(setq org-roam-capture-templates
|
|
'(("d" "default" plain "%?" :target
|
|
(file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
|
|
:unnarrowed t)
|
|
("t" "tech tips" plain "%?" :target
|
|
(file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: techtips\n")
|
|
:unnarrowed t))))
|
|
|
|
;; (require 'org-roam-protocol)
|
|
#+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
|