about summary refs log tree commit diff stats
path: root/lisp
diff options
context:
space:
mode:
authorCase Duckworth2021-03-12 17:20:49 -0600
committerCase Duckworth2021-03-12 17:20:49 -0600
commitc918211dcd9cb0d8c8cb30274c9b81004e6d8315 (patch)
tree4430225d5cccf4c8d685f8af4e0a52bdf63ccd39 /lisp
parentReturn a value from `acdw/set' (diff)
downloademacs-c918211dcd9cb0d8c8cb30274c9b81004e6d8315.tar.gz
emacs-c918211dcd9cb0d8c8cb30274c9b81004e6d8315.zip
Configure `org-mode'.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/acdw-org.el187
1 files changed, 187 insertions, 0 deletions
diff --git a/lisp/acdw-org.el b/lisp/acdw-org.el new file mode 100644 index 0000000..1522f78 --- /dev/null +++ b/lisp/acdw-org.el
@@ -0,0 +1,187 @@
1;;; acdw-org.el -*- lexical-binding: t; coding: utf-8-unix -*-
2;;
3;; Author: Various
4;; URL: https://tildegit.org/acdw/emacs
5;;
6;; This file is NOT part of GNU Emacs.
7;;
8;;; License:
9;;
10;; Everyone is permitted to do whatever with this software, without
11;; limitation. This software comes without any warranty whatsoever,
12;; but with two pieces of advice:
13;; - Don't hurt yourself.
14;; - Make good choices.
15;;
16;;; Commentary:
17;;
18;; This file is for the weird little `org-mode' functions that just take up
19;; space in my main init file. I've tried to give credit where credit is due.
20;;
21;;; Code:
22
23;;; unpackaged.el: https://github.com/alphapapa/unpackaged.el
24
25;;; ORG-RETURN-DWIM
26
27(defun unpackaged/org-element-descendant-of (type element)
28 "Return non-nil if ELEMENT is a descendant of TYPE.
29TYPE should be an element type, like `item' or `paragraph'.
30ELEMENT should be a list like that returned by
31`org-element-context'."
32 ;; MAYBE: Use `org-element-lineage'.
33 (when-let* ((parent (org-element-property :parent element)))
34 (or (eq type (car parent))
35 (unpackaged/org-element-descendant-of type parent))))
36
37(defun unpackaged/org-return-dwim (&optional default)
38 "A helpful replacement for `org-return'. With prefix,
39call `org-return'.
40
41On headings, move point to position after entry content. In
42lists, insert a new item or end the list, with checkbox if
43appropriate. In tables, insert a new row or end the table."
44 ;; Inspired by John Kitchin:
45 ;; http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/
46 (interactive "P")
47 (if default
48 (org-return)
49 (cond
50 ;; Act depending on context around point.
51
52 ;; NOTE: I prefer RET to not follow links, but by uncommenting
53 ;; this block, links will be followed.
54 ;; FURTHER NOTE: Ideally, I would follow links unless point
55 ;; /appeared/ to be at the end of the line (even if it's still
56 ;; inside the link) -- when it would do `org-return'. That
57 ;; would take some /doing/, however.
58
59 ;; ((eq 'link (car (org-element-context)))
60 ;; ;; Link: Open it.
61 ;; (org-open-at-point-global))
62
63 ((org-at-heading-p)
64 ;; Heading: Move to position after entry content. NOTE: This is
65 ;; probably the most interesting feature of this function.
66 (let ((heading-start (org-entry-beginning-position)))
67 (goto-char (org-entry-end-position))
68 (cond ((and (org-at-heading-p)
69 (= heading-start (org-entry-beginning-position)))
70 ;; Entry ends on its heading; add newline after
71 (end-of-line)
72 (insert "\n\n"))
73 (t
74 ;; Entry ends after its heading; back up
75 (forward-line -1)
76 (end-of-line)
77 (when (org-at-heading-p)
78 ;; At the same heading
79 (forward-line)
80 (insert "\n")
81 (forward-line -1))
82 ;; FIXME: looking-back is supposed to be called with
83 ;; more arguments.
84 (while (not (looking-back (rx
85 (repeat 3
86 (seq (optional blank)
87 "\n")))
88 nil))
89 (insert "\n"))
90 (forward-line -1)))))
91
92 ((org-at-item-checkbox-p)
93 ;; Checkbox: Insert new item with checkbox.
94 (org-insert-todo-heading nil))
95
96 ((org-in-item-p)
97 ;; Plain list. Yes, this gets a little complicated...
98 (let ((context (org-element-context)))
99 (if (or (eq 'plain-list (car context)) ; First item in list
100 (and (eq 'item (car context))
101 (not (eq (org-element-property
102 :contents-begin context)
103 (org-element-property
104 :contents-end context))))
105 ;; Element in list item, e.g. a link
106 (unpackaged/org-element-descendant-of 'item context))
107 ;; Non-empty item: Add new item.
108 (org-insert-item)
109 ;; Empty item: Close the list.
110 ;; TODO: Do this with org functions rather than operating
111 ;; on the text. Can't seem to find the right function.
112 (delete-region (line-beginning-position) (line-end-position))
113 (insert "\n"))))
114
115 ((when (fboundp 'org-inlinetask-in-task-p)
116 (org-inlinetask-in-task-p))
117 ;; Inline task: Don't insert a new heading.
118 (org-return))
119
120 ((org-at-table-p)
121 (cond ((save-excursion
122 (beginning-of-line)
123 ;; See `org-table-next-field'.
124 (cl-loop with end = (line-end-position)
125 for cell = (org-element-table-cell-parser)
126 always (equal (org-element-property
127 :contents-begin cell)
128 (org-element-property
129 :contents-end cell))
130 while (re-search-forward "|" end t)))
131 ;; Empty row: end the table.
132 (delete-region (line-beginning-position)
133 (line-end-position))
134 (org-return))
135 (t
136 ;; Non-empty row: call `org-return'.
137 (org-return))))
138 (t
139 ;; All other cases: call `org-return'.
140 (org-return)))))
141
142;;; ORG-FIX-BLANK-LINES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
143
144(defun unpackaged/org-fix-blank-lines (&optional prefix)
145 "Ensure that blank lines exist between headings and
146 between headings and their contents. With prefix, operate on
147 whole buffer. Ensures that blank lines exist after each
148 headings's drawers."
149 (interactive "P")
150 (org-map-entries (lambda ()
151 (org-with-wide-buffer
152 ;; `org-map-entries' narrows the buffer, which
153 ;; prevents us from seeing newlines before the
154 ;; current heading, so we do this part widened.
155 (while (not (looking-back "\n\n" nil))
156 ;; Insert blank lines before heading.
157 (insert "\n")))
158 (let ((end (org-entry-end-position)))
159 ;; Insert blank lines before entry content
160 (forward-line)
161 (while (and (org-at-planning-p)
162 (< (point) (point-max)))
163 ;; Skip planning lines
164 (forward-line))
165 (while (re-search-forward
166 org-drawer-regexp end t)
167 ;; Skip drawers. You might think that
168 ;; `org-at-drawer-p' would suffice, but for
169 ;; some reason it doesn't work correctly when
170 ;; operating on hidden text. This works, taken
171 ;; from `org-agenda-get-some-entry-text'.
172 (re-search-forward "^[ \t]*:END:.*\n?" end t)
173 (goto-char (match-end 0)))
174 (unless (or (= (point) (point-max))
175 (org-at-heading-p)
176 (looking-at-p "\n"))
177 (insert "\n"))))
178 t (if prefix
179 nil
180 'tree)))
181
182(defun acdw/hook--org-mode-fix-blank-lines ()
183 (when (eq major-mode 'org-mode)
184 (let ((current-prefix-arg 4))
185 (call-interactively #'unpackaged/org-fix-blank-lines))))
186
187(provide 'acdw-org)