summary refs log tree commit diff stats
path: root/lisp/acdw-org.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/acdw-org.el')
-rw-r--r--lisp/acdw-org.el548
1 files changed, 0 insertions, 548 deletions
diff --git a/lisp/acdw-org.el b/lisp/acdw-org.el deleted file mode 100644 index 2ec3339..0000000 --- a/lisp/acdw-org.el +++ /dev/null
@@ -1,548 +0,0 @@
1;;; acdw-org.el --- My org customizations -*- lexical-binding: t; -*-
2
3;;; Code:
4
5(require 'cl-lib)
6
7;;; Variables
8
9(defcustom org-agenda-skip-file-regexp nil
10 "Files matching this regexp are removed from `org-agenda-files'."
11 :group 'org-agenda
12 :type 'regexp)
13
14;;; Functions
15
16
17;;; DWIM
18
19;; https://github.com/alphapapa/unpackaged.el,
20;; http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/
21(defun +org-return-dwim (&optional arg)
22 "A helpful replacement for `org-return'.
23When called interactively with \\[universal-argument], call `org-return'
24itself. Other values of ARG will call `newline' with that ARG."
25 (interactive "P")
26 ;; Auto-fill if enabled
27 (when auto-fill-function
28 (dolist (func (ensure-list auto-fill-function))
29 (funcall func)))
30 (cl-letf* ((el (org-element-at-point))
31 ((symbol-function 'el-child-of)
32 (lambda (&rest types)
33 (org-element-lineage el types t))))
34 (cond ; Figure out what we're going to do
35 (arg ; Handle prefix ARG
36 (pcase arg
37 ('(4) (org-return t nil t))
38 (_ (newline arg t))))
39 ((and org-return-follows-link ; Open a link
40 (el-child-of 'link))
41 (org-open-at-point-global))
42 ((org-at-heading-p) ; Open a paragraph after a heading
43 (let ((heading-start (org-entry-beginning-position)))
44 (goto-char (org-entry-end-position))
45 (cond ((and (org-at-heading-p) ; Entry is only a heading
46 (= heading-start (org-entry-beginning-position)))
47 (end-of-line)
48 (newline 2))
49 (:else ; Entry is more than a heading
50 (forward-line -1)
51 (end-of-line)
52 (when (org-at-heading-p)
53 ;; Open a paragraph
54 (forward-line)
55 (newline)
56 (forward-line -1))
57 (while (not (looking-back "\\(?:[[:blank:]]?\n\\)\\{3\\}" nil))
58 (newline))
59 (forward-line -1)))))
60 ((org-at-item-checkbox-p) ; Insert a new checkbox item
61 (end-of-line)
62 (org-insert-todo-heading nil))
63 ((org-in-item-p) ; Insert a new list item
64 (let* ((context (org-element-context el))
65 (first-item-p (eq 'plain-list (car context)))
66 (itemp (eq 'item (car context)))
67 (emptyp (or
68 ;; This (regular) list item is empty
69 (eq (org-element-property :contents-begin context)
70 (org-element-property :contents-end context))
71 ;; This (definition) list item is empty
72 (looking-at " *::")))
73 (item-child-p (el-child-of 'item)))
74 (cond ((and itemp emptyp)
75 ;; This test has to be here even though it's the same as the
76 ;; :else clause, because an item that's empty will also satisfy
77 ;; the next clause.
78 (delete-region (line-beginning-position) (line-end-position))
79 (newline))
80 ((or first-item-p
81 (and itemp (not emptyp))
82 item-child-p)
83 (org-end-of-item)
84 (org-insert-item))
85 (:else
86 (delete-region (line-beginning-position) (line-end-position))
87 (newline)))))
88 ((and (fboundp 'org-inlinetask-in-task-p) ; Just return for inline tasks
89 (org-inlinetask-in-task-p))
90 (org-return))
91 ((org-at-table-p) ; Insert a new table row
92 (cond ((save-excursion ; Empty row: end the table
93 (beginning-of-line)
94 (cl-loop with end = (line-end-position)
95 for cell = (org-element-table-cell-parser)
96 always (eq (org-element-property :contents-begin cell)
97 (org-element-property :contents-end cell))
98 while (re-search-forward "|" end t)))
99 (delete-region (line-beginning-position) (line-end-position))
100 (org-return))
101 (:else ; Non-empty row
102 (org-return))))
103 (:else ; Something else
104 (org-return)))))
105
106(defun +org-table-copy-down|+org-return-dwim (&optional n)
107 "Call `org-table-copy-down' or `+org-return' depending on context."
108 (interactive "P")
109 (if (org-table-check-inside-data-field 'noerror)
110 (org-table-copy-down (or n 1))
111 (+org-return-dwim n)))
112
113
114;;; Buffer view cleanup
115
116(defun +org-hide-drawers-except-point ()
117 "Hide all drawers except for the one point is in."
118 ;; Most of this bit is taken from `org-fold--hide-drawers'.
119 (let ((pt (point))
120 (begin (point-min))
121 (end (point-max)))
122 (save-excursion
123 (goto-char begin)
124 (while (and (< (point) end)
125 (re-search-forward org-drawer-regexp end t))
126 (if (org-fold-folded-p nil 'drawer)
127 (goto-char (org-fold-next-folding-state-change 'drawer nil end))
128 (let* ((drawer (org-element-at-point))
129 (type (org-element-type drawer))
130 (el-begin (org-element-property :begin drawer))
131 (el-end (org-element-property :end drawer)))
132 (when (memq type '(drawer property-drawer))
133 (org-fold-hide-drawer-toggle
134 (if (< el-begin pt el-end) 'off 'on)
135 nil drawer)
136 (goto-char el-end))))))))
137
138
139;;; Copy rich text to the keyboard
140
141;; Thanks to Oleh Krehel:
142;; https://emacs.stackexchange.com/questions/54292/copy-results-of-org-export-directly-to-clipboard
143;; So. Emacs can't do this itself because it doesn't support sending clipboard
144;; or selection contents as text/html. We have to use xclip instead.
145;; (defun org-to-html-to-clipboard (&rest org-export-args)
146;; "Export current org buffer to HTML, then copy it to the clipboard.
147;; ORG-EXPORT-ARGS are passed to `org-export-to-file'."
148;; (let ((f (make-temp-file "org-html-export")))
149;; (apply #'org-export-to-file 'html f org-export-args)
150;; (start-process "xclip" " *xclip*"
151;; "xclip" "-verbose" "-i" f
152;; "-t" "text/html" "-selection" "clipboard")
153;; (message "HTML pasted to clipboard.")))
154
155;; Wayland version.. TODO: make it work for both
156(defun org-to-html-to-clipboard (&rest org-export-args)
157 "Export current org buffer to HTML, then copy it to the clipboard.
158ORG-EXPORT-ARGS are passed to `org-export-to-file'."
159 (let ((buf (generate-new-buffer "*org-html-clipboard*" t)))
160 (apply #'org-export-to-buffer 'html buf org-export-args)
161 (with-current-buffer buf
162 (call-process-region (point-min) (point-max)
163 "wl-copy" nil nil nil
164 "-t" "text/html")
165 (kill-buffer-and-window))
166 (message "HTML copied to clipboard.")))
167
168(defun org-subtree-to-html-to-clipboard ()
169 "Export current subtree to HTML."
170 (interactive)
171 (org-to-html-to-clipboard nil :subtree))
172
173
174;;; Prompting
175
176(defun +org-prompt-for-property (property &optional clipboardp insert list)
177 "Prompt for PROPERTY and return a properly-formatted string.
178Pre-fill the input with clipboard contents if they match CLIPBOARDP. If
179CLIPBOARDP is nil or missing, don't pre-fill.
180
181If INSERT is non-nil, insert the property into the property
182drawer of the current org tree.
183
184If LIST is non-nil, return the result as a list instead of a string."
185 (let* ((kill (current-kill 0))
186 (value (read-string (concat property ": ")
187 (when (and clipboardp
188 (or (eq clipboardp t)
189 (funcall clipboardp kill)))
190 kill))))
191 (when insert
192 (org-set-property property value))
193 (if list
194 (list property value)
195 (format ":%s: %s" property value))))
196
197(defun +org-prompt-tags (&optional prompt global)
198 (let* ((buffer (org-capture-get :buffer))
199 (file (buffer-file-name (or (buffer-base-buffer buffer) buffer)))
200 (org-last-tags-completion-table
201 (org-global-tags-completion-table
202 (if global (org-agenda-files) (list file))))
203 (org-add-colon-after-tag-completion t)
204 (ins (mapconcat
205 #'identity
206 (let ((crm-separator "[ \t]*:[ \t]*"))
207 (completing-read-multiple
208 (or prompt "Tags: ")
209 org-last-tags-completion-table nil nil nil
210 'org-tags-history))
211 ":")))
212 (when (org-string-nw-p ins)
213 (prog1 (concat
214 (unless (eq (char-before) ?:) ":")
215 ins
216 (unless (eq (char-after) ?:) ":"))
217 (when (org-at-heading-p) (org-align-tags))))))
218
219
220;;; Navigating headings
221
222(defun org-next-visible-heading-unfolding (arg)
223 (interactive "p")
224 (when (let ((pt (org-next-visible-heading arg)))
225 (and (buffer-narrowed-p)
226 (or (= (point) (point-min))
227 (and pt
228 (= pt (point-max))))))
229 (widen)
230 (org-next-visible-heading arg)
231 (org-narrow-to-subtree)))
232
233(defun org-previous-visible-heading-unfolding (arg)
234 (interactive "p")
235 (org-next-visible-heading-unfolding (- arg)))
236
237(defun org-up-heading-unfolding (arg)
238 (interactive "p")
239 (when (let ((pt (outline-up-heading arg)))
240 (and (buffer-narrowed-p)
241 (= (point) (point-min))))
242 (widen)
243 (org-up-heading-unfolding arg)
244 (org-narrow-to-subtree)))
245
246
247;;; Misc.
248
249(defun org-clock-in-or-out (prefix)
250 "If clocked in, clock out. Otherwise, clock in."
251 (interactive "P")
252 (if (org-clocking-p)
253 (org-clock-out prefix)
254 (org-clock-in prefix)))
255
256
257;;; Faces
258
259(defface org-bold '((t (:weight bold)))
260 "Bold face in `org-mode' documents.")
261
262(defface org-italic '((t (:slant italic)))
263 "Italic face in `org-mode' documents.")
264
265(defface org-underline '((t (:underline t)))
266 "Underline face in `org-mode' documents.")
267
268(defface org-strikethrough '((t (:strike-through t)))
269 "Strike-through face for `org-mode' documents.")
270
271
272;;; Packages
273
274(use-package org
275 :defer t
276 :custom-face
277 (org-level-1 ((t :inherit fixed-pitch
278 :weight bold
279 :slant italic
280 :height 1.0)))
281 (org-level-2 ((t :inherit fixed-pitch
282 :weight bold
283 :slant italic
284 :height 1.0)))
285 (org-level-3 ((t :inherit fixed-pitch
286 :weight bold
287 :height 1.0)))
288 (org-level-4 ((t :inherit org-level-3)))
289 (org-level-5 ((t :inherit org-level-4)))
290 (org-level-6 ((t :inherit org-level-5)))
291 (org-level-7 ((t :inherit org-level-6)))
292 (org-level-8 ((t :inherit org-level-7)))
293 (org-drawer ((t :inherit fixed-pitch)))
294 (org-property-value ((t :inherit fixed-pitch)))
295 (org-special-keyword ((t :inherit fixed-pitch)))
296 (org-indent ((t :inherit fixed-pitch)))
297 (org-table ((t :inherit fixed-pitch)))
298 :config
299 ;; Options
300 (setopt org-adapt-indentation nil
301 org-auto-align-tags t
302 org-archive-mark-done t
303 org-fold-catch-invisible-edits 'show-and-error
304 org-clock-clocked-in-display 'mode-line
305 org-clock-string-limit 0
306 org-clock-persist nil
307 org-confirm-babel-evaluate nil
308 org-cycle-separator-lines 0
309 org-deadline-warning-days 0
310 org-directory (sync/ "org/" t)
311 org-ellipsis (or (bound-and-true-p truncate-string-ellipsis) "…")
312 org-emphasis-alist
313 '(("*" org-bold)
314 ("/" org-italic)
315 ("_" org-underline)
316 ("=" org-verbatim)
317 ("~" org-code)
318 ("+" org-strikethrough))
319 org-fontify-done-headline t
320 org-fontify-quote-and-verse-blocks t
321 org-fontify-whole-heading-line t
322 org-hide-emphasis-markers t
323 org-html-coding-system 'utf-8-unix
324 org-image-actual-width (list (* (window-font-width)
325 (- fill-column 8)))
326 org-imenu-depth 3
327 org-indent-indentation-per-level 0
328 org-indent-mode-turns-on-hiding-stars nil
329 org-insert-heading-respect-content t
330 org-list-demote-modify-bullet '(("-" . "+")
331 ("+" . "-"))
332 org-log-done 'time
333 org-log-into-drawer t
334 org-num-skip-commented t
335 org-num-skip-unnumbered t
336 org-num-skip-footnotes t
337 org-outline-path-complete-in-steps nil
338 org-pretty-entities t
339 org-pretty-entities-include-sub-superscripts nil
340 org-refile-targets '((nil . (:maxlevel . 2))
341 (org-agenda-files . (:maxlevel . 1)))
342 org-refile-use-outline-path 'file
343 org-special-ctrl-a/e t
344 org-special-ctrl-k t
345 org-src-fontify-natively t
346 org-src-tab-acts-natively t
347 org-src-window-setup 'current-window
348 org-startup-truncated nil
349 org-startup-with-inline-images t
350 org-tags-column 0 ;(- 0 fill-column -3)
351 org-todo-keywords '((sequence "TODO(t)" "WAIT(w@/!)" "ONGOING(o@)"
352 "|" "DONE(d!)" "ASSIGNED(a@/!)")
353 (sequence "|" "CANCELED(k@)")
354 (sequence "MEETING(m)"))
355 org-use-fast-todo-selection 'auto
356 org-use-speed-commands t
357 org-element-use-cache nil)
358 ;; Keys
359 (keymap-set org-mode-map "C-M-k" #'kill-paragraph)
360 (keymap-set org-mode-map "C-M-t" #'transpose-paragraphs)
361 (keymap-set org-mode-map "RET" #'+org-return-dwim)
362 (keymap-set org-mode-map "S-<return>" #'+org-table-copy-down|+org-return-dwim)
363 (keymap-unset org-mode-map "C-'" t)
364 (keymap-unset org-mode-map "C-," t)
365 (keymap-set org-mode-map "C-c C-n" #'org-next-visible-heading-unfolding)
366 (keymap-set org-mode-map "C-c C-p" #'org-previous-visible-heading-unfolding)
367 (keymap-set org-mode-map "C-c C-u" #'org-up-heading-unfolding)
368 ;; Hooks
369 (add-hook 'org-mode-hook
370 (defun org-mode@setup ()
371 (when (require 'visual-fill-column nil t)
372 (setq-local visual-fill-column-extra-text-width '(2 . 2))
373 (visual-fill-column-mode))
374 (variable-pitch-mode)
375 (turn-off-auto-fill)
376 (org-indent-mode)
377 (abbrev-mode)
378 (add-hook 'before-save-hook
379 (defun before-save@org-mode@before-save ()
380 (org-align-tags 'all)
381 (+org-hide-drawers-except-point)
382 )
383 nil :local)))
384 ;; Extra font-lock keywords
385 (font-lock-add-keywords
386 'org-mode
387 `(;; List markers => org-indent
388 (,(concat
389 "^[ ]*\\(\\(?:[-+]\\|\\(?:[0-9]+\\|[A-Za-z]\\)[.)]\\)"
390 "\\(?:[ ]+\\|$\\)\\)"
391 "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\]"
392 "[ ]*\\)?"
393 "\\(?:\\(\\[[ X-]\\]\\)"
394 "\\(?:[ ]+\\|$\\)\\)?")
395 0 'org-indent))))
396
397(use-package org-clock
398 :bind (:map org-mode-map
399 ("<f8>" . org-clock-in-or-out))
400 :config
401 (setopt org-clock-clocked-in-display 'mode-line
402 ;; global-mode-string
403 ;; '((t jabber-activity-mode-string)
404 ;; (:eval (when (org-clocking-p) org-mode-line-string))
405 ;; (display-time-mode display-time-string))
406 )
407 ;; (add-hook 'org-clock-in-hook (defun org-clock@remove-from-global-mode-string ()
408 ;; (setq global-mode-string
409 ;; (delq 'org-mode-line-string global-mode-string))))
410 )
411
412(use-package org-agenda
413 :bind (("C-c a" . org-agenda))
414 :config
415 (setopt org-agenda-skip-deadline-if-done t
416 org-agenda-skip-scheduled-if-done t
417 org-agenda-span 10
418 org-agenda-block-separator ?─
419 org-agenda-time-grid '((daily today require-timed)
420 (800 1000 1200 1400 1600 1800 2000)
421 " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
422 org-agenda-current-time-string "← now ───────────────"
423 org-agenda-include-diary nil ; I use the org-diary features
424 org-agenda-todo-ignore-deadlines 'near
425 org-agenda-todo-ignore-scheduled 'future
426 org-agenda-include-deadlines t
427 org-deadline-warning-days 0
428 org-agenda-show-future-repeats 'next
429 org-agenda-window-setup 'current-window
430 org-agenda-skip-file-regexp "sync-conflict"
431 org-agenda-inhibit-startup t
432 org-agenda-sticky t
433 org-agenda-follow-indirect t
434 org-stuck-projects '("TODO=\"WAIT\""
435 ("TODO" "NEXT")
436 nil
437 "")
438 org-agenda-custom-commands
439 `(("c" "Click Here Digital To-do"
440 ((agenda "" ((org-agenda-overriding-header "Tasks")
441 (org-agenda-span 'fortnight)
442 (org-agenda-start-day "+0")
443 (org-agenda-skip-function
444 '(org-agenda-skip-subtree-if 'todo
445 '("WAIT" "MCKENZIE" "RACHEL")))))
446 (stuck "" ((org-agenda-overriding-header "Waiting"))))
447 ((org-agenda-files ',(list (progn (require 'chd)
448 (chd/ "inbox-chd.org"))
449 (sync/ "org/diary.org")))))))
450 ;; Speedup agenda generation
451 ;; https://orgmode.org/manual/Speeding-Up-Your-Agendas.html
452 ;; https://orgmode.org/worg/agenda-optimization.html
453 (setopt org-agenda-dim-blocked-tasks nil
454 org-agenda-inhibit-startup t
455 org-agenda-use-tag-inheritance nil
456 org-agenda-ignore-properties '(effort appt stats category))
457 ;; Hooks and advice
458 (add-hook 'org-agenda-mode-hook #'truncate-lines-local-mode)
459 (add-hook 'org-agenda-mode-hook #'hl-line-mode)
460 (add-hook 'org-agenda-after-show-hook #'org-narrow-to-subtree)
461 ;; (add-hook 'org-agenda-after-show-hook #'+org-hide-drawers-except-point)
462 (define-advice org-agenda-files (:filter-return (files) skip-regexp)
463 "Filter some files from `org-agenda'."
464 (when org-agenda-skip-file-regexp
465 (setq files
466 (cl-remove-if (lambda (file)
467 (string-match-p org-agenda-skip-file-regexp
468 file))
469 files)))
470 files)
471 (define-advice org-agenda (:around (orig &rest r) inhibit-hooks)
472 (dlet ((org-mode-hook nil))
473 (apply orig r)))
474 (define-advice org-agenda-skip (:around (orig &rest r) fix-looking-at)
475 (dlet ((comment-start-skip "^\\s-*#\\(?: \\|$\\)"))
476 (apply orig r)))
477 ;; (advice-remove 'org-agenda 'org-agenda@inhibit-hooks)
478 (define-advice org-agenda-switch-to (:after (&rest _) do-hooks)
479 (run-hooks 'org-mode-hook))
480 (progress@around org-agenda-list "Building agenda")
481 (with-eval-after-load 'org-agenda
482 (add-to-list 'org-agenda-files (sync/ "org/diary.org"))))
483
484(use-package org-capture
485 :bind (("C-c c" . org-capture)))
486
487(use-package ol ; org-link
488 :after org
489 :preface
490 (defmacro +org-link-define-type (type args &rest body)
491 "Define an org link TYPE.
492A function named `+org-link-TYPE-open' will be created, with ARGS
493as its arguments and BODY as its body. BODY can be blank, in
494which case the user will be messaged (This is a good do-nothing
495effect for exporting link types)."
496 (declare (indent 2)
497 (doc-string 3)
498 (debug (sexp sexp def-body)))
499 (let ((fn (intern (format "+org-link-%s-open" type)))
500 (body (or body `((message ,(format "%S: %%S" type)
501 ,(car args)))))
502 (type-string (format "%S" type)))
503 `(prog1
504 (defun ,fn ,args ,@body)
505 (org-link-set-parameters ,type-string :follow #',fn))))
506 :config
507 (+org-link-define-type sms (number _))
508 (+org-link-define-type tel (number _)))
509
510(use-package ox ; org-export
511 :after org
512 :config
513 (require 'ox-md)
514 (setopt org-export-coding-system 'utf-8-unix
515 org-export-headline-levels 8
516 org-export-with-drawers nil
517 org-export-with-section-numbers nil
518 org-export-with-smart-quotes t
519 org-export-with-sub-superscripts t
520 org-export-with-toc nil))
521
522(use-package org-word-count
523 :load-path "~/src/org-word-count.el/"
524 :hook org-mode-hook)
525
526(use-package org-modern
527 :ensure t
528 :custom-face
529 (org-modern-label ((t :inherit fixed-pitch
530 :height 1.0)))
531 :hook (org-mode-hook)
532 :config
533 (setopt org-modern-star nil
534 org-modern-list '((43 . "◦")
535 (45 . "•")
536 (42 . "‣"))
537 org-hide-leading-stars nil
538 org-modern-hide-stars nil
539 org-tags-column 0
540 org-modern-keyword nil
541 org-modern-table nil))
542
543(use-package org-taskwise
544 :after org
545 :load-path "~/src/org-taskwise.el/")
546
547(provide 'acdw-org)
548;;; acdw-org.el ends here