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
This commit is contained in:
Henrik Lissner
2017-07-05 02:33:41 +02:00
parent 576a91b66c
commit d2d4166b42
31 changed files with 774 additions and 721 deletions

View File

@ -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\")"

View File

@ -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

View File

@ -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 "<escape>" #'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))

View File

@ -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))
)

View File

@ -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))
)

View File

@ -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))))

View File

@ -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))))

View File

@ -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))

View File

@ -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))))

View File

@ -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 "<tab>" #'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))

View File

@ -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 "<r>")
(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 "<a>")
(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)))

View File

@ -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))))

View File

@ -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))

View File

@ -0,0 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; org/org-attach/packages.el
(package! org-download)

View File

@ -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))))

View File

@ -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))

View File

@ -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)

View File

@ -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 "<r>")
(+org-capture/dwim
(unless (or (evil-normal-state-p) (evil-insert-state-p))
(buffer-substring beg end))))

View File

@ -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))))

View File

@ -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))

View File

@ -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))

View File

@ -0,0 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; org/org-export/packages.el
(package! ox-pandoc)

View File

@ -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))

View File

@ -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 ())

View File

@ -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)))

View File

@ -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
"<f8>" #'+org-present/org-tree-slides
"<f7>" #'+org-present/next))

View File

@ -0,0 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; org/org-present/packages.el
(package! centered-window-mode)
(package! org-tree-slide)
(package! ox-reveal)

View File

@ -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))))))

View File

@ -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 ()

259
modules/org/org/config.el Normal file
View File

@ -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 "<tab>" #'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 "<escape>" #'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)))

View File

@ -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)