diff options
Diffstat (limited to 'lisp/acdw-org.el')
-rw-r--r-- | lisp/acdw-org.el | 110 |
1 files changed, 75 insertions, 35 deletions
diff --git a/lisp/acdw-org.el b/lisp/acdw-org.el index 63f6516..f210301 100644 --- a/lisp/acdw-org.el +++ b/lisp/acdw-org.el | |||
@@ -1,10 +1,11 @@ | |||
1 | ;;; acdw-org.el -*- lexical-binding: t; coding: utf-8-unix -*- | 1 | ;;; acdw-org.el --- org extras -*- lexical-binding: t; coding: utf-8-unix -*- |
2 | ;; Author: Various | 2 | ;; Author: Various |
3 | ;; URL: https://tildegit.org/acdw/emacs | 3 | ;; URL: https://tildegit.org/acdw/emacs |
4 | 4 | ||
5 | ;; This file is NOT part of GNU Emacs. | 5 | ;; This file is NOT part of GNU Emacs. |
6 | 6 | ||
7 | ;;; License: | 7 | ;;; License: |
8 | |||
8 | ;; Everyone is permitted to do whatever with this software, without | 9 | ;; Everyone is permitted to do whatever with this software, without |
9 | ;; limitation. This software comes without any warranty whatsoever, | 10 | ;; limitation. This software comes without any warranty whatsoever, |
10 | ;; but with two pieces of advice: | 11 | ;; but with two pieces of advice: |
@@ -12,11 +13,38 @@ | |||
12 | ;; - Make good choices. | 13 | ;; - Make good choices. |
13 | 14 | ||
14 | ;;; Commentary: | 15 | ;;; Commentary: |
16 | |||
15 | ;; This file is for the weird little `org-mode' functions that just take up | 17 | ;; This file is for the weird little `org-mode' functions that just take up |
16 | ;; space in my main init file. I've tried to give credit where credit is due. | 18 | ;; space in my main init file. I've tried to give credit where credit is due. |
17 | 19 | ||
20 | ;; 2021-09-13 Hi readers of "Emacs News!" I just saw that Sacha decided to | ||
21 | ;; include this in her weekly newsletter. Thanks for the gold kind stranger, | ||
22 | ;; etc. If you're looking for stuff in here that /isn't/ just ripped | ||
23 | ;; wholesale from something else on the internet, you'll want the following | ||
24 | ;; (updated as I write more/remember to update them): | ||
25 | |||
26 | ;; `acdw-org/fix-blank-lines-in-buffer' | ||
27 | ;; `acdw-org/count-words-stupidly' | ||
28 | ;; `acdw/org-next-heading-widen' | ||
29 | ;; `acdw/org-previous-heading-widen' | ||
30 | ;; `acdw-org/work-month-headings' | ||
31 | |||
32 | ;; To be honest, I could easily (and probably should) extract some of these out | ||
33 | ;; into their own /real/ libraries. | ||
34 | |||
35 | ;; Until then, just require this file /after/ you require org -- i.e., | ||
36 | ;; (with-eval-after-load 'org (require 'acdw-org)) -- or else it'll load every | ||
37 | ;; time you start up Emacs. | ||
38 | |||
18 | ;;; Code: | 39 | ;;; Code: |
19 | 40 | ||
41 | (require 'dom) | ||
42 | (require 'org) | ||
43 | (require 'org-element) | ||
44 | (require 'ox) | ||
45 | (require 'subr-x) | ||
46 | (require 'calendar) | ||
47 | |||
20 | 48 | ||
21 | ;;; unpackaged.el: https://github.com/alphapapa/unpackaged.el | 49 | ;;; unpackaged.el: https://github.com/alphapapa/unpackaged.el |
22 | 50 | ||
@@ -29,13 +57,14 @@ ELEMENT should be a list like that returned by `org-element-context'." | |||
29 | (or (eq type (car parent)) | 57 | (or (eq type (car parent)) |
30 | (acdw-org/element-descendant-of type parent)))) | 58 | (acdw-org/element-descendant-of type parent)))) |
31 | 59 | ||
32 | (defun acdw-org/return-dwim (&optional default) | 60 | (defun acdw-org/return-dwim (&optional prefix) |
33 | "A helpful replacement for `org-return'. With prefix, call `org-return'. | 61 | "A helpful replacement for `org-return'. With PREFIX, call `org-return'. |
34 | 62 | ||
35 | On headings, move point to position after entry content. In | 63 | On headings, move point to position after entry content. In |
36 | lists, insert a new item or end the list, with checkbox if | 64 | lists, insert a new item or end the list, with checkbox if |
37 | appropriate. In tables, insert a new row or end the table." | 65 | appropriate. In tables, insert a new row or end the table." |
38 | ;; Inspired by John Kitchin: http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/ | 66 | ;; Inspired by John Kitchin: |
67 | ;; http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/ | ||
39 | (interactive "P") | 68 | (interactive "P") |
40 | ;; Auto-fill if enabled | 69 | ;; Auto-fill if enabled |
41 | (when auto-fill-function | 70 | (when auto-fill-function |
@@ -43,13 +72,13 @@ appropriate. In tables, insert a new row or end the table." | |||
43 | (dolist (func auto-fill-function) | 72 | (dolist (func auto-fill-function) |
44 | (funcall func)) | 73 | (funcall func)) |
45 | (funcall auto-fill-function))) | 74 | (funcall auto-fill-function))) |
46 | (if default | 75 | (if prefix |
47 | ;; Handle prefix args | 76 | ;; Handle prefix args |
48 | (pcase default | 77 | (pcase prefix |
49 | ('(4) (newline)) | 78 | ('(4) (newline)) |
50 | ('(16) (newline 2)) | 79 | ('(16) (newline 2)) |
51 | ;; this is ... not ideal. but whatever. | 80 | ;; this is ... not ideal. but whatever. |
52 | (_ (newline default))) | 81 | (_ (newline prefix))) |
53 | (cond | 82 | (cond |
54 | ;; Act depending on context around point. | 83 | ;; Act depending on context around point. |
55 | ((and org-return-follows-link | 84 | ((and org-return-follows-link |
@@ -76,8 +105,10 @@ appropriate. In tables, insert a new row or end the table." | |||
76 | (forward-line) | 105 | (forward-line) |
77 | (insert "\n") | 106 | (insert "\n") |
78 | (forward-line -1)) | 107 | (forward-line -1)) |
79 | ;; FIXME: looking-back is supposed to be called with more arguments. | 108 | (while (not |
80 | (while (not (looking-back (rx (repeat 3 (seq (optional blank) "\n"))))) | 109 | (looking-back |
110 | (rx (repeat 3 (seq (optional blank) "\n"))) | ||
111 | nil)) | ||
81 | (insert "\n")) | 112 | (insert "\n")) |
82 | (forward-line -1))))) | 113 | (forward-line -1))))) |
83 | 114 | ||
@@ -135,10 +166,9 @@ appropriate. In tables, insert a new row or end the table." | |||
135 | (org-return))))) | 166 | (org-return))))) |
136 | 167 | ||
137 | (defun acdw-org/fix-blank-lines (&optional prefix) | 168 | (defun acdw-org/fix-blank-lines (&optional prefix) |
138 | "Ensure that blank lines exist between headings and | 169 | "Ensure blank lines around headings. |
139 | between headings and their contents. With prefix, operate on | 170 | Optional PREFIX argument operates on the entire buffer. |
140 | whole buffer. Ensures that blank lines exist after each | 171 | Drawers are included with their headings." |
141 | headings's drawers." | ||
142 | (interactive "P") | 172 | (interactive "P") |
143 | (org-map-entries (lambda () | 173 | (org-map-entries (lambda () |
144 | (org-with-wide-buffer | 174 | (org-with-wide-buffer |
@@ -168,14 +198,10 @@ appropriate. In tables, insert a new row or end the table." | |||
168 | (org-at-heading-p) | 198 | (org-at-heading-p) |
169 | (looking-at-p "\n")) | 199 | (looking-at-p "\n")) |
170 | (insert "\n")))) | 200 | (insert "\n")))) |
171 | t (if prefix | 201 | t |
172 | nil | 202 | (if prefix |
173 | 'tree))) | 203 | nil |
174 | 204 | 'tree))) | |
175 | (defun acdw-org/fix-blank-lines-in-buffer () | ||
176 | (when (eq major-mode 'org-mode) | ||
177 | (let ((current-prefix-arg 4)) | ||
178 | (call-interactively #'acdw-org/fix-blank-lines)))) | ||
179 | 205 | ||
180 | 206 | ||
181 | ;;; Generate custom IDs: | 207 | ;;; Generate custom IDs: |
@@ -205,19 +231,20 @@ appropriate. In tables, insert a new row or end the table." | |||
205 | "Convert TITLE to a reasonable filename." | 231 | "Convert TITLE to a reasonable filename." |
206 | ;; Based on the slug logic in `org-roam', but `org-roam' also uses a | 232 | ;; Based on the slug logic in `org-roam', but `org-roam' also uses a |
207 | ;; timestamp, and I only use the slug. | 233 | ;; timestamp, and I only use the slug. |
208 | (setq title (s-downcase title)) | 234 | (setq title (downcase title)) |
209 | (setq title (s-replace-regexp "[^a-zA-Z0-9]+" "-" title)) | 235 | (setq title (replace-regexp-in-string "[^a-zA-Z0-9]+" "-" title)) |
210 | (setq title (s-replace-regexp "-+" "-" title)) | 236 | (setq title (replace-regexp-in-string "-+" "-" title)) |
211 | (setq title (s-replace-regexp "^-" "" title)) | 237 | (setq title (replace-regexp-in-string "^-" "" title)) |
212 | (setq title (s-replace-regexp "-$" "" title)) | 238 | (setq title (replace-regexp-in-string "-$" "" title)) |
213 | title) | 239 | title) |
214 | 240 | ||
215 | 241 | ||
216 | ;;; ADVICE AND TWEAKS | 242 | ;;; ADVICE AND TWEAKS |
217 | 243 | ||
244 | ;; I definitely got this from somewhere. | ||
218 | ;; Correct `org-delete-backward-char' to use `backward-delete-char-untabify' | 245 | ;; Correct `org-delete-backward-char' to use `backward-delete-char-untabify' |
219 | (defun acdw-org/delete-backward-char (N) | 246 | (defun acdw-org/delete-backward-char (N) |
220 | "Like `delete-backward-char-untabify', insert whitespace at field end in tables. | 247 | "Keep tables aligned while deleting N characters backward. |
221 | When deleting backwards, in tables this function will insert | 248 | When deleting backwards, in tables this function will insert |
222 | whitespace in front of the next \"|\" separator, to keep the | 249 | whitespace in front of the next \"|\" separator, to keep the |
223 | table aligned. The table will still be marked for re-alignment | 250 | table aligned. The table will still be marked for re-alignment |
@@ -237,9 +264,10 @@ the deletion might narrow the column." | |||
237 | (backward-delete-char-untabify N) | 264 | (backward-delete-char-untabify N) |
238 | (org-fix-tags-on-the-fly)))) | 265 | (org-fix-tags-on-the-fly)))) |
239 | 266 | ||
267 | ;; Same here. | ||
240 | (defun acdw-org/org-table-copy-down (n) | 268 | (defun acdw-org/org-table-copy-down (n) |
241 | "Like `org-table-copy-down', except instead of erroring when | 269 | "Call `org-table-copy-down', or `org-return' outside of a table. |
242 | that command makes no sense, just call `org-return'." | 270 | N is passed to the functions." |
243 | (interactive "p") | 271 | (interactive "p") |
244 | (if (org-table-check-inside-data-field 'noerror) | 272 | (if (org-table-check-inside-data-field 'noerror) |
245 | (org-table-copy-down n) | 273 | (org-table-copy-down n) |
@@ -279,7 +307,7 @@ instead of the true count." | |||
279 | ;; Ignore tables | 307 | ;; Ignore tables |
280 | ((org-at-table-p) (forward-line)) | 308 | ((org-at-table-p) (forward-line)) |
281 | ;; Ignore hyperlinks, but count the descriptions | 309 | ;; Ignore hyperlinks, but count the descriptions |
282 | ((looking-at org-bracket-link-analytic-regexp) | 310 | ((looking-at org-link-bracket-re) |
283 | (when-let ((desc (match-string-no-properties 5))) | 311 | (when-let ((desc (match-string-no-properties 5))) |
284 | (save-match-data | 312 | (save-match-data |
285 | (setq words (+ words | 313 | (setq words (+ words |
@@ -349,9 +377,9 @@ instead of the true count." | |||
349 | (region-end))))) | 377 | (region-end))))) |
350 | (cond ((and region-content clipboard-url (not point-in-link)) | 378 | (cond ((and region-content clipboard-url (not point-in-link)) |
351 | (delete-region (region-beginning) (region-end)) | 379 | (delete-region (region-beginning) (region-end)) |
352 | (insert (org-make-link-string clipboard-url region-content))) | 380 | (insert (org-link-make-string clipboard-url region-content))) |
353 | ((and clipboard-url (not point-in-link)) | 381 | ((and clipboard-url (not point-in-link)) |
354 | (insert (org-make-link-string | 382 | (insert (org-link-make-string |
355 | clipboard-url | 383 | clipboard-url |
356 | (read-string "title: " | 384 | (read-string "title: " |
357 | (with-current-buffer | 385 | (with-current-buffer |
@@ -369,6 +397,7 @@ instead of the true count." | |||
369 | 397 | ||
370 | ;;; Next and previous heading, with widening | 398 | ;;; Next and previous heading, with widening |
371 | (defun acdw/org-next-heading-widen (arg) | 399 | (defun acdw/org-next-heading-widen (arg) |
400 | "Find the ARGth next org heading, widening if necessary." | ||
372 | (interactive "p") | 401 | (interactive "p") |
373 | (let ((current-point (point)) | 402 | (let ((current-point (point)) |
374 | (point-target (if (> arg 0) (point-max) (point-min)))) | 403 | (point-target (if (> arg 0) (point-max) (point-min)))) |
@@ -382,6 +411,7 @@ instead of the true count." | |||
382 | (org-next-visible-heading arg)))) | 411 | (org-next-visible-heading arg)))) |
383 | 412 | ||
384 | (defun acdw/org-previous-heading-widen (arg) | 413 | (defun acdw/org-previous-heading-widen (arg) |
414 | "Find the ARGth previous org heading, widening if necessary." | ||
385 | (interactive "p") | 415 | (interactive "p") |
386 | (acdw/org-next-heading-widen (- arg))) | 416 | (acdw/org-next-heading-widen (- arg))) |
387 | 417 | ||
@@ -390,11 +420,17 @@ instead of the true count." | |||
390 | ;; Gets rid of weekends. | 420 | ;; Gets rid of weekends. |
391 | 421 | ||
392 | (defun acdw-org/work-month-headings (&optional month year) | 422 | (defun acdw-org/work-month-headings (&optional month year) |
423 | "Create headings for every workday in MONTH and YEAR, or this month. | ||
424 | Workdays are Monday through Friday. This function inserts a new | ||
425 | heading with an inactive timestamp for each workday of MONTH in YEAR. | ||
426 | |||
427 | I use this function to attempt to organize my work month. I'll | ||
428 | probably abandon it at some point for a better solution (see: | ||
429 | `org-agenda')." | ||
393 | (interactive (list | 430 | (interactive (list |
394 | (read-number "Month: " (car (calendar-current-date))) | 431 | (read-number "Month: " (car (calendar-current-date))) |
395 | (read-number "Year: " (nth 2 (calendar-current-date))))) | 432 | (read-number "Year: " (nth 2 (calendar-current-date))))) |
396 | (let ((offset 0) | 433 | (let ((month (or month |
397 | (month (or month | ||
398 | (car (calendar-current-date)))) | 434 | (car (calendar-current-date)))) |
399 | (year (or year | 435 | (year (or year |
400 | (car (last (calendar-current-date)))))) | 436 | (car (last (calendar-current-date)))))) |
@@ -415,4 +451,8 @@ instead of the true count." | |||
415 | 451 | ||
416 | 452 | ||
417 | (provide 'acdw-org) | 453 | (provide 'acdw-org) |
418 | ;; acdw-org.el ends here | 454 | ;;; acdw-org.el ends here |
455 | |||
456 | ;; Local Variables: | ||
457 | ;; flymake-inhibit: t | ||
458 | ;; End: | ||