Commit 8f6164aeec88

Vincent Demeester <vincent@sbr.pm>
2024-01-26 11:37:42
tools/emacs: dired transient menu and org-search-from-sacha functions :)
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 9fbbcb7
Changed files (2)
tools/emacs/config/config-dired.el
@@ -233,5 +233,147 @@ This relies on the external 'fd' executable."
   (setq dired-sidebar-theme 'arrow)
   (setq dired-sidebar-use-term-integration t))
 
+(require 'transient)
+(require 'easymenu)
+
+(defcustom cc-dired-listing-switches '("--human-readable"
+                                       "--group-directories-first"
+                                       "--time-style=long-iso")
+  "List of GNU ls arguments used by the function `cc/--dired-sort-by'.
+
+This variable requires GNU ls from coreutils installed.\n
+See the man page `ls(1)' for details."
+  :type '(repeat string)
+  :group 'dired)
+
+(transient-define-prefix cc/dired-sort-by ()
+  "Transient menu to sort Dired buffer by different criteria.
+
+This function requires GNU ls from coreutils installed."
+  :value '("--human-readable"
+           "--group-directories-first"
+           "--time-style=long-iso")
+                                     ; TODO: support cc-dired-listing-switches
+  [["Arguments"
+    ("-a" "all" "--all")
+    ("g" "group directories first" "--group-directories-first")
+    ("-r" "reverse" "--reverse")
+    ("-h" "human readable" "--human-readable")
+    ("t" "time style" "--time-style="
+     :choices ("full-iso" "long-iso" "iso" "locale"))]
+
+   ["Sort By"
+    ("n"
+     "Name"
+     (lambda () (interactive)
+       (cc/--dired-sort-by :name
+                           (transient-args transient-current-command)))
+     :transient nil)
+    ("k"
+     "Kind"
+     (lambda () (interactive)
+       (cc/--dired-sort-by :kind
+                           (transient-args transient-current-command)))
+     :transient nil)
+    ("l"
+     "Date Last Opened"
+     (lambda () (interactive)
+       (cc/--dired-sort-by :date-last-opened
+                           (transient-args transient-current-command)))
+     :transient nil)
+    ("a"
+     "Date Added"
+     (lambda () (interactive)
+       (cc/--dired-sort-by :date-added
+                           (transient-args transient-current-command)))
+     :transient nil)
+    ("m"
+     "Date Modified"
+     (lambda () (interactive)
+       (cc/--dired-sort-by :date-modified
+                           (transient-args transient-current-command)))
+     :transient nil)
+    ("M"
+     "Date Metadata Changed"
+     (lambda () (interactive)
+       (cc/--dired-sort-by :date-metadata-changed
+                           (transient-args transient-current-command)))
+     :transient nil)
+    ("v"
+     "Version"
+     (lambda () (interactive)
+       (cc/--dired-sort-by :version
+                           (transient-args transient-current-command)))
+     :transient nil)
+    ("s"
+     "Size"
+     (lambda () (interactive)
+       (cc/--dired-sort-by :size
+                           (transient-args transient-current-command)))
+     :transient nil)]])
+
+(defun cc/--dired-sort-by (criteria &optional prefix-args)
+  "Sort current Dired buffer according to CRITERIA and PREFIX-ARGS.
+
+This function will invoke `dired-sort-other' with arguments built from
+CRITERIA and PREFIX-ARGS.
+
+CRITERIA is a keyword of which the following are supported:
+  :name             :date-added             :version
+  :kind             :date-metadata-changed  :size
+  :date-last-opened :date-modified
+
+PREFIX-ARGS is a list of GNU ls arguments. If nil, then it will use the value
+of `cc-dired-listing-switches'. Otherwise this is typically populated by the
+Transient menu `cc/dired-sort-by'.
+
+This function requires GNU ls from coreutils installed.
+
+See the man page `ls(1)' for details."
+  (let ((arg-list (list "-l")))
+    (if prefix-args
+        (nconc arg-list prefix-args)
+      (nconc arg-list cc-dired-listing-switches))
+    (cond
+     ((eq criteria :name)
+      (message "Sorted by name"))
+
+     ((eq criteria :kind)
+      (message "Sorted by kind")
+      (push "--sort=extension" arg-list))
+
+     ((eq criteria :date-last-opened)
+      (message "Sorted by date last opened")
+      (push "--sort=time" arg-list)
+      (push "--time=access" arg-list))
+
+     ((eq criteria :date-added)
+      (message "Sorted by date added")
+      (push "--sort=time" arg-list)
+      (push "--time=creation" arg-list))
+
+     ((eq criteria :date-modified)
+      (message "Sorted by date modified")
+      (push "--sort=time" arg-list)
+      (push "--time=modification" arg-list))
+
+     ((eq criteria :date-metadata-changed)
+      (message "Sorted by date metadata changed")
+      (push "--sort=time" arg-list)
+      (push "--time=status" arg-list))
+
+     ((eq criteria :version)
+      (message "Sorted by version")
+      (push "--sort=version" arg-list))
+
+     ((eq criteria :size)
+      (message "Sorted by size")
+      (push "-S" arg-list))
+
+     (t
+      (message "Default sorted by name")))
+
+    (dired-sort-other (mapconcat 'identity arg-list " "))))
+
 (provide 'config-dired)
 ;; config-dired.el ends here
tools/emacs/config/config-org.el
@@ -834,5 +834,60 @@ file which do not already have one."
 ;;               org-tree-slide-content-margin-top 1
 ;;               org-tree-slide-skip-outline-level 4))
 
+;; from https://sachachua.com/blog/2024/01/using-consult-and-org-ql-to-search-my-org-mode-agenda-files-and-sort-the-results-to-prioritize-heading-matches/
+(defun my-consult-org-ql-agenda-jump ()
+  "Search agenda files with preview."
+  (interactive)
+  (let* ((marker (consult--read
+                  (consult--dynamic-collection
+                   #'my-consult-org-ql-agenda-match)
+                  :state (consult--jump-state)
+                  :category 'consult-org-heading
+                  :prompt "Heading: "
+                  :sort nil
+                  :lookup #'consult--lookup-candidate))
+         (buffer (marker-buffer marker))
+         (pos (marker-position marker)))
+    ;; based on org-agenda-switch-to
+    (unless buffer (user-error "Trying to switch to non-existent buffer"))
+    (pop-to-buffer-same-window buffer)
+    (goto-char pos)
+    (when (derived-mode-p 'org-mode)
+      (org-fold-show-context 'agenda)
+      (run-hooks 'org-agenda-after-show-hook))))
+
+(defun my-consult-org-ql-agenda-format (o)
+  (propertize
+   (org-ql-view--format-element o)
+   'consult--candidate (org-element-property :org-hd-marker o)))
+
+(defun my-consult-org-ql-agenda-match (string)
+  "Return candidates that match STRING.
+Sort heading matches first, followed by other matches.
+Within those groups, sort by date and priority."
+  (let* ((query (org-ql--query-string-to-sexp string))
+         (sort '(date reverse priority))
+         (heading-query (-tree-map (lambda (x) (if (eq x 'rifle) 'heading x)) query))
+         (matched-heading
+          (mapcar #'my-consult-org-ql-agenda-format
+                  (org-ql-select 'org-agenda-files heading-query
+                    :action 'element-with-markers
+                    :sort sort)))
+         (all-matches
+          (mapcar #'my-consult-org-ql-agenda-format
+                  (org-ql-select 'org-agenda-files query
+                    :action 'element-with-markers
+                    :sort sort))))
+    (append
+     matched-heading
+     (seq-difference all-matches matched-heading))))
+
+(use-package org-ql
+  :after org
+  :bind ("M-s a" . my-consult-org-ql-agenda-jump))
+
+(use-package org-ql-view
+  :after org-ql)
+
 (provide 'config-org)
 ;;; config-org.el ends here