;;; gpolonkai/org-utils.el --- Org-mode related functions ;;; ;;; SPDX-License-Identifier: GPL-3.0-or-later ;;; Copyright © 2025 Gergely Polonkai ;;; This library is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU Lesser General Public ;;; License as published by the Free Software Foundation; either ;;; version 3 of the License, or (at your option) any later version. ;;; ;;; This library is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; Lesser General Public License for more details. ;;; ;;; You should have received a copy of the GNU Lesser General Public ;;; License along with this library; if not, write to the ;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;;; Boston, MA 02111-1307, USA. ;;; ;;; Commentary: ;;; ;;; Utility functions stolen from the Internet or written by me ;;; ;;; Code: (defun gpolonkai/org-agenda-list (&optional arg) "Wrapper around `org-agenda' to open my custom list. ARG is passed verbatim to `org-agenda'." (interactive "P") (org-agenda arg "c")) (defun gpolonkai/org-insert-current-timestamp (&optional arg) "Insert the current timestamp. ARG is passed verbatim to `org-time-stamp'." (interactive "P") (org-time-stamp '(16) arg)) (defcustom gpolonkai/org-dbl-space-punct-marks (list ?. ?! ?? ?…) "Punctuation marks after which the space key should insert two space characters." :type '(set character)) (defun gpolonkai/org-space-key (&optional arg) "Insert two spaces after certain markers. ARG will be passed down verbatim to `self-insert-command'." (interactive "p") (when (and (not (org-in-block-p '("src"))) (looking-back (rx-to-string `(any,@ gpolonkai/org-dbl-space-punct-marks)) nil)) (call-interactively 'self-insert-command arg)) (call-interactively 'self-insert-command arg)) ;; The whole idea comes from https://blog.aaronbieber.com/2016/09/24/an-agenda-for-life-with-org-mode.html ;; which i use almost verbatim, hence the ~air-~ prefix. (defun air-org-skip-subtree-if-priority (priority) "Skip an agenda subtree if it has a priority of PRIORITY. PRIORITY may be one of the characters ?A, ?B, or ?C." (let ((subtree-end (save-excursion (org-end-of-subtree t))) (pri-value (* 1000 (- org-lowest-priority priority))) (pri-current (org-get-priority (thing-at-point 'line t)))) (if (= pri-value pri-current) subtree-end nil))) (defun air-org-skip-subtree-if-habit () "Skip an agenda entry if it has a STYLE property equal to \"habit\"." (let ((subtree-end (save-excursion (org-end-of-subtree t)))) (if (string= (org-entry-get nil "STYLE") "habit") subtree-end nil))) (defun gpolonkai/org-skip-subtree-if-state (state) "Skip an agenda entry if its state is STATE." (let ((subtree-end (save-excursion (org-end-of-subtree t)))) (if (string= (org-get-todo-state) state) subtree-end nil))) (defun gpolonkai/org-insert-heading-created (&optional arg) "Insert a heading with the CREATED property set to the current time. This emulates how Orgzly works. If ARG is set, insert a subheading; otherwise insert a heading." (interactive "p") (let* ((org-insert-heading-respect-content t) (format-string (concat "[" (substring (cdr org-time-stamp-formats) 1 -1) "]")) (timestamp (format-time-string format-string (current-time)))) (if (> arg 1) (org-insert-subheading '(4)) (org-insert-heading)) (org-set-property "CREATED" timestamp))) ;; The following functions, prefixed with `f-ediff', are from the org-mode mailing list (see archive ;; at https://list.orgmode.org/loom.20130801T011342-572@post.gmane.org/). (defun f-ediff-org-showhide (buf command &rest cmdargs) "If buffer BUF exists and in `org-mode', execute COMMAND with CMDARGS." (when buf (when (eq (buffer-local-value 'major-mode (get-buffer buf)) 'org-mode) (save-excursion (set-buffer buf) (apply command cmdargs))))) (defun f-ediff-org-unfold-tree-element () "Unfold tree at diff location." (f-ediff-org-showhide ediff-buffer-A 'org-reveal) (f-ediff-org-showhide ediff-buffer-B 'org-reveal) (f-ediff-org-showhide ediff-buffer-C 'org-reveal)) (defun f-ediff-org-fold-tree () "Fold tree back to top level." (f-ediff-org-showhide ediff-buffer-A 'hide-sublevels 1) (f-ediff-org-showhide ediff-buffer-B 'hide-sublevels 1) (f-ediff-org-showhide ediff-buffer-C 'hide-sublevels 1)) ;; From the Howardism blog: http://www.howardism.org/Technical/Emacs/capturing-content.html (defun ha/org-capture-fileref-snippet (f type headers func-name) "Capture a snippet from a file, with the filename and the location within. F is the name of the file the capture is coming from. TYPE is the type of the block to be inserted (e.g. \"src\"). HEADERS are the headers appended to the block's #begin line (usually starting with the language’s mode). FUNC-NAME is the name of the function point is in, if any." (let* ((code-snippet (buffer-substring-no-properties (mark) (- (point) 1))) (file-name (buffer-file-name)) (file-base (file-name-nondirectory file-name)) (line-number (line-number-at-pos (region-beginning))) (initial-txt (if (null func-name) (format "From [[file:%s::%s][%s]]:" file-name line-number file-base) (format "From ~%s~ (in [[file:%s::%s][%s]]):" func-name file-name line-number file-base)))) (format " %s ,#+begin_%s %s %s ,#+end_%s" initial-txt type headers code-snippet type))) (defun ha/org-capture-clip-snippet (f) "Capture the selected text as an EXAMPLE block. The captured text also contains a backlink to the file. F is the file the capture is coming from." (with-current-buffer (find-buffer-visiting f) (ha/org-capture-fileref-snippet f "example" "" nil))) (defun ha/org-capture-code-snippet (f) "Capture the selected text as an SRC block. The captured block will have the correct language set, and contains a backlink to the file. F is the file the capture is coming from." (with-current-buffer (find-buffer-visiting f) (let ((org-src-mode (replace-regexp-in-string "-mode" "" (format "%s" major-mode))) (func-name (which-function))) (ha/org-capture-fileref-snippet f "src" org-src-mode func-name)))) (provide 'gpolonkai/org-utils) ;;; org-utils.el ends here