From d2d4166b42b9f3d843c3700c6608f336ee1f86de Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Wed, 5 Jul 2017 02:33:41 +0200 Subject: [PATCH] Move lang/org => org/* Since lang/org has grown (and is expected to grow much, much more), it has been given its own module category. Concerns #129, #138 --- bin/org-capture | 2 +- init.example.el | 12 +- modules/lang/org/+agenda.el | 27 -- modules/lang/org/+attach.el | 46 -- modules/lang/org/+export.el | 28 -- modules/lang/org/autoload/babel.el | 10 - modules/lang/org/autoload/capture.el | 11 - modules/lang/org/autoload/notebook.el | 36 -- modules/lang/org/autoload/util.el | 10 - modules/lang/org/config.el | 396 ------------------ .../org => org/org-attach}/autoload/evil.el | 20 +- .../org-attach/autoload/org-attach.el} | 33 +- modules/org/org-attach/config.el | 49 +++ modules/org/org-attach/packages.el | 4 + modules/org/org-babel/autoload.el | 12 + .../org/+babel.el => org/org-babel/config.el} | 36 +- modules/org/org-babel/packages.el | 10 + modules/org/org-capture/autoload/evil.el | 10 + .../org/org-capture/autoload/org-capture.el | 17 + .../+capture.el => org/org-capture/config.el} | 27 +- modules/org/org-export/config.el | 35 ++ modules/org/org-export/packages.el | 4 + modules/org/org-notebook/autoload.el | 36 ++ .../org-notebook/config.el} | 21 +- modules/org/org-present/autoload.el | 88 ++++ modules/org/org-present/config.el | 59 +++ modules/org/org-present/packages.el | 6 + modules/{lang => org}/org/autoload/org.el | 178 ++++---- modules/{lang => org}/org/autoload/tables.el | 2 +- modules/org/org/config.el | 259 ++++++++++++ modules/{lang => org}/org/packages.el | 11 +- 31 files changed, 774 insertions(+), 721 deletions(-) delete mode 100644 modules/lang/org/+agenda.el delete mode 100644 modules/lang/org/+attach.el delete mode 100644 modules/lang/org/+export.el delete mode 100644 modules/lang/org/autoload/babel.el delete mode 100644 modules/lang/org/autoload/capture.el delete mode 100644 modules/lang/org/autoload/notebook.el delete mode 100644 modules/lang/org/autoload/util.el delete mode 100644 modules/lang/org/config.el rename modules/{lang/org => org/org-attach}/autoload/evil.el (66%) rename modules/{lang/org/autoload/attach.el => org/org-attach/autoload/org-attach.el} (66%) create mode 100644 modules/org/org-attach/config.el create mode 100644 modules/org/org-attach/packages.el create mode 100644 modules/org/org-babel/autoload.el rename modules/{lang/org/+babel.el => org/org-babel/config.el} (53%) create mode 100644 modules/org/org-babel/packages.el create mode 100644 modules/org/org-capture/autoload/evil.el create mode 100644 modules/org/org-capture/autoload/org-capture.el rename modules/{lang/org/+capture.el => org/org-capture/config.el} (74%) create mode 100644 modules/org/org-export/config.el create mode 100644 modules/org/org-export/packages.el create mode 100644 modules/org/org-notebook/autoload.el rename modules/{lang/org/+notebook.el => org/org-notebook/config.el} (56%) create mode 100644 modules/org/org-present/autoload.el create mode 100644 modules/org/org-present/config.el create mode 100644 modules/org/org-present/packages.el rename modules/{lang => org}/org/autoload/org.el (88%) rename modules/{lang => org}/org/autoload/tables.el (96%) create mode 100644 modules/org/org/config.el rename modules/{lang => org}/org/packages.el (62%) diff --git a/bin/org-capture b/bin/org-capture index 706891c3a..c987e0908 100755 --- a/bin/org-capture +++ b/bin/org-capture @@ -24,5 +24,5 @@ fi emacsclient -c \ -F '((name . "org-capture") (width . 70) (height . 25))' \ - --eval "(+org/capture \"$key\" \"$2\")" + --eval "(+org-capture/dwim \"$2\" \"$key\")" diff --git a/init.example.el b/init.example.el index e7dc5da14..a39835345 100644 --- a/init.example.el +++ b/init.example.el @@ -90,7 +90,6 @@ lua ; one-based indices? one-based indices markdown ; writing docs for people to ignore ocaml ; an objective camel - org ; for organized fearless leader (WIP) php ; make php less awful to work with purescript ; javascript, but functional python ; beautiful is better than ugly @@ -103,6 +102,17 @@ typescript ; javascript, but better web ; the tubes + :org + org ; organize your plain life in plain text + org-babel ; executable code snippets in org-mode + ;org-attach ; FIXME my own, simpler attachment system + org-capture ; a better org-capture, in or outside of Emacs + org-export ; a custom, centralized export system + org-notebook ; org-mode as a notebook + org-present ; using org-mode for presentations + ;org-sync ; TODO sync with mobile + ;org-publish ; TODO org + blogs + ;; Applications are complex and opinionated modules that transform Emacs ;; toward a specific purpose. They should be loaded last. :app diff --git a/modules/lang/org/+agenda.el b/modules/lang/org/+agenda.el deleted file mode 100644 index a849eee5a..000000000 --- a/modules/lang/org/+agenda.el +++ /dev/null @@ -1,27 +0,0 @@ -;;; lang/org/+agenda.el -*- lexical-binding: t; -*- - -(after! org-agenda - (setq-default - diary-file (concat doom-local-dir "diary.org") - ;; calendar-mark-diary-entries-flag nil - org-agenda-dim-blocked-tasks nil - org-agenda-files (directory-files +org-dir t "\\.org$" t) - org-agenda-inhibit-startup t - org-agenda-skip-unavailable-files nil) - - (after! recentf - ;; Don't clobber recentf with agenda files - (defun +org-is-agenda-file (filename) - (cl-find (file-truename filename) org-agenda-files - :key #'file-truename - :test #'equal)) - (add-to-list 'recentf-exclude #'+org-is-agenda-file)) - - ;; - (map! :map org-agenda-mode-map - :e "" #'org-agenda-Quit - :e "m" #'org-agenda-month-view - :e "C-j" #'org-agenda-next-item - :e "C-k" #'org-agenda-previous-item - :e "C-n" #'org-agenda-next-item - :e "C-p" #'org-agenda-previous-item)) diff --git a/modules/lang/org/+attach.el b/modules/lang/org/+attach.el deleted file mode 100644 index 16a93f57d..000000000 --- a/modules/lang/org/+attach.el +++ /dev/null @@ -1,46 +0,0 @@ -;;; lang/org/+attach.el -*- lexical-binding: t; -*- - -;; FIXME Needs to be rewritten -;; -;; Initializes my own org-mode attachment system. I didn't like Org's native -;; one. Mine stores attachments in a global org .attach directory. It also -;; implements drag-and-drop file support and attachment icons. It also treats -;; images specially. -;; -;; To clean up unreferenced attachments, call `doom/org-cleanup-attachments' -(add-hook '+org-init-hook #'+org|init-attach t) - -(defun +org|init-attach () - (setq org-attach-directory +org-attachment-dir) - - ;; Don't track attachments in projectile or recentf - (push ".attach" projectile-globally-ignored-file-suffixes) - (after! recentf - (push (format "/%s.+$" (regexp-quote +org-attachment-dir)) recentf-exclude)) - - ;; FIXME Use all-the-icons - ;; (doom-fix-unicode '("FontAwesome" 13) ? ? ? ? ? ? ? ?) - ;; Drag-and-drop support - (require 'org-download) - (setq-default org-download-image-dir +org-attachment-dir - org-download-heading-lvl nil - org-download-timestamp "_%Y%m%d_%H%M%S") - - (setq org-download-screenshot-method - (cond (IS-MAC "screencapture -i %s") - (IS-LINUX "maim --opengl -s %s"))) - - ;; Write download paths relative to current file - (advice-add #'org-download--dir-2 :override #'ignore) - (defun +org*download-fullname (path) - (file-relative-name path (file-name-directory (buffer-file-name)))) - (advice-add #'org-download--fullname :filter-return #'+org*download-fullname) - - ;; Add another drag-and-drop handler that will handle anything but image files - (setq dnd-protocol-alist `(("^\\(https?\\|ftp\\|file\\|nfs\\):\\(//\\)?" . doom/org-download-dnd) - ,@dnd-protocol-alist)) - - ;; keybinds - ;; (map! :leader :n "oa" (find-file-in! +org-attachment-dir)) - ) - diff --git a/modules/lang/org/+export.el b/modules/lang/org/+export.el deleted file mode 100644 index bd92d580f..000000000 --- a/modules/lang/org/+export.el +++ /dev/null @@ -1,28 +0,0 @@ -;;; lang/org/+export.el -*- lexical-binding: t; -*- - -;; My own, centralized exporting system as well. - -(add-hook '+org-init-hook #'+org|init-export t) - -(defun +org|init-export () - (setq org-export-directory (expand-file-name ".export" +org-dir) - org-export-backends '(ascii html latex md) - org-export-with-toc t - org-export-with-author t) - - ;; Export to a central directory (why isn't this easier?) - (unless (file-directory-p org-export-directory) - (make-directory org-export-directory t)) - (defun +org*export-output-file-name (args) - (unless (nth 2 args) - (setq args (append args (list org-export-directory)))) - args) - (advice-add #'org-export-output-file-name :filter-args #'+org*export-output-file-name) - - ;; (require 'ox-pandoc) - ;; (setq org-pandoc-options '((standalone . t) (mathjax . t) (parse-raw . t))) - - ;; keybinds - ;; (map! :leader :n "oe" (find-file-in! org-export-directory)) - ) - diff --git a/modules/lang/org/autoload/babel.el b/modules/lang/org/autoload/babel.el deleted file mode 100644 index 51d8294a1..000000000 --- a/modules/lang/org/autoload/babel.el +++ /dev/null @@ -1,10 +0,0 @@ -;;; lang/org/autoload/babel.el -*- lexical-binding: t; -*- - -;;;###autoload -(defun +org/edit-special-same-window () - (interactive) - (let ((shackle-rules '(("^\\*Org Src" :align t :select t :regexp t :noesc t :same t)))) - (call-interactively #'org-edit-special) - ;; FIXME too tightly coupled with doom-buffer-mode - (when (fboundp 'solaire-mode) - (solaire-mode +1)))) diff --git a/modules/lang/org/autoload/capture.el b/modules/lang/org/autoload/capture.el deleted file mode 100644 index 7343ac6bf..000000000 --- a/modules/lang/org/autoload/capture.el +++ /dev/null @@ -1,11 +0,0 @@ -;;; lang/org/autoload/capture.el -*- lexical-binding: t; -*- - -;;;###autoload -(defun +org/capture (&optional key string) - "Initializes the current frame as a pop-up `org-capture' frame." - (interactive) - (let ((key (or key "n")) - (string (unless (string-empty-p string) string))) - (if string - (org-capture-string string key) - (org-capture nil key)))) diff --git a/modules/lang/org/autoload/notebook.el b/modules/lang/org/autoload/notebook.el deleted file mode 100644 index 2be931f38..000000000 --- a/modules/lang/org/autoload/notebook.el +++ /dev/null @@ -1,36 +0,0 @@ -;;; lang/org/autoload/notebook.el -*- lexical-binding: t; -*- - -;;;###autoload -(defun +org-mode-notes-dir () - "Return the directory were `major-mode's org notes files are." - (if-let (name (cdr (assq major-mode +org-notes-code-alist))) - (expand-file-name (concat name "/") +org-code-notes-dir) - (let ((mode-name (s-replace "+" "p" (s-chop-suffix "-mode" (symbol-name major-mode))))) - (expand-file-name (concat mode-name "/") +org-code-notes-dir)))) - -(defun +org--explore-notes (dir) - (unless (file-directory-p dir) - (error "Directory doesn't exist: %s" dir)) - (if (fboundp '+evil/neotree) - (neotree-dir dir) - (let ((default-directory dir)) - (call-interactively (command-remapping 'find-file))))) - -;;;###autoload -(defun +org/browse-notes-for-major-mode () - "Browse org notes in `+org-code-notes-dir' in neotree, ido, ivy or helm -- -whichever is available." - (interactive) - (let ((dir (+org-mode-notes-dir))) - (unless (file-in-directory-p dir +org-code-notes-dir) - (error "Invalid location for %s notes: %s" major-mode (abbreviate-file-name dir))) - (unless (file-directory-p dir) - (make-directory dir t)) - (+org--explore-notes dir))) - -;;;###autoload -(defun +org/browse-notes-for-project () - "Browse org notes in `+org-project-notes-dir' in neotree, ido, ivy or helm -- -whichever is available." - (interactive) - (+org--explore-notes +org-project-notes-dir)) diff --git a/modules/lang/org/autoload/util.el b/modules/lang/org/autoload/util.el deleted file mode 100644 index 71c155380..000000000 --- a/modules/lang/org/autoload/util.el +++ /dev/null @@ -1,10 +0,0 @@ -;;; lang/org/autoload/util.el -*- lexical-binding: t; -*- - -;;;###autoload -(defun +org-get-property (name &optional _file) ; TODO Add FILE - "Get a propery from an org file." - (save-excursion - (goto-char 1) - (re-search-forward (format "^#\\+%s:[ \t]*\\([^\n]+\\)" (upcase name)) nil t) - (buffer-substring-no-properties (match-beginning 1) (match-end 1)))) - diff --git a/modules/lang/org/config.el b/modules/lang/org/config.el deleted file mode 100644 index 11c4a03cf..000000000 --- a/modules/lang/org/config.el +++ /dev/null @@ -1,396 +0,0 @@ -;;; lang/org/config.el -*- lexical-binding: t; -*- - -;; A few things you can expect -;; + `org-capture' in a popup frame (can be invoked from outside emacs too) -;; + Exported files are put in a centralized location (see -;; `org-export-directory') -;; + Inline latex previews (requires latex and dvipng programs) -;; + Inline code block execution for various languages -;; + TODO A simpler attachment system (with auto-deleting support) and -;; drag-and-drop for images and documents into org files -;; + TODO Custom links for class notes -;; + TODO An org-mode based CRM (including invoicing and pdf exporting) (see custom-crm) -;; + TODO A tag-based file browser reminiscient of Evernote and Quiver (there's neotree too!) - -(defvar +org-init-hook nil - "TODO") - -(add-hook 'org-load-hook #'+org|init) -(add-hook 'org-mode-hook #'+org|hook) - -;; Custom variables -(defvar +org-dir (expand-file-name "~/work/org/") - "The directory where org files are kept.") -(defvaralias 'org-directory '+org-dir) - -(defvar +org-attachment-dir ".attach/" - "Where to store attachments (relative to current org file).") - -;; Ensure ELPA org is prioritized above built-in org. -(when-let (path (locate-library "org" nil doom--package-load-path)) - (cl-pushnew (file-name-directory path) load-path)) - -(load! +agenda) -(load! +attach) -(load! +capture) -(load! +export) -(load! +notebook) -(load! +babel) - - -;; -;; Config -;; - -(defun +org|hook () - "Run everytime `org-mode' is enabled." - (setq line-spacing 1) - - ;; show-paren-mode causes problems for org-indent-mode - (make-local-variable 'show-paren-mode) - (setq show-paren-mode nil) - - (visual-line-mode +1) - (when (and (featurep 'evil) evil-mode) - (evil-org-mode +1)) - - (require 'toc-org) - (toc-org-enable) - - (unless org-agenda-inhibit-startup - ;; My version of the 'overview' #+STARTUP option: expand first-level - ;; headings. - (when (eq org-startup-folded t) - (outline-hide-sublevels 2)) - - ;; If saveplace places the point in a folded position, unfold it on load - (when (outline-invisible-p) - (ignore-errors - (save-excursion - (outline-previous-visible-heading 1) - (org-show-subtree))))) - - (defun +org|realign-table-maybe () - "Auto-align table under cursor." - (when (org-at-table-p) - (save-excursion - (org-table-align)))) - (add-hook 'evil-insert-state-exit-hook #'+org|realign-table-maybe nil t) - - (defun +org|update-cookies () - "Update counts in headlines (aka \"cookies\")." - (when (and buffer-file-name (file-exists-p buffer-file-name)) - (org-update-statistics-cookies t))) - - (add-hook 'before-save-hook #'+org|update-cookies nil t) - (add-hook 'evil-insert-state-exit-hook #'+org|update-cookies nil t)) - - -(defun +org|init () - "Initializes org core." - (define-minor-mode evil-org-mode - "Evil-mode bindings for org-mode." - :init-value nil - :lighter " !" - :keymap (make-sparse-keymap) - :group 'evil-org) - - (setq-default - org-export-coding-system 'utf-8 - org-todo-keywords - '((sequence "[ ](t)" "[-](p)" "[?](m)" "|" "[X](d)") - (sequence "TODO(T)" "|" "DONE(D)") - (sequence "IDEA(i)" "NEXT(n)" "ACTIVE(a)" "WAITING(w)" "LATER(l)" - "|" "CANCELLED(c)")) - - ;; Behavior - org-blank-before-new-entry '((heading . nil) (plain-list-item . auto)) - org-catch-invisible-edits 'show - org-checkbox-hierarchical-statistics nil - org-enforce-todo-checkbox-dependencies nil - org-confirm-elisp-link-function nil - org-default-priority ?C - org-hierarchical-todo-statistics t - org-loop-over-headlines-in-active-region t - org-refile-use-outline-path t - org-special-ctrl-a/e t - - ;; Sorting/refiling - org-archive-location (concat +org-dir "/archived/%s::") - org-refile-targets '((nil . (:maxlevel . 2))) ; display full path in refile completion - - ;; Latex - org-highlight-latex-and-related '(latex) - org-latex-create-formula-image-program 'dvipng - org-latex-image-default-width ".9\\linewidth" - org-latex-preview-ltxpng-directory (concat doom-cache-dir "/ltxpng/") - org-latex-remove-logfiles nil - org-startup-with-latex-preview nil - ;; org-latex-packages-alist - ;; '(("" "gauss" t) - ;; ("" "physics" t) TODO Install this) - ) - - (let ((ext-regexp (regexp-opt '("GIF" "JPG" "JPEG" "SVG" "TIF" "TIFF" "BMP" "XPM" - "gif" "jpg" "jpeg" "svg" "tif" "tiff" "bmp" "xpm")))) - (setq iimage-mode-image-regex-alist - `((,(concat "\\(`?file://\\|\\[\\[\\|<\\|`\\)?\\([-+./_0-9a-zA-Z]+\\." - ext-regexp "\\)\\(\\]\\]\\|>\\|'\\)?") . 2) - (,(concat "<\\(http://.+\\." ext-regexp "\\)>") . 1)))) - - ;; enable gpg support - (require 'org-crypt) - (org-crypt-use-before-save-magic) - (setq org-tags-exclude-from-inheritance '("crypt") - org-crypt-key user-mail-address - epa-file-encrypt-to user-mail-address) - - ;; smartparens config - (sp-with-modes '(org-mode) - (sp-local-pair "\\[" "\\]" :post-handlers '(("| " "SPC"))) - (sp-local-pair "\\(" "\\)" :post-handlers '(("| " "SPC"))) - (sp-local-pair "$$" "$$" :post-handlers '((:add " | ")) :unless '(sp-point-at-bol-p)) - (sp-local-pair "{" nil)) - - ;; Initialize everything else - (+org|init-ui) - (+org|init-keybinds) - - (run-hooks '+org-init-hook) - (+org|hacks)) - - -(defun +org|init-ui () - "Configures the UI for `org-mode'." - (setq-default - org-fontify-done-headline t - org-fontify-quote-and-verse-blocks t - org-fontify-whole-heading-line t - org-hide-emphasis-markers nil - org-hide-leading-stars t - org-hide-leading-stars-before-indent-mode t - org-image-actual-width nil - org-indent-indentation-per-level 2 - org-pretty-entities nil - org-pretty-entities-include-sub-superscripts t - org-startup-folded t - org-startup-indented t - org-startup-with-inline-images nil - org-tags-column 0 - org-use-sub-superscripts '{} - - ;; Appearance - outline-blank-line t - org-indent-mode-turns-on-hiding-stars t - org-adapt-indentation nil - org-cycle-separator-lines 1 - org-cycle-include-plain-lists t - ;; org-ellipsis "  " - org-entities-user '(("flat" "\\flat" nil "" "" "266D" "♭") - ("sharp" "\\sharp" nil "" "" "266F" "♯")) - org-footnote-auto-label 'plain - org-hidden-keywords nil - - ;; LaTeX previews are too small and usually render to light backgrounds, so - ;; this enlargens them and ensures their background (and foreground) match the - ;; current theme. - org-format-latex-options - (plist-put org-format-latex-options :scale 1.5) - org-format-latex-options - (plist-put org-format-latex-options - :background (face-attribute (or (cadr (assq 'default face-remapping-alist)) - 'default) - :background nil t))) - - (define-minor-mode +org-pretty-mode - "TODO" - :init-value nil - :lighter " *" - :group 'evil-org - (setq org-hide-emphasis-markers +org-pretty-mode) - (org-toggle-pretty-entities) - ;; In case the above un-align tables - (org-table-map-tables 'org-table-align t)) - - ;; Use ivy/helm if either is available - (when (or (featurep! :completion ivy) - (featurep! :completion helm)) - (setq-default org-completion-use-ido nil - org-outline-path-complete-in-steps nil)) - - ;; Custom fontification - (defsubst +org--tag-face (n) - (let ((kwd (match-string n))) - (or (and (equal kwd "#") 'org-tag) - (and (equal kwd "@") 'org-special-keyword)))) - - (defun +org|adjust-faces () - "Correct (and improve) org-mode's font-lock keywords. - - 1. Re-set `org-todo' & `org-headline-done' faces, to make them respect - underlying faces. - 2. Fontify item bullets - 3. Fontify item checkboxes (and when they're marked done)" - (let ((org-todo (format org-heading-keyword-regexp-format - org-todo-regexp)) - (org-done (format org-heading-keyword-regexp-format - (concat "\\(?:" (mapconcat #'regexp-quote org-done-keywords "\\|") "\\)")))) - (setq - org-font-lock-extra-keywords - (append (org-delete-all - `(("\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]" - (0 (org-get-checkbox-statistics-face) t)) - (,org-todo (2 (org-get-todo-face 2) t)) - (,org-done (2 'org-headline-done t))) - org-font-lock-extra-keywords) - `((,org-todo (2 (org-get-todo-face 2) prepend)) - (,org-done (2 'org-headline-done prepend)) - ;; Make checkbox statistic cookies respect underlying faces - ("\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]" - (0 (org-get-checkbox-statistics-face) prepend)) - ;; I like how org-mode fontifies checked TODOs and want this to extend to - ;; checked checkbox items: - ("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" - 1 'org-headline-done prepend) - ;; make plain list bullets stand out - ("^ *\\([-+]\\|[0-9]+[).]\\) " 1 'org-list-dt append) - ;; and separators/dividers - ("^ *\\(-----+\\)$" 1 'org-meta-line) - ;; custom #hashtags & @at-tags for another level of organization - ;; TODO refactor this into a single rule - ("\\s-\\(\\([#@]\\)[^ \n]+\\)" 1 (+org--tag-face 2))))))) - (add-hook 'org-font-lock-set-keywords-hook #'+org|adjust-faces) - - ;; The standard unicode characters are usually misaligned depending on the - ;; font. This bugs me. Personally, markdown #-marks for headlines are more - ;; elegant, so we use those. - (def-package! org-bullets - :commands org-bullets-mode - :init (add-hook 'org-mode-hook #'org-bullets-mode) - :config (setq org-bullets-bullet-list '("#")))) - -(defun +org|init-keybinds () - "Initialize my `org-mode' keybindings." - (map! (:map org-mode-map - "RET" #'org-return-indent - "C-j" nil - "C-k" nil) - - (:map evil-org-mode-map - :n "RET" #'+org/dwim-at-point - ;; - :ni "A-L" #'org-shiftmetaright - :ni "A-H" #'org-shiftmetaleft - :ni "A-K" #'org-shiftmetaup - :ni "A-J" #'org-shiftmetadown - ;; Expand tables (or shiftmeta move) - :ni "C-S-l" #'+org/table-append-field-or-shift-right - :ni "C-S-h" #'+org/table-prepend-field-or-shift-left - :ni "C-S-k" #'+org/table-prepend-row-or-shift-up - :ni "C-S-j" #'+org/table-append-row-or-shift-down - ;; Navigate table cells - :i "C-L" #'+org/table-next-field - :i "C-H" #'+org/table-previous-field - :i "C-K" #'+org/table-previous-row - :i "C-J" #'+org/table-next-row - - :i "C-e" #'org-end-of-line - :i "C-a" #'org-beginning-of-line - - :i [tab] #'+org/indent-or-next-field-or-yas-expand - :i [backtab] #'+org/dedent-or-prev-field - - :n [tab] #'+org/toggle-fold - :v [backtab] #'+snippets/expand-on-region - - :nv "j" #'evil-next-visual-line - :nv "k" #'evil-previous-visual-line - - :i "M-a" (λ! (evil-visual-state) (org-mark-element)) - :n "M-a" #'org-mark-element - :v "M-a" #'mark-whole-buffer - - :ni [M-return] (λ! (+org/insert-item 'below)) - :ni [S-M-return] (λ! (+org/insert-item 'above)) - - (:localleader - :n "RET" #'org-archive-subtree - :n "SPC" #'+org/toggle-checkbox - :n "/" #'org-sparse-tree - :n "=" #'org-align-all-tags - :n "?" #'org-tags-view - :n "a" #'org-agenda - :n "d" #'org-time-stamp - :n "D" #'org-deadline - :n "e" #'org-edit-special - :n "E" #'+org/edit-special-same-window - :n "n" (λ! (if (buffer-narrowed-p) (widen) (org-narrow-to-subtree))) - :n "r" #'org-refile - :n "R" (λ! (org-metaleft) (org-archive-to-archive-sibling)) ; archive to parent sibling - :n "s" #'org-schedule - :n "t" (λ! (org-todo (if (org-entry-is-todo-p) 'none 'todo))) - :v "t" (λ! (evil-ex-normal evil-visual-beginning evil-visual-end "\\t")) - :n "T" #'org-todo - :n "v" #'variable-pitch-mode - :nv "l" #'org-insert-link - :nv "L" #'org-store-link - ;:n "w" #'writing-mode - ;:n "x" #'+org/remove-link - ) - - ;; TODO Improve folding bindings - :n "za" #'+org/toggle-fold - :n "zA" #'org-shifttab - :n "zc" #'outline-hide-subtree - :n "zC" (λ! (outline-hide-sublevels 1)) - :n "zd" (lambda (&optional arg) (interactive "p") (outline-hide-sublevels (or arg 3))) - :n "zm" (λ! (outline-hide-sublevels 1)) - :n "zo" #'outline-show-subtree - :n "zO" #'outline-show-all - :n "zr" #'outline-show-all - - :m "]]" (λ! (org-forward-heading-same-level nil) (org-beginning-of-line)) - :m "[[" (λ! (org-backward-heading-same-level nil) (org-beginning-of-line)) - :m "]l" #'org-next-link - :m "[l" #'org-previous-link - - :m "gh" #'outline-up-heading - :m "gj" #'org-forward-heading-same-level - :m "gk" #'org-backward-heading-same-level - :m "gl" (λ! (call-interactively #'outline-next-visible-heading) (outline-show-children)) - - :n "go" #'org-open-at-point - :n "gO" (λ! (let ((org-link-frame-setup (append '((file . find-file-other-window)) org-link-frame-setup)) - (org-file-apps '(("\\.org$" . emacs) - (t . "open \"%s\"")))) - (call-interactively #'org-open-at-point))) - - :n "gQ" #'org-fill-paragraph - :m "$" #'org-end-of-line - :m "^" #'org-beginning-of-line - :n "<" #'org-metaleft - :n ">" #'org-metaright - :v "<" (λ! (org-metaleft) (evil-visual-restore)) - :v ">" (λ! (org-metaright) (evil-visual-restore)) - :n "-" #'org-cycle-list-bullet - :m "" #'org-cycle))) - - -(defun +org|hacks () - "Getting org to behave." - ;; Don't open separate windows - (cl-pushnew '(file . find-file) org-link-frame-setup) - - ;; Let OS decide what to do with files when opened - (setq org-file-apps - `(("\\.org$" . emacs) - (t . ,(cond (IS-MAC "open -R \"%s\"") - (IS-LINUX "xdg-open \"%s\""))))) - - ;; Remove highlights on ESC - (defun +org|remove-occur-highlights () - (when (derived-mode-p 'org-mode) - (org-remove-occur-highlights) - t)) - (add-hook '+evil-esc-hook #'+org|remove-occur-highlights)) - diff --git a/modules/lang/org/autoload/evil.el b/modules/org/org-attach/autoload/evil.el similarity index 66% rename from modules/lang/org/autoload/evil.el rename to modules/org/org-attach/autoload/evil.el index 7787b95cd..67ffe1b9a 100644 --- a/modules/lang/org/autoload/evil.el +++ b/modules/org/org-attach/autoload/evil.el @@ -1,16 +1,8 @@ -;;; lang/org/autoload/evil.el -*- lexical-binding: t; -*- +;;; org/org-attach/autoload/evil.el -*- lexical-binding: t; -*- -;;;###autoload (autoload '+org:capture "lang/org/autoload/evil" nil t) -(evil-define-operator +org:capture (&optional beg end) - "Send a selection to `doom/org-capture'." - :move-point nil :type inclusive - (interactive "") - (org-capture-string - (when (and (evil-visual-state-p) beg end) - (buffer-substring beg end)))) - -;;;###autoload (autoload '+org:attach "lang/org/autoload/evil" nil t) -(evil-define-command +org:attach (&optional uri) +;;;###autoload (autoload '+org-attach:dwim "org/org-attach/autoload/evil" nil t) +(evil-define-command +org-attach:dwim (&optional uri) + "An evil ex interface to `+org-attach/dwim'." (interactive "") (unless (eq major-mode 'org-mode) (user-error "Not in an org-mode buffer")) @@ -26,12 +18,12 @@ (if (evil-visual-state-p) (org-insert-link nil (format "./%s" rel-path) (concat (buffer-substring-no-properties (region-beginning) (region-end)) - " " (doom--org-attach-icon rel-path))) + " " (org-attach--icon rel-path))) (insert (if image-p (format "[[./%s]] " rel-path) (format "%s [[./%s][%s]] " - (doom--org-attach-icon rel-path) + (org-attach--icon rel-path) rel-path (file-name-nondirectory (directory-file-name rel-path)))))) (when (string-match-p (regexp-opt '("jpg" "jpeg" "gif" "png")) (file-name-extension rel-path)) (org-redisplay-inline-images))) diff --git a/modules/lang/org/autoload/attach.el b/modules/org/org-attach/autoload/org-attach.el similarity index 66% rename from modules/lang/org/autoload/attach.el rename to modules/org/org-attach/autoload/org-attach.el index 2655de513..19189cd13 100644 --- a/modules/lang/org/autoload/attach.el +++ b/modules/org/org-attach/autoload/org-attach.el @@ -1,19 +1,20 @@ -;;; lang/org/autoload/attach.el -*- lexical-binding: t; -*- +;;; org/org-attach/autoload/org-attach.el -*- lexical-binding: t; -*- -(defun +org--attach-icon (path) - (char-to-string (pcase (downcase (file-name-extension path)) - ("jpg" ?) ("jpeg" ?) ("png" ?) ("gif" ?) - ("pdf" ?) - ("ppt" ?) ("pptx" ?) - ("xls" ?) ("xlsx" ?) - ("doc" ?) ("docx" ?) - ("ogg" ?) ("mp3" ?) ("wav" ?) - ("mp4" ?) ("mov" ?) ("avi" ?) - ("zip" ?) ("gz" ?) ("tar" ?) ("7z" ?) ("rar" ?) - (_ ?)))) +(defun +org-attach--icon (path) + (char-to-string + (pcase (downcase (file-name-extension path)) + ((or "jpg" "jpeg" "png" "gif") ?) + ("pdf" ?) + ((or "ppt" "pptx") ?) + ((or "xls" "xlsx") ?) + ((or "doc" "docx") ?) + ((or "ogg" "mp3" "wav" "aiff" "flac") ?) + ((or "mp4" "mov" "avi") ?) + ((or "zip" "gz" "tar" "7z" "rar") ?) + (_ ?)))) ;;;###autoload -(defun +org-cleanup-attachments () +(defun +org-attach-cleanup () ;; "Deletes any attachments that are no longer present in the org-mode buffer." (let* ((attachments-local (+org-attachments)) (attachments (directory-files org-attach-directory t "^[^.]" t)) @@ -22,6 +23,7 @@ to-delete)) (defun +org-attachments () + "List all attachments in the current buffer." (unless (eq major-mode 'org-mode) (user-error "Not an org buffer")) (org-save-outline-visibility nil @@ -43,10 +45,11 @@ (cl-remove-duplicates attachments)))) ;;;###autoload -(defun +org-download-dnd (uri action) +(defun +org-attach-download-dnd (uri action) (if (eq major-mode 'org-mode) (doom:org-attach uri) ;; FIXME (let ((dnd-protocol-alist - (rassq-delete-all '+org-download-dnd (copy-alist dnd-protocol-alist)))) + (rassq-delete-all '+org-attach-download-dnd + (copy-alist dnd-protocol-alist)))) (dnd-handle-one-url nil action uri)))) diff --git a/modules/org/org-attach/config.el b/modules/org/org-attach/config.el new file mode 100644 index 000000000..61d489bb9 --- /dev/null +++ b/modules/org/org-attach/config.el @@ -0,0 +1,49 @@ +;;; org/org-attach/config.el -*- lexical-binding: t; -*- + +(defvar +org-attach-dir (expand-file-name ".attach/" +org-dir) + "Where to store attachments (relative to current org file).") + + +(add-hook '+org-init-hook #'+org|init-attach t) + +;; FIXME This module is broken and needs to be rewritten. +;; +;; I believe Org's native attachment system is over-complicated and litters +;; files with metadata I don't want. +;; +;; This installs my own attachment system. It: +;; +;; + Centralizes attachment in a global location, +;; + Adds drag-and-drop file support +;; + TODO ...with attachment icons, and +;; + TODO Offers an attachment management system. + +(def-package! org-download + :config + (setq-default org-download-image-dir +org-attach-dir + org-download-heading-lvl nil + org-download-timestamp "_%Y%m%d_%H%M%S") + (setq org-download-screenshot-method + (cond (IS-MAC "screencapture -i %s") + (IS-LINUX "maim --opengl -s %s"))) + + ;; Write download paths relative to current file + (defun +org-attach*download-fullname (path) + (file-relative-name path (file-name-directory (buffer-file-name)))) + (advice-add #'org-download--dir-2 :override #'ignore) + (advice-add #'org-download--fullname + :filter-return #'+org-attach*download-fullname)) + +;; +(defun +org-attach|init () + (setq org-attach-directory +org-attach-directory) + + (push ".attach" projectile-globally-ignored-file-suffixes) + (after! recentf + (push (format "/%s.+$" (regexp-quote +org-attach-dir)) + recentf-exclude)) + + (require 'org-download) + + ;; Add another drag-and-drop handler that will handle anything but image files + (push '("^\\(https?\\|ftp\\|file\\|nfs\\):\\(//\\)?" . +org-attach-download-dnd) dnd-protocol-alist)) diff --git a/modules/org/org-attach/packages.el b/modules/org/org-attach/packages.el new file mode 100644 index 000000000..6dce4d54f --- /dev/null +++ b/modules/org/org-attach/packages.el @@ -0,0 +1,4 @@ +;; -*- no-byte-compile: t; -*- +;;; org/org-attach/packages.el + +(package! org-download) diff --git a/modules/org/org-babel/autoload.el b/modules/org/org-babel/autoload.el new file mode 100644 index 000000000..489f4f3b3 --- /dev/null +++ b/modules/org/org-babel/autoload.el @@ -0,0 +1,12 @@ +;;; org/org-babel/autoload.el -*- lexical-binding: t; -*- + +;;;###autoload +(defun +org-babel/edit (arg) + "Edit the source block at point in a popup. + +If ARG is non-nil (universal argument), use the current window." + (interactive "P") + (if arg + (call-interactively #'org-edit-special) + (with-popup-rules! (("^\\*Org Src" :regexp t :select t :noesc t :same t)) + (call-interactively #'org-edit-special)))) diff --git a/modules/lang/org/+babel.el b/modules/org/org-babel/config.el similarity index 53% rename from modules/lang/org/+babel.el rename to modules/org/org-babel/config.el index cafba6546..e36d1f48c 100644 --- a/modules/lang/org/+babel.el +++ b/modules/org/org-babel/config.el @@ -1,14 +1,13 @@ -;;; lang/org/+babel.el -*- lexical-binding: t; -*- +;;; org/org-babel/config.el -*- lexical-binding: t; -*- -(add-hook '+org-init-hook #'+org|init-babel t) +(add-hook 'org-load-hook #'+org-babel|init t) -(defun +org|init-babel () - (setq org-confirm-babel-evaluate nil ; you don't need my permission - org-src-fontify-natively t ; make code pretty - org-src-preserve-indentation t +(defun +org-babel|init () + (setq org-src-fontify-natively t ; make code pretty + org-src-preserve-indentation t ; use native major-mode indentation org-src-tab-acts-natively t org-src-window-setup 'current-window - org-edit-src-content-indentation 0) + org-confirm-babel-evaluate nil) ; you don't need my permission (org-babel-do-load-languages 'org-babel-load-languages @@ -25,28 +24,29 @@ matlab plantuml python - restclient + restclient ; ob-restclient ruby - rust + rust ; ob-rust sh sqlite - sql-mode - translate + sql-mode ; ob-sql-mode + translate ; ob-translate ))) ;; In a recent update, `org-babel-get-header' was removed from org-mode, which ;; is something a fair number of babel plugins use. So until those plugins - ;; update... + ;; update, this polyfill will do: (defun org-babel-get-header (params key &optional others) - (delq nil - (mapcar - (lambda (p) (if (funcall (if others #'not #'identity) (eq (car p) key)) p)) - params))) + (cl-loop with fn = (if others #'not #'identity) + for p in params + if (funcall fn (eq (car p) key)) + collect p)) ;; I prefer C-c C-c for confirming over the default C-c ' (map! :map org-src-mode-map "C-c C-c" #'org-edit-src-exit) - ;; I know the keybindings, no need for the header line (defun +org|src-mode-remove-header () - (when header-line-format (setq header-line-format nil))) + "Remove header-line with keybinding help; I know the keybinds." + (when header-line-format + (setq header-line-format nil))) (add-hook 'org-src-mode-hook #'+org|src-mode-remove-header)) diff --git a/modules/org/org-babel/packages.el b/modules/org/org-babel/packages.el new file mode 100644 index 000000000..d9d792ba3 --- /dev/null +++ b/modules/org/org-babel/packages.el @@ -0,0 +1,10 @@ +;; -*- no-byte-compile: t; -*- +;;; org/org-babel/packages.el + +(package! ob-go) +(package! ob-mongo) +(package! ob-redis) +(package! ob-restclient) +(package! ob-rust :recipe (:fetcher github :repo "zweifisch/ob-rust")) +(package! ob-sql-mode) +(package! ob-translate) diff --git a/modules/org/org-capture/autoload/evil.el b/modules/org/org-capture/autoload/evil.el new file mode 100644 index 000000000..d1b01841e --- /dev/null +++ b/modules/org/org-capture/autoload/evil.el @@ -0,0 +1,10 @@ +;;; org/org-capture/autoload/evil.el -*- lexical-binding: t; -*- + +;;;###autoload (autoload '+org-capture:dwim "org/org-capture/autoload/evil" nil t) +(evil-define-operator +org-capture:dwim (&optional beg end) + "Evil ex interface to `+org-capture/dwim'." + :move-point nil :type inclusive + (interactive "") + (+org-capture/dwim + (unless (or (evil-normal-state-p) (evil-insert-state-p)) + (buffer-substring beg end)))) diff --git a/modules/org/org-capture/autoload/org-capture.el b/modules/org/org-capture/autoload/org-capture.el new file mode 100644 index 000000000..ad1c72a71 --- /dev/null +++ b/modules/org/org-capture/autoload/org-capture.el @@ -0,0 +1,17 @@ +;;; org/org-capture/autoload/org-capture.el -*- lexical-binding: t; -*- + +;;;###autoload +(defun +org-capture/dwim (&optional string key) + "Sends STRING, the current selection or prompted input to `org-capture'. + +Uses the capture template specified by KEY. Otherwise, prompts you for one." + (interactive) + (let ((key (or key "n"))) + (if-let (string (cond ((not (equal string "")) + string) + ((region-active-p) + (buffer-substring-no-properties + (region-beginning) + (region-end))))) + (org-capture-string string key) + (org-capture nil key)))) diff --git a/modules/lang/org/+capture.el b/modules/org/org-capture/config.el similarity index 74% rename from modules/lang/org/+capture.el rename to modules/org/org-capture/config.el index 2f991f971..038d87b72 100644 --- a/modules/lang/org/+capture.el +++ b/modules/org/org-capture/config.el @@ -1,4 +1,6 @@ -;;; lang/org/+capture.el -*- lexical-binding: t; -*- +;;; org/org-capture/config.el -*- lexical-binding: t; -*- + +(add-hook 'org-load-hook #'+org-capture|init t) ;; Sets up two `org-capture' workflows that I like: ;; @@ -7,16 +9,14 @@ ;; ;; 2. Through a org-capture popup frame that is invoked from outside Emacs (the ;; script is in ~/.emacs.d/bin). This lets me open an org-capture box -;; anywhere I can call org-capture, like, say, from qutebrowser, vimperator, -;; dmenu or a global keybinding. +;; anywhere I can call org-capture (whether or not Emacs is open/running), +;; like, say, from qutebrowser, vimperator, dmenu or a global keybinding. -(add-hook '+org-init-hook #'+org|init-capture t) - -(defun +org|init-capture () +(defun +org-capture|init () "Set up a sane `org-capture' workflow." - (setq org-default-notes-file (concat +org-dir "notes.org")) - - (setq org-capture-templates + (setq org-default-notes-file (concat +org-dir "notes.org") + ;; FIXME This is incomplete! + org-capture-templates '(;; TODO: New Task (todo) ;; TODO: New vocabulary word @@ -45,18 +45,17 @@ ;; and clean up properly) if the frame is named "org-capture". (require 'org-capture) (require 'org-protocol) - (defun +org*capture-init (&rest _) + (defun +org-capture*init (&rest _) "Makes sure the org-capture window is the only window in the frame." (when (equal "org-capture" (frame-parameter nil 'name)) (setq mode-line-format nil) (delete-other-windows))) - (advice-add #'org-capture :after #'+org*capture-init) + (advice-add #'org-capture :after #'+org-capture*init) - (defun +org|capture-finalize () + (defun +org-capture|finalize () "Closes the frame once org-capture is done." (when (equal "org-capture" (frame-parameter nil 'name)) (when (and (featurep 'persp-mode) persp-mode) (+workspace/delete (+workspace-current-name))) (delete-frame))) - (add-hook 'org-capture-after-finalize-hook #'+org|capture-finalize)) - + (add-hook 'org-capture-after-finalize-hook #'+org-capture|finalize)) diff --git a/modules/org/org-export/config.el b/modules/org/org-export/config.el new file mode 100644 index 000000000..a366d61d2 --- /dev/null +++ b/modules/org/org-export/config.el @@ -0,0 +1,35 @@ +;;; org/org-export/config.el -*- lexical-binding: t; -*- + +(add-hook 'org-load-hook #'+org-export|init t) + +;; I don't have any beef with org's built-in export system, but I do wish it +;; would export to a central directory, rather than `default-directory'. This is +;; because all my org files are usually in one place, and I want to be able to +;; refer back to old exports if needed. + +(def-package! ox-pandoc + :config + (unless (executable-find "pandoc") + (warn "org-export: couldn't find pandoc, disabling pandoc export")) + (setq org-pandoc-options + '((standalone . t) + (mathjax . t) + (parse-raw . t)))) + +;; +(defun +org-export|init () + (setq org-export-directory (expand-file-name ".export" +org-dir) + org-export-backends '(ascii html latex md) + org-export-with-toc t + org-export-with-author t) + + ;; Always export to a central location + (unless (file-directory-p org-export-directory) + (make-directory org-export-directory t)) + (defun +org*export-output-file-name (args) + "Return a centralized export location." + (unless (nth 2 args) + (setq args (append args (list org-export-directory)))) + args) + (advice-add #'org-export-output-file-name + :filter-args #'+org*export-output-file-name)) diff --git a/modules/org/org-export/packages.el b/modules/org/org-export/packages.el new file mode 100644 index 000000000..66f62ee84 --- /dev/null +++ b/modules/org/org-export/packages.el @@ -0,0 +1,4 @@ +;; -*- no-byte-compile: t; -*- +;;; org/org-export/packages.el + +(package! ox-pandoc) diff --git a/modules/org/org-notebook/autoload.el b/modules/org/org-notebook/autoload.el new file mode 100644 index 000000000..2f98210fb --- /dev/null +++ b/modules/org/org-notebook/autoload.el @@ -0,0 +1,36 @@ +;;; org/org-notebook/autoload.el -*- lexical-binding: t; -*- + +(defun +org-notebook--explore-notes (dir) + (unless (file-directory-p dir) + (error "Directory doesn't exist: %s" dir)) + (if (fboundp '+evil/neotree) + (neotree-dir dir) + (let ((default-directory dir)) + (call-interactively (command-remapping 'find-file))))) + +;;;###autoload +(defun +org-notebook/find-major-mode-notes () + "Browse org notes in `+org-notebook-code-dir' in neotree, ido, ivy or helm -- +whichever is available." + (interactive) + (let ((dir (expand-file-name + (concat (or (cdr (assq major-mode +org-notebook-code-alist)) + (replace-regexp-in-string + "+" "p" + (string-remove-suffix "-mode" (symbol-name major-mode)) + nil t)) + "/") + +org-notebook-code-dir))) + (unless (file-in-directory-p dir +org-notebook-code-dir) + (error "Invalid location for %s notes: %s" + major-mode (abbreviate-file-name dir))) + (unless (file-directory-p dir) + (make-directory dir t)) + (+org-notebook--explore-notes dir))) + +;;;###autoload +(defun +org-notebook/find-project-notes () + "Browse org notes in `+org-notebook-project-dir' in neotree, ido, ivy or helm -- +whichever is available." + (interactive) + (+org-notebook--explore-notes +org-notebook-project-dir)) diff --git a/modules/lang/org/+notebook.el b/modules/org/org-notebook/config.el similarity index 56% rename from modules/lang/org/+notebook.el rename to modules/org/org-notebook/config.el index 9fb006539..3d6e1f891 100644 --- a/modules/lang/org/+notebook.el +++ b/modules/org/org-notebook/config.el @@ -1,26 +1,27 @@ -;;; lang/org/+notebook.el -*- lexical-binding: t; -*- +;;; org/org-notebook/config.el -*- lexical-binding: t; -*- + +;; (add-hook 'org-load-hook '+org|init-notebook t) ;; While I program, write or plan, I want easy access to notes of various kinds, ;; such as major-mode/language specific notes, or project-specific notes. They -;; can be accessed via `+org/browse-notes-for-major-mode' and -;; `+org/browse-notes-for-project'. +;; can be accessed via `+org-notebook/find-major-mode-notes' and +;; `+org-notebook/find-project-notes'. -;; (add-hook '+org-init-hook '+org|init-notebook t) - -(defvar +org-notes-dir (concat +org-dir "notes/") +(defvar +org-notebook-dir (concat +org-dir "notes/") "The directory where the notes are kept.") -(defvar +org-code-notes-dir (concat +org-notes-dir "code/") +(defvar +org-notebook-code-dir (concat +org-notebook-dir "code/") "The directory where programming notes and snippets are kept.") -(defvar +org-project-notes-dir (concat +org-notes-dir "projects/") +(defvar +org-notebook-project-dir (concat +org-notebook-dir "projects/") "The directory where project notes are kept.") -(defvar +org-notes-code-alist + +(defvar +org-notebook-code-alist '((js2-mode . "javascript")) "An alist mapping certain modes (symbols) to their org notes directory name. If a mode isn't here, it's guessed by stripping out the -mode suffix and replacing '+' characters with 'p's.") -;; (defun +org|init-notebook ()) +;; (defun +org|init-notebook ()) diff --git a/modules/org/org-present/autoload.el b/modules/org/org-present/autoload.el new file mode 100644 index 000000000..d6831873e --- /dev/null +++ b/modules/org/org-present/autoload.el @@ -0,0 +1,88 @@ +;;; org/org-present/autoload.el -*- lexical-binding: t; -*- + +;;;###autoload +(defun +doom-present*org-tree-slide-narrow-exclude-header (orig-fn &rest args) + "TODO" + (cl-letf (((symbol-function 'org-narrow-to-subtree) + (lambda () (save-excursion + (save-match-data + (org-with-limited-levels + (narrow-to-region + (progn (org-back-to-heading t) + (forward-line 1) + (point)) + (progn (org-end-of-subtree t t) + (when (and (org-at-heading-p) (not (eobp))) (backward-char 1)) + (point))))))))) + (apply orig-fn args))) + +;;;###autoload +(defun +org-present|org-tree-prepare-window () + "TODO" + (doom/window-zoom) + (let ((arg (if org-tree-slide-mode +1 -1))) + (when (fboundp 'centered-window-mode) + (centered-window-mode arg)) + (window-divider-mode (* arg -1)) + (doom-hide-modeline-mode arg) + (+org-pretty-mode arg) + (cond (org-tree-slide-mode + (org-indent-mode -1) + (text-scale-set +org-present-text-scale) + (ignore-errors (org-toggle-latex-fragment '(4))) + (set-face-attribute 'org-level-2 nil :height 1.4)) + (t + (org-indent-mode +1) + (text-scale-set 0) + (org-remove-latex-fragment-image-overlays) + (set-face-attribute 'org-level-2 nil :height 1.0) + (+org-present|remove-overlays) + (org-remove-inline-images))))) + +(defvar +org-present--overlays nil) +;;;###autoload +(defun +org-present/org-tree-slides () + (interactive) + (unless (derived-mode-p 'org-mode) + (error "Not in an org buffer")) + (call-interactively 'org-tree-slide-mode) + (add-hook 'kill-buffer-hook '+org-present--cleanup-org-tree-slides-mode)) + +;;;###autoload +(defun +org-present|add-overlays () + (add-to-invisibility-spec '(+org-present)) + (save-excursion + ;; hide org-mode options starting with #+ + (goto-char (point-min)) + (while (re-search-forward "^[[:space:]]*\\(#\\+\\)\\(\\(?:BEGIN\\|END\\|ATTR\\)[^[:space:]]+\\).*" nil t) + (+org-present--make-invisible + (match-beginning 1) + (match-end 0))) + ;; hide stars in headings + (goto-char (point-min)) + (while (re-search-forward "^\\(\\*+\\s-\\)" nil t) + (+org-present--make-invisible (match-beginning 1) (match-end 1))))) + +;;;###autoload +(defun +org-present|remove-overlays () + (mapc #'delete-overlay +org-present--overlays) + (remove-from-invisibility-spec '(+org-present))) + +;;;###autoload +(defun +org-present|detect-slide () + (outline-show-all) + (if (member "title" (org-get-tags-at)) + (text-scale-set 10) + (text-scale-set +org-present-text-scale))) + +(defun +org-present--cleanup-org-tree-slides-mode () + (unless (cl-loop for buf in (doom-buffers-in-mode 'org-mode) + if (buffer-local-value 'org-tree-slide-mode buf) + return t) + (org-tree-slide-mode -1) + (remove-hook 'kill-buffer-hook #'+org-present--cleanup-org-tree-slides-mode))) + +(defun +org-present--make-invisible (beg end) + (let ((overlay (make-overlay beg end))) + (push overlay +org-present--overlays) + (overlay-put overlay 'invisible '+org-present))) diff --git a/modules/org/org-present/config.el b/modules/org/org-present/config.el new file mode 100644 index 000000000..48c59fe84 --- /dev/null +++ b/modules/org/org-present/config.el @@ -0,0 +1,59 @@ +;;; org/org-present/config.el -*- lexical-binding: t; -*- + +(defvar +org-present-text-scale 7 + "The `text-scale-amount' for `org-tree-slide-mode'.") + +(add-hook 'org-load-hook #'+org-present|init t) + + +;; +;; Plugins +;; + +(def-package! ox-reveal + :config + (setq org-reveal-root "http://cdn.jsdelivr.net/reveal.js/3.0.0/" + org-reveal-mathjax t)) + + +(def-package! org-tree-slide + :commands org-tree-slide-mode + :config + (org-tree-slide-simple-profile) + (setq org-tree-slide-skip-outline-level 2 + org-tree-slide-activate-message " " + org-tree-slide-deactivate-message " " + org-tree-slide-modeline-display nil) + + (map! :map org-tree-slide-mode-map + [right] #'org-tree-slide-move-next-tree + [left] #'org-tree-slide-move-previous-tree) + + (add-hook! 'org-tree-slide-mode-after-narrow-hook + #'(+org-present|detect-slide +org-present|add-overlays org-display-inline-images)) + + (add-hook 'org-tree-slide-mode-hook #'+org-present|org-tree-prepare-window) + (advice-add #'org-tree-slide--display-tree-with-narrow + :around #'+doom-present*org-tree-slide-narrow-exclude-header)) + + +(def-package! centered-window-mode + :commands centered-window-mode + :config + (setq cwm-use-vertical-padding t + cwm-frame-internal-border 110 + cwm-left-fringe-ratio -10 + cwm-centered-window-width 240)) + + +;; +;; Bootstrap +;; + +(defun +org-present|init () + (require 'ox-reveal) + + (map! :map org-mode-map + "" #'+org-present/org-tree-slides + "" #'+org-present/next)) + diff --git a/modules/org/org-present/packages.el b/modules/org/org-present/packages.el new file mode 100644 index 000000000..2459aa651 --- /dev/null +++ b/modules/org/org-present/packages.el @@ -0,0 +1,6 @@ +;; -*- no-byte-compile: t; -*- +;;; org/org-present/packages.el + +(package! centered-window-mode) +(package! org-tree-slide) +(package! ox-reveal) diff --git a/modules/lang/org/autoload/org.el b/modules/org/org/autoload/org.el similarity index 88% rename from modules/lang/org/autoload/org.el rename to modules/org/org/autoload/org.el index d62258553..03baa862f 100644 --- a/modules/lang/org/autoload/org.el +++ b/modules/org/org/autoload/org.el @@ -1,4 +1,81 @@ -;;; lang/org/autoload/org.el -*- lexical-binding: t; -*- +;;; org/org/autoload/org.el -*- lexical-binding: t; -*- + +;;;###autoload +(define-minor-mode +org-pretty-mode + "TODO" + :init-value nil + :lighter " *" + :group 'evil-org + (setq org-hide-emphasis-markers +org-pretty-mode) + (org-toggle-pretty-entities) + ;; In case the above un-align tables + (org-table-map-tables 'org-table-align t)) + +;;;###autoload +(defun +org|realign-table-maybe () + "Auto-align table under cursor." + (when (org-at-table-p) + (save-excursion + (org-table-align)))) + +;;;###autoload +(defun +org|update-cookies () + "Update counts in headlines (aka \"cookies\")." + (when (and buffer-file-name (file-exists-p buffer-file-name)) + (org-update-statistics-cookies t))) + +;;;###autoload +(defun +org/dwim-at-point () + "Do-what-I-mean at point. This includes following timestamp links, aligning +tables, toggling checkboxes/todos, executing babel blocks, previewing latex +fragments, opening links, or refreshing images." + (interactive) + (let* ((scroll-pt (window-start)) + (context (org-element-context)) + (type (org-element-type context))) + (cond + ((memq type '(planning timestamp)) + (org-follow-timestamp-link)) + + ((memq type '(table table-row)) + (if (org-element-property :tblfm (org-element-property :parent context)) + (org-table-recalculate t) + (org-table-align))) + + ((org-element-property :checkbox (org-element-lineage context '(item) t)) + (let ((match (and (org-at-item-checkbox-p) (match-string 1)))) + (org-toggle-checkbox (if (equal match "[ ]") '(16))))) + + ((and (eq type 'headline) + (org-element-property :todo-type context)) + (org-todo + (if (eq (org-element-property :todo-type context) 'done) 'todo 'done))) + + ((and (eq type 'headline) + (string= "ARCHIVE" (car-safe (org-get-tags)))) + (org-force-cycle-archived)) + + ((eq type 'headline) + (org-remove-latex-fragment-image-overlays) + (org-toggle-latex-fragment '(4))) + + ((eq type 'babel-call) + (org-babel-lob-execute-maybe)) + + ((memq type '(src-block inline-src-block)) + (org-babel-execute-src-block)) + + ((memq type '(latex-fragment latex-environment)) + (org-toggle-latex-fragment)) + + ((eq type 'link) + (let ((path (org-element-property :path (org-element-lineage context '(link) t)))) + (if (and path (image-type-from-file-name path)) + (+org/refresh-inline-images) + (org-open-at-point)))) + + (t (+org/refresh-inline-images))) + (set-window-start nil scroll-pt))) ;;;###autoload (defun +org/indent () @@ -126,79 +203,12 @@ wrong places)." (evil-append-line 1)))) ;;;###autoload -(defun +org/toggle-fold () - "Toggle the local fold at the point (as opposed to cycling through all levels -with `org-cycle'). Also removes babel result blocks, if run from a code block." - (interactive) +(defun +org-get-property (name &optional _file) ; TODO Add FILE + "Get a propery from an org file." (save-excursion - (org-beginning-of-line) - (cond ((org-in-src-block-p) - (org-babel-remove-result)) - ((org-at-heading-p) - (outline-toggle-children)) - ((org-at-item-p) - (let ((window-beg (window-start))) - (org-cycle) - (set-window-start nil window-beg)))))) - -;;;###autoload -(defun +org/toggle-checkbox () - "Toggle the presence of a checkbox in the current item." - (interactive) - (org-toggle-checkbox '(4))) - -;;;###autoload -(defun +org/dwim-at-point () - "Do-what-I-mean at point. This includes following timestamp links, aligning -tables, toggling checkboxes/todos, executing babel blocks, previewing latex -fragments, opening links, or refreshing images." - (interactive) - (let* ((scroll-pt (window-start)) - (context (org-element-context)) - (type (org-element-type context))) - (cond - ((memq type '(planning timestamp)) - (org-follow-timestamp-link)) - - ((memq type '(table table-row)) - (if (org-element-property :tblfm (org-element-property :parent context)) - (org-table-recalculate t) - (org-table-align))) - - ((org-element-property :checkbox (org-element-lineage context '(item) t)) - (let ((match (and (org-at-item-checkbox-p) (match-string 1)))) - (org-toggle-checkbox (if (equal match "[ ]") '(16))))) - - ((and (eq type 'headline) - (org-element-property :todo-type context)) - (org-todo - (if (eq (org-element-property :todo-type context) 'done) 'todo 'done))) - - ((and (eq type 'headline) - (string= "ARCHIVE" (car-safe (org-get-tags)))) - (org-force-cycle-archived)) - - ((eq type 'headline) - (org-remove-latex-fragment-image-overlays) - (org-toggle-latex-fragment '(4))) - - ((eq type 'babel-call) - (org-babel-lob-execute-maybe)) - - ((memq type '(src-block inline-src-block)) - (org-babel-execute-src-block)) - - ((memq type '(latex-fragment latex-environment)) - (org-toggle-latex-fragment)) - - ((eq type 'link) - (let ((path (org-element-property :path (org-element-lineage context '(link) t)))) - (if (and path (image-type-from-file-name path)) - (+org/refresh-inline-images) - (org-open-at-point)))) - - (t (+org/refresh-inline-images))) - (set-window-start nil scroll-pt))) + (goto-char 1) + (re-search-forward (format "^#\\+%s:[ \t]*\\([^\n]+\\)" (upcase name)) nil t) + (buffer-substring-no-properties (match-beginning 1) (match-end 1)))) ;;;###autoload (defun +org/refresh-inline-images () @@ -214,3 +224,25 @@ fragments, opening links, or refreshing images." (if (org-before-first-heading-p) (line-end-position) (save-excursion (org-end-of-subtree) (point)))))) + +;;;###autoload +(defun +org/toggle-checkbox () + "Toggle the presence of a checkbox in the current item." + (interactive) + (org-toggle-checkbox '(4))) + +;;;###autoload +(defun +org/toggle-fold () + "Toggle the local fold at the point (as opposed to cycling through all levels +with `org-cycle'). Also removes babel result blocks, if run from a code block." + (interactive) + (save-excursion + (org-beginning-of-line) + (cond ((org-in-src-block-p) + (org-babel-remove-result)) + ((org-at-heading-p) + (outline-toggle-children)) + ((org-at-item-p) + (let ((window-beg (window-start))) + (org-cycle) + (set-window-start nil window-beg)))))) diff --git a/modules/lang/org/autoload/tables.el b/modules/org/org/autoload/tables.el similarity index 96% rename from modules/lang/org/autoload/tables.el rename to modules/org/org/autoload/tables.el index 036c3db3b..6f9e42748 100644 --- a/modules/lang/org/autoload/tables.el +++ b/modules/org/org/autoload/tables.el @@ -1,4 +1,4 @@ -;;; lang/org/autoload/tables.el -*- lexical-binding: t; -*- +;;; org/org/autoload/tables.el -*- lexical-binding: t; -*- ;;;###autoload (defun +org/table-next-row () diff --git a/modules/org/org/config.el b/modules/org/org/config.el new file mode 100644 index 000000000..fc8adf64f --- /dev/null +++ b/modules/org/org/config.el @@ -0,0 +1,259 @@ +;;; org/org/config.el -*- lexical-binding: t; -*- + +;; Ensure ELPA org is prioritized above built-in org. +(when-let (path (locate-library "org" nil doom--package-load-path)) + (cl-pushnew (file-name-directory path) load-path :test #'equal)) + +;; Custom variables +(defvar +org-dir (expand-file-name "~/work/org/") + "The directory where org files are kept.") +(defvaralias 'org-directory '+org-dir) + +(add-hook 'org-load-hook #'+org|init) +(add-hook 'org-mode-hook #'+org|hook) + + +;; +;; Plugins +;; + +(def-package! toc-org + :commands toc-org-enable + :init (add-hook 'org-mode-hook #'toc-org-enable)) + +(def-package! org-crypt ; built-in + :commands org-crypt-use-before-save-magic + :init (add-hook 'org-load-hook #'org-crypt-use-before-save-magic) + :config + (setq org-tags-exclude-from-inheritance '("crypt") + org-crypt-key user-mail-address + epa-file-encrypt-to user-mail-address)) + +;; The standard unicode characters are usually misaligned depending on the font. +;; This bugs me. Personally, markdown #-marks for headlines are more elegant, so +;; we use those. +(def-package! org-bullets + :commands org-bullets-mode + :init (add-hook 'org-mode-hook #'org-bullets-mode) + :config (setq org-bullets-bullet-list '("#"))) + + +;; +;; Hooks & bootstraps +;; + +(defun +org|hook () + "Run everytime `org-mode' is enabled." + (setq line-spacing 1) + + ;; show-paren-mode causes problems for org-indent-mode + (make-local-variable 'show-paren-mode) + (setq show-paren-mode nil) + + (unless org-agenda-inhibit-startup + ;; My version of the 'overview' #+STARTUP option: expand first-level + ;; headings. + (when (eq org-startup-folded t) + (outline-hide-sublevels 2)) + + ;; If saveplace places the point in a folded position, unfold it on load + (when (outline-invisible-p) + (ignore-errors + (save-excursion + (outline-previous-visible-heading 1) + (org-show-subtree)))))) + +(defun +org|init () + "Run once, when org is first loaded." + (define-minor-mode +org-evil-mode + "Evil-mode bindings for org-mode." + :init-value nil + :lighter " !" + :keymap (make-sparse-keymap) + :group 'evil-org) + + (add-hook 'org-mode-hook #'visual-line-mode) + (when (featurep! :feature evil) + (add-hook 'org-mode-hook #'+org-evil-mode)) + + (add-hook 'evil-insert-state-exit-hook #'+org|realign-table-maybe nil t) + (add-hook 'evil-insert-state-exit-hook #'+org|update-cookies nil t) + (add-hook 'before-save-hook #'+org|update-cookies nil t) + + (+org-init-ui) + (+org-init-keybinds) + (+org-hacks)) + +;; +(defun +org-init-ui () + "Configures the UI for `org-mode'." + (setq-default + org-adapt-indentation nil + org-agenda-dim-blocked-tasks nil + org-agenda-files (directory-files +org-dir t "\\.org$" t) + org-agenda-inhibit-startup t + org-agenda-skip-unavailable-files nil + org-cycle-include-plain-lists t + org-cycle-separator-lines 1 + ;; org-ellipsis "  " + org-entities-user '(("flat" "\\flat" nil "" "" "266D" "♭") ("sharp" "\\sharp" nil "" "" "266F" "♯")) + org-fontify-done-headline t + org-fontify-quote-and-verse-blocks t + org-fontify-whole-heading-line t + org-footnote-auto-label 'plain + org-hidden-keywords nil + org-hide-emphasis-markers nil + org-hide-leading-stars t + org-hide-leading-stars-before-indent-mode t + org-image-actual-width nil + org-indent-indentation-per-level 2 + org-indent-mode-turns-on-hiding-stars t + org-pretty-entities nil + org-pretty-entities-include-sub-superscripts t + org-startup-folded t + org-startup-indented t + org-startup-with-inline-images nil + org-tags-column 0 + org-use-sub-superscripts '{} + outline-blank-line t + + ;; LaTeX previews are too small and usually render to light backgrounds, so + ;; this enlargens them and ensures their background (and foreground) match the + ;; current theme. + org-format-latex-options (plist-put org-format-latex-options :scale 1.5) + org-format-latex-options + (plist-put org-format-latex-options + :background (face-attribute (or (cadr (assq 'default face-remapping-alist)) + 'default) + :background nil t))) + + ;; Use ivy/helm if either is available + (when (or (featurep! :completion ivy) + (featurep! :completion helm)) + (setq-default org-completion-use-ido nil + org-outline-path-complete-in-steps nil)) + + ;; Custom fontification + (defsubst +org--tag-face (n) + (let ((kwd (match-string n))) + (or (and (equal kwd "#") 'org-tag) + (and (equal kwd "@") 'org-special-keyword)))) + + (defun +org|init-custom-fontification () + "Correct (and improve) org-mode's font-lock keywords. + + 1. Re-set `org-todo' & `org-headline-done' faces, to make them respect + underlying faces. + 2. Fontify item bullets + 3. Fontify item checkboxes (and when they're marked done) + 4. Fontify dividers/separators (5+ dashes) + 5. Fontify #hashtags and @at-tags, for personal convenience" + (let ((org-todo (format org-heading-keyword-regexp-format + org-todo-regexp)) + (org-done (format org-heading-keyword-regexp-format + (concat "\\(?:" (mapconcat #'regexp-quote org-done-keywords "\\|") "\\)")))) + (setq + org-font-lock-extra-keywords + (append (org-delete-all + `(("\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]" + (0 (org-get-checkbox-statistics-face) t)) + (,org-todo (2 (org-get-todo-face 2) t)) + (,org-done (2 'org-headline-done t))) + org-font-lock-extra-keywords) + `((,org-todo (2 (org-get-todo-face 2) prepend)) + (,org-done (2 'org-headline-done prepend)) + ;; Make checkbox statistic cookies respect underlying faces + ("\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]" + (0 (org-get-checkbox-statistics-face) prepend)) + ;; I like how org-mode fontifies checked TODOs and want this to extend to + ;; checked checkbox items: + ("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" + 1 'org-headline-done prepend) + ;; make plain list bullets stand out + ("^ *\\([-+]\\|[0-9]+[).]\\) " 1 'org-list-dt append) + ;; and separators/dividers + ("^ *\\(-----+\\)$" 1 'org-meta-line) + ;; custom #hashtags & @at-tags for another level of organization + ("\\s-\\(\\([#@]\\)[^ \n.,]+\\)" 1 (+org--tag-face 2))))))) + (add-hook 'org-font-lock-set-keywords-hook #'+org|init-custom-fontification)) + +(defun +org-init-keybinds () + "Sets up org-mode and evil keybindings. Tries to fix the idiosyncrasies +between the two." + (map! (:map org-mode-map "RET" #'org-return-indent) + + (:map +org-evil-mode-map + :n "RET" #'+org/dwim-at-point + + ;; Navigate table cells (from insert-mode) + :i "C-L" #'+org/table-next-field + :i "C-H" #'+org/table-previous-field + :i "C-K" #'+org/table-previous-row + :i "C-J" #'+org/table-next-row + + :n [tab] #'+org/toggle-fold + :i [tab] #'+org/indent-or-next-field-or-yas-expand + :i [backtab] #'+org/dedent-or-prev-field + + :ni [M-return] (λ! (+org/insert-item 'below)) + :ni [S-M-return] (λ! (+org/insert-item 'above)) + + :m "]]" (λ! (org-forward-heading-same-level nil) (org-beginning-of-line)) + :m "[[" (λ! (org-backward-heading-same-level nil) (org-beginning-of-line)) + :m "]l" #'org-next-link + :m "[l" #'org-previous-link + :m "$" #'org-end-of-line + :m "^" #'org-beginning-of-line + :n "gQ" #'org-fill-paragraph + :n "<" #'org-metaleft + :n ">" #'org-metaright + :v "<" (λ! (org-metaleft) (evil-visual-restore)) + :v ">" (λ! (org-metaright) (evil-visual-restore)) + :m "" #'org-cycle + + ;; Fix code-folding keybindings + :n "za" #'+org/toggle-fold + :n "zA" #'org-shifttab + :n "zc" #'outline-hide-subtree + :n "zC" (λ! (outline-hide-sublevels 1)) + :n "zd" (lambda (&optional arg) (interactive "p") (outline-hide-sublevels (or arg 3))) + :n "zm" (λ! (outline-hide-sublevels 1)) + :n "zo" #'outline-show-subtree + :n "zO" #'outline-show-all + :n "zr" #'outline-show-all) + + (:after org-agenda + (:map org-agenda-mode-map + :e "" #'org-agenda-Quit + :e "m" #'org-agenda-month-view + :e "C-j" #'org-agenda-next-item + :e "C-k" #'org-agenda-previous-item + :e "C-n" #'org-agenda-next-item + :e "C-p" #'org-agenda-previous-item)))) + +;; +(defun +org-hacks () + "Getting org to behave." + ;; Don't open separate windows + (cl-pushnew '(file . find-file) org-link-frame-setup) + + ;; Let OS decide what to do with files when opened + (setq org-file-apps + `(("\\.org$" . emacs) + (t . ,(cond (IS-MAC "open -R \"%s\"") + (IS-LINUX "xdg-open \"%s\""))))) + + ;; Remove highlights on ESC + (defun +org|remove-occur-highlights () + (when (derived-mode-p 'org-mode) + (org-remove-occur-highlights) + t)) + (add-hook '+evil-esc-hook #'+org|remove-occur-highlights) + + (after! recentf + ;; Don't clobber recentf with agenda files + (defun +org-is-agenda-file (filename) + (cl-find (file-truename filename) org-agenda-files + :key #'file-truename + :test #'equal)) + (add-to-list 'recentf-exclude #'+org-is-agenda-file))) diff --git a/modules/lang/org/packages.el b/modules/org/org/packages.el similarity index 62% rename from modules/lang/org/packages.el rename to modules/org/org/packages.el index 1bb90700f..cf4164710 100644 --- a/modules/lang/org/packages.el +++ b/modules/org/org/packages.el @@ -1,5 +1,5 @@ ;; -*- no-byte-compile: t; -*- -;;; lang/org/packages.el +;;; org/org/packages.el ;; NOTE This is an insecure source, but unavoidable if we want org 9.0+. ;; orgmode.org offers no secure access to this repo. If this bothers you, @@ -7,14 +7,5 @@ ;; orgmode.org. (package! org-plus-contrib :recipe (:fetcher git :url "http://orgmode.org/org-mode.git")) -(package! org-download) (package! org-bullets :recipe (:fetcher github :repo "hlissner/org-bullets")) (package! toc-org) -(package! ob-go) -(package! ob-mongo) -(package! ob-redis) -(package! ob-restclient) -(package! ob-rust :recipe (:fetcher github :repo "zweifisch/ob-rust")) -(package! ob-sql-mode) -(package! ob-translate) -;; (package! ox-pandox)