Refactor focus functions and improve clipboard handling

- Refactors `org-focus-private`, `org-focus-lazer`, and `org-focus-all` into a single `org-focus` function for better code reuse.
- Simplifies `org-agenda-refresh` for improved efficiency.
- Improves `my/copy-idlink-to-clipboard` for clarity and robustness.
- Fixes an issue with `my/magit-gptcommit-commit-accept-wrapper` to preserve the original commit message.
- Enhances `my/html2org-clipboard` with error handling for more reliable HTML to Org conversion.
- Updates Clipmon configuration for better integration and stability.
This commit is contained in:
Roger Gonzalez 2025-03-30 11:55:34 -03:00
parent af6b91d643
commit 9ea2a251a0
Signed by: rogs
GPG Key ID: C7ECE9C6C36EC2E6

View File

@ -258,69 +258,81 @@ TODO: Breakup this section into smaller, more focused components later
;; Custom ORG functions ;; Custom ORG functions
;; Refresh org-agenda after rescheduling a task. ;; Refresh org-agenda after rescheduling a task.
(defun org-agenda-refresh () (defun org-agenda-refresh ()
"Refresh all `org-agenda' buffers." "Refresh all `org-agenda' buffers more efficiently."
(dolist (buffer (buffer-list)) (let ((agenda-buffers (seq-filter
(with-current-buffer buffer (lambda (buf)
(when (derived-mode-p 'org-agenda-mode) (with-current-buffer buf
(derived-mode-p 'org-agenda-mode)))
(buffer-list))))
(dolist (buffer agenda-buffers)
(with-current-buffer buffer
(org-agenda-maybe-redo))))) (org-agenda-maybe-redo)))))
(defadvice org-schedule (after refresh-agenda activate) (defadvice org-schedule (after refresh-agenda activate)
"Refresh org-agenda." "Refresh org-agenda."
(org-agenda-refresh)) (org-agenda-refresh))
(defun org-focus-private() "Set focus on private things." (defun org-focus (files msg)
(interactive) "Set focus on specific org FILES with notification MSG."
(setq org-agenda-files '("~/org/private.org")) (setq org-agenda-files files)
(message "Focusing on private Org files")) (message msg))
(defun org-focus-lazer() "Set focus on Lazer things."
(interactive) (defun org-focus-private ()
(setq org-agenda-files '("~/org/lazer.org")) "Set focus on private things."
(message "Focusing on Lazer Org files")) (interactive)
(defun org-focus-all() "Set focus on all things." (org-focus '("~/org/private.org") "Focusing on private Org files"))
(interactive)
(setq org-agenda-files '("~/org/")) (defun org-focus-lazer ()
(message "Focusing on all Org files")) "Set focus on Lazer things."
(interactive)
(org-focus '("~/org/lazer.org") "Focusing on Lazer Org files"))
(defun org-focus-all ()
"Set focus on all things."
(interactive)
(org-focus '("~/org/") "Focusing on all Org files"))
(defun my/org-add-ids-to-headlines-in-file () (defun my/org-add-ids-to-headlines-in-file ()
"Add ID properties to all headlines in the current file which "Add ID properties to all headlines in the current file which
do not already have one." do not already have one."
(interactive) (interactive)
(org-map-entries 'org-id-get-create)) (org-map-entries 'org-id-get-create))
(add-hook 'org-mode-hook (add-hook 'org-mode-hook
(lambda () (lambda ()
(add-hook 'before-save-hook (add-hook 'before-save-hook
'my/org-add-ids-to-headlines-in-file nil 'local))) 'my/org-add-ids-to-headlines-in-file nil 'local)))
(defun my/copy-idlink-to-clipboard() "Copy an ID link with the (defun my/copy-idlink-to-clipboard ()
headline to killring, if no ID is there then create a new unique "Copy an ID link with the headline to killring.
ID. This function works only in org-mode or org-agenda buffers. If no ID exists, create a new unique ID. This function works only in
org-mode or org-agenda buffers.
The purpose of this function is to easily construct id:-links to The purpose of this function is to easily construct id:-links to
org-mode items. If its assigned to a key it saves you marking the org-mode items. If its assigned to a key it saves you marking the
text and copying to the killring. text and copying to the killring.
This function is a cornerstone of my note-linking workflow. It creates and copies This function is a cornerstone of my note-linking workflow. It creates and copies
an org-mode ID link to the current heading, making it easy to reference content an org-mode ID link to the current heading, making it easy to reference content
across my knowledge base. I use this constantly when creating connections between across my knowledge base. I use this constantly when creating connections between
related notes or tasks." related notes or tasks."
(interactive) (interactive)
(when (eq major-mode 'org-agenda-mode) ;if we are in agenda mode we switch to orgmode (when (eq major-mode 'org-agenda-mode) ;if we are in agenda mode we switch to orgmode
(org-agenda-show) (org-agenda-show)
(org-agenda-goto)) (org-agenda-goto))
(when (eq major-mode 'org-mode) ; do this only in org-mode buffers (when (eq major-mode 'org-mode) ; do this only in org-mode buffers
(setq mytmphead (nth 4 (org-heading-components))) (let* ((heading (nth 4 (org-heading-components)))
(setq mytmpid (funcall 'org-id-get-create)) (id (org-id-get-create))
(setq mytmplink (format "[[id:%s][%s]]" mytmpid mytmphead)) (link (format "[[id:%s][%s]]" id heading)))
(kill-new mytmplink) (kill-new link)
(message "Copied %s to killring (clipboard)" mytmplink) (message "Copied %s to killring (clipboard)" link))))
))
(global-set-key (kbd "<f5>") 'my/copy-idlink-to-clipboard) (global-set-key (kbd "<f5>") 'my/copy-idlink-to-clipboard)
(defun org-reset-checkbox-state-maybe () (defun org-reset-checkbox-state-maybe ()
"Reset all checkboxes in an entry if the `RESET_CHECK_BOXES' property is set" "Reset all checkboxes in an entry if the `RESET_CHECK_BOXES' property is set."
(interactive "*") (interactive "*")
(if (org-entry-get (point) "RESET_CHECK_BOXES") (when (org-entry-get (point) "RESET_CHECK_BOXES")
(org-reset-checkbox-state-subtree))) (org-reset-checkbox-state-subtree)))
(defun org-checklist () (defun org-checklist ()
(when (member org-state org-done-keywords) ;; org-state dynamically bound in org.el/org-todo (when (member org-state org-done-keywords) ;; org-state dynamically bound in org.el/org-todo
@ -329,11 +341,13 @@ related notes or tasks."
(add-hook 'org-after-todo-state-change-hook 'org-checklist) (add-hook 'org-after-todo-state-change-hook 'org-checklist)
(defun org-roam-node-insert-immediate (arg &rest args) (defun org-roam-node-insert-immediate (arg &rest args)
(interactive "P") "Insert a node immediately without the capture process."
(let ((args (cons arg args)) (interactive "P")
(org-roam-capture-templates (list (append (car org-roam-capture-templates) (let ((args (cons arg args))
'(:immediate-finish t))))) (org-roam-capture-templates
(apply #'org-roam-node-insert args))) (list (append (car org-roam-capture-templates)
'(:immediate-finish t)))))
(apply #'org-roam-node-insert args)))
;; Save all org buffers on each save ;; Save all org buffers on each save
(add-hook 'auto-save-hook 'org-save-all-org-buffers) (add-hook 'auto-save-hook 'org-save-all-org-buffers)
@ -448,9 +462,14 @@ More info here: https://github.com/doomemacs/doomemacs/issues/581#issuecomment-6
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun my/ediff-init-and-example () (defun my/ediff-init-and-example ()
"Compare init.el with the example init file."
(interactive) (interactive)
(ediff-files (concat doom-user-dir "init.el") (let ((init-file (concat doom-user-dir "init.el"))
(concat doom-emacs-dir "templates/init.example.el"))) (example-file (concat doom-emacs-dir "templates/init.example.el")))
(if (and (file-exists-p init-file)
(file-exists-p example-file))
(ediff-files init-file example-file)
(message "Cannot find init.el or example file"))))
(define-key! help-map "di" #'my/ediff-init-and-example) (define-key! help-map "di" #'my/ediff-init-and-example)
#+end_src #+end_src
@ -523,10 +542,15 @@ Usage: Press F4 in any org-mode buffer to convert and paste HTML from clipboard
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun my/html2org-clipboard () (defun my/html2org-clipboard ()
"Convert HTML in clipboard to Org format and paste it."
(interactive) (interactive)
(kill-new (shell-command-to-string "timeout 1 xclip -selection clipboard -o -t text/html | pandoc -f html -t json | pandoc -f json -t org --wrap=none")) (condition-case err
(yank) (progn
(message "Pasted HTML in org")) (kill-new (shell-command-to-string
"timeout 1 xclip -selection clipboard -o -t text/html | pandoc -f html -t json | pandoc -f json -t org --wrap=none"))
(yank)
(message "Pasted HTML in org"))
(error (message "Error converting HTML to Org: %s" (error-message-string err)))))
(after! org (after! org
(define-key org-mode-map (kbd "<f4>") 'my/html2org-clipboard)) (define-key org-mode-map (kbd "<f4>") 'my/html2org-clipboard))
#+end_src #+end_src
@ -561,10 +585,14 @@ Clipmon serves as my clipboard manager within Emacs. I chose it over alternative
The configuration below sets up Clipmon to check the clipboard every second and makes the kill ring accessible through M-y with helm integration. The configuration below sets up Clipmon to check the clipboard every second and makes the kill ring accessible through M-y with helm integration.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(global-set-key (kbd "M-y") 'helm-show-kill-ring) (use-package clipmon
(add-to-list 'after-init-hook 'clipmon-mode-start) :init
(defadvice clipmon--on-clipboard-change (around stop-clipboard-parsing activate) (let ((interprogram-cut-function nil)) ad-do-it)) (global-set-key (kbd "M-y") 'helm-show-kill-ring)
(setq clipmon-timer-interval 1) (add-to-list 'after-init-hook 'clipmon-mode-start)
:config
(defadvice clipmon--on-clipboard-change (around stop-clipboard-parsing activate)
(let ((interprogram-cut-function nil)) ad-do-it))
(setq clipmon-timer-interval 1))
#+end_src #+end_src
@ -587,13 +615,15 @@ The configuration below sets up Clipmon to check the clipboard every second and
:END: :END:
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun my/magit-gptcommit-commit-accept-wrapper (orig-fun &rest args) (defun my/magit-gptcommit-commit-accept-wrapper (orig-fun &rest args)
"Wrapper for magit-gptcommit-commit-accept to preserve original message."
(when-let ((buf (magit-commit-message-buffer))) (when-let ((buf (magit-commit-message-buffer)))
(with-current-buffer buf (with-current-buffer buf
(let ((orig-message (git-commit-buffer-message))) (let ((orig-message (string-trim-right (or (git-commit-buffer-message) "") "\n$")))
(apply orig-fun args) (apply orig-fun args)
(save-excursion (unless (string-empty-p orig-message)
(goto-char (point-min)) (save-excursion
(insert (string-trim-right orig-message "\n$"))))))) (goto-char (point-min))
(insert orig-message)))))))
(advice-add 'magit-gptcommit-commit-accept (advice-add 'magit-gptcommit-commit-accept
:around #'my/magit-gptcommit-commit-accept-wrapper) :around #'my/magit-gptcommit-commit-accept-wrapper)