From b2aba41920b019a81f81ffcb4c44ef8121df5dfb Mon Sep 17 00:00:00 2001 From: SqrtMinusOne Date: Thu, 9 Nov 2023 14:08:36 +0300 Subject: [PATCH] feat(emacs): more org-ql, restclient and telega chats with topics --- .config/cron/truncate.guile | 1 + .emacs.d/init.el | 108 +++++++++++++++++++++++++++++++- Emacs.org | 121 +++++++++++++++++++++++++++++++++++- 3 files changed, 225 insertions(+), 5 deletions(-) create mode 100644 .config/cron/truncate.guile diff --git a/.config/cron/truncate.guile b/.config/cron/truncate.guile new file mode 100644 index 0000000..564916e --- /dev/null +++ b/.config/cron/truncate.guile @@ -0,0 +1 @@ +(job "0 * * * * " "truncate -s /home/pavel/.local/state/shepherd/shepherd.log") diff --git a/.emacs.d/init.el b/.emacs.d/init.el index 500388b..840e708 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -2911,7 +2911,19 @@ Returns ( . ) or nil." (use-package restclient :if (not my/remote-server) - :straight t) + :straight t + :config + (general-define-key + :keymaps 'restclient-mode-map + :states '(normal visual) + "RET" #'restclient-http-send-current + "M-RET" #'restclient-http-send-current-stay-in-window + "y" nil + "M-y" #'restclient-copy-curl-command) + (general-define-key + :keymaps 'restclient-response-mode-map + :states '(normal visual) + "q" #'quit-window)) (use-package ob-restclient :after (org restclient) @@ -3516,6 +3528,50 @@ and lots of comments which are too long for my Emacs config." (with-eval-after-load 'org-ql (advice-add #'org-ql-view--format-element :override #'my/org-ql-view--format-element-override)) +(defun my/org-ql--get-clock-data-parse-buffer () + (let (res) + (org-element-map (org-element-parse-buffer) 'clock + (lambda (clock) + (let ((start (time-convert + (org-timestamp-to-time (org-element-property :value clock)) + 'integer)) + (end (time-convert + (org-timestamp-to-time (org-element-property :value clock) t) + 'integer))) + (save-excursion + (org-back-to-heading t) + (let* ((headline (org-element-at-point-no-context)) + (tags-val (org-ql--tags-at (point))) + (tags (seq-filter + #'stringp ;; to filter out `org-ql-nil' + (append (unless (eq (car tags-val) 'org-ql-nil) + (car tags-val)) + (unless (eq (cdr tags-val) 'org-ql-nil) + (cdr tags-val))))) + (filename (f-filename + (buffer-file-name))) + (outline-path (mapcar + #'substring-no-properties + (org-ql--outline-path))) + (category (org-get-category))) + (push + `((:start . ,start) + (:end . ,end) + (:headline . ,headline) + (:tags . ,tags) + (:filename . ,filename) + (:outline-path . ,outline-path) + (:category . ,category)) + res)))))) + res)) + +(defun my/org-ql--get-clock-data () + (let (res) + (dolist (file (org-agenda-files)) + (with-current-buffer (find-file-noselect file) + (setq res (append res (my/org-ql--get-clock-data-parse-buffer))))) + res)) + (defun my/alist-agg (path alist value) "Traverse ALIST by PATH, adding VALUE to each node. @@ -3732,6 +3788,12 @@ VALUE is a number." (org-element-at-point))))) (my/org-ql-meeting-tasks meeting))) +(with-eval-after-load 'org-agenda + (general-define-key + :keymaps 'org-agenda-mode-map + :states '(normal motion) + "gm" #'my/org-ql-meeting-tasks-agenda)) + (use-package org-habit-stats :straight (:host github :repo "ml729/org-habit-stats") :after (org) @@ -7056,6 +7118,44 @@ base toot." (setq telega-online-status-function #'my/telega-online-status) +(defun my/telega-switch-to-topic () + (interactive) + (let* ((topics-data (gethash + (plist-get telega-chatbuf--chat :id) + telega--chat-topics)) + (topics-string + (mapcar + (lambda (topic) + (let* ((name (plist-get (plist-get topic :info) :name)) + (unread-count (plist-get topic :unread_count)) + (name-string (with-temp-buffer + (telega-ins--topic-title topic 'with-icon) + (buffer-string)))) + (if (zerop unread-count) + name-string + (format "%-40s (%s)" + name-string + (propertize (format "%d" unread-count) + 'face 'telega-unread-unmuted-modeline))))) + topics-data)) + (topics-collection (cl-loop for datum in topics-data + for string in topics-string + collect (cons string datum))) + (topic (completing-read "Topic: " topics-collection nil t))) + (telega-chat--goto-thread + telega-chatbuf--chat + (plist-get + (plist-get + (alist-get topic topics-collection nil nil #'equal) + :info) + :message_thread_id)))) + +(with-eval-after-load 'telega + (general-define-key + :states '(normal) + :keymaps 'telega-chat-mode-map + "T" #'my/telega-switch-to-topic)) + (use-package google-translate :straight t :if (not my/remote-server) @@ -7320,6 +7420,9 @@ base toot." (defun my/elcord-update-presence-mask-advice (r) (list (my/elcord-mask-buffer-name (nth 0 r)) (nth 1 r))) +(defun my/elcord-symlink () + (shell-command-to-string "bash -c 'ln -sf {app/com.discordapp.Discord,$XDG_RUNTIME_DIR}/discord-ipc-0 &'")) + (use-package elcord :straight t :if (and (or @@ -7333,7 +7436,8 @@ base toot." (advice-add 'elcord--try-update-presence :filter-args #'my/elcord-update-presence-mask-advice) (add-to-list 'elcord-mode-text-alist '(telega-chat-mode . "Telega Chat")) (add-to-list 'elcord-mode-text-alist '(telega-root-mode . "Telega Root")) - (elcord-mode)) + (elcord-mode) + (my/elcord-symlink)) (use-package snow :straight (:repo "alphapapa/snow.el" :host github) diff --git a/Emacs.org b/Emacs.org index d235a24..955f8e1 100644 --- a/Emacs.org +++ b/Emacs.org @@ -4050,7 +4050,19 @@ References: #+begin_src emacs-lisp (use-package restclient :if (not my/remote-server) - :straight t) + :straight t + :config + (general-define-key + :keymaps 'restclient-mode-map + :states '(normal visual) + "RET" #'restclient-http-send-current + "M-RET" #'restclient-http-send-current-stay-in-window + "y" nil + "M-y" #'restclient-copy-curl-command) + (general-define-key + :keymaps 'restclient-response-mode-map + :states '(normal visual) + "q" #'quit-window)) (use-package ob-restclient :after (org restclient) @@ -4884,7 +4896,55 @@ and lots of comments which are too long for my Emacs config." **** Aggregate clocked time This turned out to be kinda complicated... I want to produce a report that aggregates my clocked time. Maybe I'll extract the below into a separate package, but it's so tightly bound to my needs so I'm not sure if there's any value in it. -First, in order to implement the aggregation I need a function to process alists: +Work-in-progress. + +#+begin_src emacs-lisp +(defun my/org-ql--get-clock-data-parse-buffer () + (let (res) + (org-element-map (org-element-parse-buffer) 'clock + (lambda (clock) + (let ((start (time-convert + (org-timestamp-to-time (org-element-property :value clock)) + 'integer)) + (end (time-convert + (org-timestamp-to-time (org-element-property :value clock) t) + 'integer))) + (save-excursion + (org-back-to-heading t) + (let* ((headline (org-element-at-point-no-context)) + (tags-val (org-ql--tags-at (point))) + (tags (seq-filter + #'stringp ;; to filter out `org-ql-nil' + (append (unless (eq (car tags-val) 'org-ql-nil) + (car tags-val)) + (unless (eq (cdr tags-val) 'org-ql-nil) + (cdr tags-val))))) + (filename (f-filename + (buffer-file-name))) + (outline-path (mapcar + #'substring-no-properties + (org-ql--outline-path))) + (category (org-get-category))) + (push + `((:start . ,start) + (:end . ,end) + (:headline . ,headline) + (:tags . ,tags) + (:filename . ,filename) + (:outline-path . ,outline-path) + (:category . ,category)) + res)))))) + res)) + +(defun my/org-ql--get-clock-data () + (let (res) + (dolist (file (org-agenda-files)) + (with-current-buffer (find-file-noselect file) + (setq res (append res (my/org-ql--get-clock-data-parse-buffer))))) + res)) +#+end_src + +A function to aggregate on alists: #+begin_src emacs-lisp (defun my/alist-agg (path alist value) "Traverse ALIST by PATH, adding VALUE to each node. @@ -5136,6 +5196,12 @@ I'll probably delete the below. (org-ql--add-markers (org-element-at-point))))) (my/org-ql-meeting-tasks meeting))) + +(with-eval-after-load 'org-agenda + (general-define-key + :keymaps 'org-agenda-mode-map + :states '(normal motion) + "gm" #'my/org-ql-meeting-tasks-agenda)) #+end_src **** Tracking habits Let's see how this goes. @@ -9692,6 +9758,48 @@ And custom online status. By default it marks you online when the Emacs frame is (setq telega-online-status-function #'my/telega-online-status) #+end_src + +Switch to topic in forum chats. +#+begin_src emacs-lisp +(defun my/telega-switch-to-topic () + (interactive) + (let* ((topics-data (gethash + (plist-get telega-chatbuf--chat :id) + telega--chat-topics)) + (topics-string + (mapcar + (lambda (topic) + (let* ((name (plist-get (plist-get topic :info) :name)) + (unread-count (plist-get topic :unread_count)) + (name-string (with-temp-buffer + (telega-ins--topic-title topic 'with-icon) + (buffer-string)))) + (if (zerop unread-count) + name-string + (format "%-40s (%s)" + name-string + (propertize (format "%d" unread-count) + 'face 'telega-unread-unmuted-modeline))))) + topics-data)) + (topics-collection (cl-loop for datum in topics-data + for string in topics-string + collect (cons string datum))) + (topic (completing-read "Topic: " topics-collection nil t))) + (telega-chat--goto-thread + telega-chatbuf--chat + (plist-get + (plist-get + (alist-get topic topics-collection nil nil #'equal) + :info) + :message_thread_id)))) + +(with-eval-after-load 'telega + (general-define-key + :states '(normal) + :keymaps 'telega-chat-mode-map + "T" #'my/telega-switch-to-topic)) +#+end_src + *** Google Translate Emacs interface to Google Translate. @@ -10067,6 +10175,12 @@ Some functions to override the displayed message: (list (my/elcord-mask-buffer-name (nth 0 r)) (nth 1 r))) #+end_src +Create a symlink for flatpak: +#+begin_src emacs-lisp +(defun my/elcord-symlink () + (shell-command-to-string "bash -c 'ln -sf {app/com.discordapp.Discord,$XDG_RUNTIME_DIR}/discord-ipc-0 &'")) +#+end_src + And the package configuration: #+begin_src emacs-lisp (use-package elcord @@ -10082,7 +10196,8 @@ And the package configuration: (advice-add 'elcord--try-update-presence :filter-args #'my/elcord-update-presence-mask-advice) (add-to-list 'elcord-mode-text-alist '(telega-chat-mode . "Telega Chat")) (add-to-list 'elcord-mode-text-alist '(telega-root-mode . "Telega Root")) - (elcord-mode)) + (elcord-mode) + (my/elcord-symlink)) #+end_src *** Snow #+begin_src emacs-lisp