aboutsummaryrefslogtreecommitdiff
path: root/.emacs.d/lisp/my
diff options
context:
space:
mode:
Diffstat (limited to '.emacs.d/lisp/my')
-rw-r--r--.emacs.d/lisp/my/emms-info-ytdl.el100
-rw-r--r--.emacs.d/lisp/my/generic-search.el99
-rw-r--r--.emacs.d/lisp/my/link-gopher.el113
-rw-r--r--.emacs.d/lisp/my/my-algo.el72
-rw-r--r--.emacs.d/lisp/my/my-bbdb.el190
-rw-r--r--.emacs.d/lisp/my/my-buffer.el448
-rw-r--r--.emacs.d/lisp/my/my-calibre.el83
-rw-r--r--.emacs.d/lisp/my/my-complete.el56
-rw-r--r--.emacs.d/lisp/my/my-consult.el35
-rw-r--r--.emacs.d/lisp/my/my-corfu.el39
-rw-r--r--.emacs.d/lisp/my/my-detached.el40
-rw-r--r--.emacs.d/lisp/my/my-dired.el109
-rw-r--r--.emacs.d/lisp/my/my-editing.el340
-rw-r--r--.emacs.d/lisp/my/my-emms.el454
-rw-r--r--.emacs.d/lisp/my/my-github.el68
-rw-r--r--.emacs.d/lisp/my/my-gitlab.el61
-rw-r--r--.emacs.d/lisp/my/my-gnus.el327
-rw-r--r--.emacs.d/lisp/my/my-grep.el48
-rw-r--r--.emacs.d/lisp/my/my-help.el138
-rw-r--r--.emacs.d/lisp/my/my-hiedb.el73
-rw-r--r--.emacs.d/lisp/my/my-hnreader.el106
-rw-r--r--.emacs.d/lisp/my/my-libgen.el241
-rw-r--r--.emacs.d/lisp/my/my-magit.el59
-rw-r--r--.emacs.d/lisp/my/my-markdown.el37
-rw-r--r--.emacs.d/lisp/my/my-markup.el68
-rw-r--r--.emacs.d/lisp/my/my-media-segment.el182
-rw-r--r--.emacs.d/lisp/my/my-net.el113
-rw-r--r--.emacs.d/lisp/my/my-nov.el56
-rw-r--r--.emacs.d/lisp/my/my-openlibrary.el147
-rw-r--r--.emacs.d/lisp/my/my-org.el1003
-rw-r--r--.emacs.d/lisp/my/my-osm.el56
-rw-r--r--.emacs.d/lisp/my/my-package.el263
-rw-r--r--.emacs.d/lisp/my/my-pacman.el46
-rw-r--r--.emacs.d/lisp/my/my-pdf-tools.el200
-rw-r--r--.emacs.d/lisp/my/my-prog.el142
-rw-r--r--.emacs.d/lisp/my/my-project.el104
-rw-r--r--.emacs.d/lisp/my/my-rtliber.el72
-rw-r--r--.emacs.d/lisp/my/my-scihub.el53
-rw-r--r--.emacs.d/lisp/my/my-semantic-scholar.el100
-rw-r--r--.emacs.d/lisp/my/my-servall.el39
-rw-r--r--.emacs.d/lisp/my/my-tempel.el68
-rw-r--r--.emacs.d/lisp/my/my-tide.el43
-rw-r--r--.emacs.d/lisp/my/my-time.el51
-rw-r--r--.emacs.d/lisp/my/my-utils.el409
-rw-r--r--.emacs.d/lisp/my/my-web.el129
-rw-r--r--.emacs.d/lisp/my/my-wget.el79
-rw-r--r--.emacs.d/lisp/my/my-wikipedia.el182
-rw-r--r--.emacs.d/lisp/my/my-ytdl.el78
-rw-r--r--.emacs.d/lisp/my/radix-tree.el258
49 files changed, 0 insertions, 7277 deletions
diff --git a/.emacs.d/lisp/my/emms-info-ytdl.el b/.emacs.d/lisp/my/emms-info-ytdl.el
deleted file mode 100644
index 489f3fb..0000000
--- a/.emacs.d/lisp/my/emms-info-ytdl.el
+++ /dev/null
@@ -1,100 +0,0 @@
-;;; emms-info-ytdl.el --- info-method for EMMS using ytdl -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2022 Free Software Foundation, Inc.
-
-;; Author: Yuchen Pei (ycp@gnu.org)
-;; Keywords: multimedia
-
-;; EMMS is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; EMMS 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 General Public
-;; License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with EMMS; see the file COPYING.. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; (add-to-list emms-info-functions 'emms-info-ytdl)
-
-;; To use this you would need to have `emms-info-ytdl-command`
-;; (typically youtube-dl or yt-dlp) installed on your system.
-
-
-;;; Code:
-
-(require 'emms-info)
-(require 'json)
-
-
-(defgroup emms-info-ytdl nil
- "Options for EMMS."
- :group 'emms-info)
-
-(defvar emms-info-ytdl-field-map
- '((info-title . title)
- (info-artist . artist)
- (info-playing-time . duration))
- "Mapping for ytdl output.")
-
-(defvar emms-info-ytdl-regexp
- "^https?://"
- "Regexp to use ytdl to get info.")
-
-(defvar emms-info-ytdl-exclude-regexp
- ;; "\\(\\.\\w+$\\|/playlist\\|/channel\\)"
- "\\(/playlist\\|/channel\\)"
- "Regexp not to use ytdl to get info.")
-
-(defvar emms-info-ytdl-command
- "yt-dlp"
- "Command to run for emms-info-ytdl.")
-
-(defcustom emms-info-ytdl-using-torsocks
- nil
- "If t, use torsocks to get ytdl info")
-
-(defun emms-info-ytdl (track)
- "Set TRACK info using ytdl."
- (when (and (eq (emms-track-type track) 'url)
- (string-match emms-info-ytdl-regexp (emms-track-name track))
- (not
- (string-match emms-info-ytdl-exclude-regexp
- (emms-track-name track))))
- (with-temp-buffer
- (when (zerop
- (let ((coding-system-for-read 'utf-8))
- (if emms-info-ytdl-using-torsocks
- (my-call-process-with-torsocks
- emms-info-ytdl-command nil '(t nil) nil "-j"
- (emms-track-name track))
- (call-process emms-info-ytdl-command nil '(t nil) nil
- "-j" (emms-track-name track)))))
- (goto-char (point-min))
- (condition-case nil
- (let ((json-fields (json-read)))
- (mapc
- (lambda (field-map)
- (let ((emms-field (car field-map))
- (ytdl-field (cdr field-map)))
- (let ((track-field (assoc ytdl-field json-fields)))
- (when track-field
- (emms-track-set
- track
- emms-field
- (if (eq emms-field 'info-playing-time)
- (truncate (cdr track-field))
- (cdr track-field)))))))
- emms-info-ytdl-field-map))
- (error (message "error while reading track info")))
- track))))
-
-(provide 'emms-info-ytdl)
-
-;;; emms-info-ytdl.el ends here
diff --git a/.emacs.d/lisp/my/generic-search.el b/.emacs.d/lisp/my/generic-search.el
deleted file mode 100644
index 3db5b08..0000000
--- a/.emacs.d/lisp/my/generic-search.el
+++ /dev/null
@@ -1,99 +0,0 @@
-;;; generic-search.el -- A search result UI -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it
-;; under the terms of the GNU Affero General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-
-;; dotfiles 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
-;; Affero General Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; A search result UI. A generic search result mode displaying a list
-;; of things, and action on an item
-
-
-;;; Code:
-
-(defvar-local generic-search-transformer nil)
-(defvar-local generic-search-formatter nil)
-(defvar-local generic-search-default-action nil)
-(defvar-local generic-search-results nil)
-(defvar-local generic-search-keymap nil)
-
-(defvar generic-search-default-transformer 'identity)
-(defvar generic-search-default-formatter 'pp)
-(defvar generic-search-default-default-action 'generic-search-message-pp)
-(defvar generic-search-default-keymap button-map)
-
-(defun generic-search-message-pp (data)
- (interactive)
- (message (pp data)))
-
-(define-derived-mode generic-search-mode special-mode "Generic search"
- "Search results.")
-
-(defun generic-search-buffer-name (name)
- (format "*generic-search %s*" name))
-
-(defun generic-search-open (results name &optional display-options)
- (let ((buffer-name (generic-search-buffer-name name)))
- (with-current-buffer (get-buffer-create buffer-name)
- (generic-search-mode)
- (setq generic-search-results results
- generic-search-formatter
- (or (alist-get 'formatter display-options)
- generic-search-default-formatter)
- generic-search-default-action
- (or (alist-get 'default-action display-options)
- generic-search-default-default-action)
- generic-search-keymap
- (or (alist-get 'keymap display-options)
- generic-search-default-keymap)
- generic-search-transformer
- (or (alist-get 'transfomer display-options
- generic-search-default-transformer)))
- (generic-search-update)
- (switch-to-buffer-other-window buffer-name))))
-
-(defun generic-search-update ()
- (let ((inhibit-read-only t))
- (erase-buffer)
- (insert (format "%s Results:" (length generic-search-results)))
- (seq-do (lambda (result)
- (insert "\n----\n")
- (let ((start (point)))
- (insert
- (funcall generic-search-formatter result))
- (make-text-button start (point)
- 'action generic-search-default-action
- 'button-data
- (funcall generic-search-transformer result)
- 'keymap generic-search-keymap)))
- generic-search-results)
- (goto-char (point-min))
- (forward-button 1)))
-
-(defun generic-search-refresh ()
- (interactive)
- (generic-search-update))
-
-(define-key generic-search-mode-map "\t" 'forward-button)
-(define-key generic-search-mode-map [backtab] 'backward-button)
-(define-key generic-search-mode-map "g" 'generic-search-refresh)
-
-(provide 'generic-search)
diff --git a/.emacs.d/lisp/my/link-gopher.el b/.emacs.d/lisp/my/link-gopher.el
deleted file mode 100644
index cf8b47a..0000000
--- a/.emacs.d/lisp/my/link-gopher.el
+++ /dev/null
@@ -1,113 +0,0 @@
-;;; link-gopher.el -- Find and filter urls -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it
-;; under the terms of the GNU Affero General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-
-;; dotfiles 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
-;; Affero General Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Find and filter urls.
-
-;;; Code:
-(require 'my-utils)
-
-;;; todo: some of these functions could be unnecessary
-(defun link-gopher-kill-all-links (url filter-regexp)
- (interactive (list (read-string "URL: "
- (thing-at-point-url-at-point))
- (read-string "Regexp: ")))
- (let ((results (link-gopher-get-all-links url filter-regexp)))
- (kill-new (string-join results " "))
- (message "Added %d links to the kill ring!" (length results))))
-(defun link-gopher-kill-all-links-in-buffer (filter-regexp)
- "may not report accurate links e.g. when the link contains special chars like space"
- (interactive "sRegexp: ")
- (let ((links (link-gopher-get-all-links-in-buffer filter-regexp)))
- (kill-new (string-join links " "))
- (message "Added %d links to the kill ring!" (length links))))
-(defun link-gopher-get-all-links (url filter-regexp)
- "get all links satisfying a regexp on url.
-no duplicates."
- (with-current-buffer (url-retrieve-synchronously url)
- (my-skip-http-header)
- (let ((results) (clean-url) (hash (make-hash-table :test 'equal)))
- (while (re-search-forward
- "\\(href\\|HREF\\|src\\|SRC\\)\\ *=\\ *['\"]\\([^\"']+\\)['\"]" nil t)
- (setq clean-url (link-gopher-clean-url (match-string 2) url))
- (when (or (not filter-regexp)
- (string-match filter-regexp clean-url))
- (when (not (gethash clean-url hash))
- (puthash clean-url t hash)
- (push clean-url results))))
- (reverse results))))
-(defun link-gopher-clean-url (url current-url)
- "clean url
- hello - filename: hello
- /hello - type: nil; host: nil; filename: /hello
- //hello - type: nil; host: hello; filename: empty string
-removing frags
-"
- (let* ((current-domain
- (progn (string-match "^\\(.*://[^/]+/\\)" current-url)
- (match-string 1 current-url)))
- (current-domain-dir-path
- (progn (string-match "^\\(.*/\\)" current-url)
- (match-string 1 current-url)))
- (url-no-frags (replace-regexp-in-string "#.*" "" url)))
- (url-encode-url
- (cond ((string-match "://" url-no-frags) url-no-frags)
- ((string-match "^//" url-no-frags) (concat "https:" url-no-frags))
- ((string-match "^/" url-no-frags) (concat current-domain url-no-frags))
- (t (concat current-domain-dir-path url-no-frags))))))
-(defun link-gopher-get-all-links-in-buffer (filter-regexp)
- (let ((results) (hash (make-hash-table :test 'equal)))
- (save-excursion
- (goto-char (point-min))
- (while
- (progn
- (when-let ((url (get-text-property (point) 'shr-url)))
- (when (or (not filter-regexp)
- (string-match filter-regexp url))
- (when (not (gethash url hash))
- (puthash url t hash)
- (push url results))))
- (when-let ((next-change-point
- (next-single-property-change (point) 'shr-url)))
- (goto-char next-change-point)))))
- results))
-
-(defun http-s-links-in-buffer (&optional filter-regexp)
- (save-excursion
- (unless filter-regexp (setq filter-regexp ".*"))
- (let ((results) (url))
- (while (re-search-forward "\\(http\\(s\\)://[^\" \n]+\\)" nil t)
- (setq url (match-string 1))
- (when (and (string-match filter-regexp url)
- (not (member url results)))
- (push url results)))
- (reverse results))))
-
-(defun http-s-media-links-in-buffer ()
- (http-s-links-in-buffer
- "\\.\\(jpg\\|png\\|gif\\|webp\\|mp4\\|flv\\|mkv\\|mov\\|webm\\|ogv\\|avi\\|rmvb\\|mp3\\|ogg\\|opus\\|pdf\\|docx\\|epub\\)$"))
-
-(provide 'link-gopher)
-;;; link-gopher.el ends here
-
diff --git a/.emacs.d/lisp/my/my-algo.el b/.emacs.d/lisp/my/my-algo.el
deleted file mode 100644
index f3e8bc8..0000000
--- a/.emacs.d/lisp/my/my-algo.el
+++ /dev/null
@@ -1,72 +0,0 @@
-;;; my-algo.el -- Algorithms related exentions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Algorithms and data structure.
-
-;;; Code:
-
-;;; radix tree with string array
-(require 'radix-tree)
-(defun my-compare-string-arrays (xs1 start1 end1 xs2 start2 end2)
- (let* ((i 0)
- (s1 (or start1 0))
- (e1 (or end1 (length xs1)))
- (s2 (or start2 0))
- (e2 (or end2 (length xs2)))
- (l1 (- e1 s1))
- (l2 (- e2 s2))
- (cmp t))
- (while (and (< i l1) (< i l2) (eq t cmp))
- (setq cmp (compare-strings (elt xs1 (+ s1 i)) nil nil
- (elt xs2 (+ s2 i)) nil nil))
- (setq i (1+ i)))
- (cond ((and (numberp cmp) (< cmp 0)) (- i))
- ((and (numberp cmp) (> cmp 0)) i)
- ((= l1 l2) t)
- ((< l1 l2) (- i))
- (t i))))
-
-(defun my-radix-tree-from-list ()
- (goto-char (point-min))
- (let ((result radix-tree-empty)
- (radix-tree-compare-function 'my-compare-string-arrays))
- (while (not (eobp))
- (let ((line (vconcat
- (split-string
- (buffer-substring-no-properties
- (point)
- (progn (forward-line 1) (1- (point))))
- "/"))))
- (setq result
- (radix-tree-insert result line t))))
- result))
-
-(defun my-kill-radix-tree-from-list ()
- (interactive)
- (let ((max-lisp-eval-depth 8000))
- (kill-new (pp (my-radix-tree-from-list)))))
-
-(provide 'my-algo)
-;;; my-algo.el ends here
-
diff --git a/.emacs.d/lisp/my/my-bbdb.el b/.emacs.d/lisp/my/my-bbdb.el
deleted file mode 100644
index 80661cd..0000000
--- a/.emacs.d/lisp/my/my-bbdb.el
+++ /dev/null
@@ -1,190 +0,0 @@
-;;; my-bbdb.el -- Extensions for bbdb -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for bbdb.
-
-;;; Code:
-
-
-;; overrides bbdb-read-record in bbdb-com.el
-(defun my-bbdb-read-record (&optional first-and-last)
- "Read and return a new BBDB record.
-Does not insert it into the database or update the hashtables,
-but does ensure that there will not be name collisions."
- (bbdb-editable)
- (let ((record (bbdb-empty-record)))
- ;; name
- (let (name)
- (bbdb-error-retry
- (setq name (bbdb-read-name first-and-last))
- (bbdb-check-name (car name) (cdr name)))
- (bbdb-record-set-firstname record (car name))
- (bbdb-record-set-lastname record (cdr name)))
-
- ;; akas
- (bbdb-record-set-aka record
- (bbdb-split 'aka (bbdb-read-string "AKAs: ")))
-
- ;; urls
- (bbdb-record-set-xfield record 'url (bbdb-read-string "urls: "))
-
- ;; mail
- (bbdb-record-set-mail
- record (bbdb-split 'mail (bbdb-read-string "E-Mail Addresses: ")))
-
- ;; notes
- (bbdb-record-set-xfield record 'notes (bbdb-read-string "notes: "))
-
- record))
-
-;; overrides bbdb-create
-;;;###autoload
-(defun my-bbdb-create (record)
- "Add a new RECORD to BBDB.
-When called interactively read all relevant info.
-Do not call this from a program; call `bbdb-create-internal' instead."
- (interactive (list (bbdb-read-record current-prefix-arg)))
- (bbdb-change-record record)
- (bbdb-display-records (list record) nil nil t))
-
-(defun my-bbdb-form (name)
- "Insert or update a bbdb record using a form.
-
-If NAME exists in bbdb, update. Otherwise insert."
- (interactive
- (list (completing-read "Name: " (mapcar 'bbdb-record-name (bbdb-records)))))
- (let* ((record (or (car (bbdb-gethash name))
- (bbdb-empty-record)))
- (new-first-name) (new-last-name))
- (switch-to-buffer-other-window "*Form BBDB*")
- (kill-all-local-variables)
- (let ((inhibit-read-only t)) (erase-buffer))
- (remove-overlays)
- (widget-insert "BBDB form\n\n")
- (setq my-bbdb-widget-first-name
- (widget-create 'editable-field :format "First Name: %v"
- (or (bbdb-record-firstname record)
- (car (bbdb-divide-name name)))))
- (setq my-bbdb-widget-last-name
- (widget-create 'editable-field :format "Last Name: %v"
- (or (bbdb-record-lastname record)
- (cdr (bbdb-divide-name name)))))
- (setq my-bbdb-widget-aka
- (widget-create 'editable-field
- :format "Aliases: %v"
- :value (bbdb-concat
- 'aka
- (bbdb-record-aka record))))
- (setq my-bbdb-widget-org
- (widget-create 'editable-field
- :format "Organisations: %v"
- :value (bbdb-concat
- 'organization
- (bbdb-record-organization record))))
- (setq my-bbdb-widget-mail
- (widget-create 'editable-field
- :format "Email addresses: %v"
- :value (bbdb-concat 'mail (bbdb-record-mail record))))
- (widget-insert "Phone numbers\n")
- (setq my-bbdb-widget-phone
- (widget-create 'editable-list
- :entry-format "%i %d %v"
- :value
- (mapcar (lambda (phone-info)
- (list (aref phone-info 0)
- (aref phone-info 1)))
- (bbdb-record-phone record))
- '(group
- (menu-choice
- :tag "Type"
- (choice-item :value "cell")
- (choice-item :value "work")
- (choice-item :value "home")
- (choice-item :value "other"))
- (editable-field :format "number: %v" ""))))
- (widget-create
- 'push-button
- :notify (lambda (&rest _)
- (setq new-first-name (widget-value my-bbdb-widget-first-name))
- (setq new-last-name (widget-value my-bbdb-widget-last-name))
- (unless (equal name
- (bbdb-concat 'name-first-last new-first-name
- new-last-name))
- (bbdb-check-name new-first-name new-last-name))
- (bbdb-record-set-name record new-first-name new-last-name)
- (bbdb-record-set-organization
- record (bbdb-split 'organization (widget-value my-bbdb-widget-org)))
- (bbdb-record-set-mail
- record (bbdb-split 'mail (widget-value my-bbdb-widget-mail)))
- (bbdb-record-set-aka
- record (bbdb-split 'aka (widget-value my-bbdb-widget-aka)))
- (bbdb-record-set-phone
- record (mapcar
- (lambda (pair)
- (vector (car pair) (cadr pair)))
- (widget-value my-bbdb-widget-phone)))
- (bbdb-change-record record)
- (bbdb-display-records (list record) nil nil t))
- "Submit"))
- (use-local-map widget-keymap)
- (widget-setup)
- (goto-char (point-min)))
-
-(defun my-bbdb-parse-record (record)
- (list
- (cons 'Name (bbdb-record-name record))
- (cons 'First-name (bbdb-record-firstname record))
- (cons 'Last-name (bbdb-record-lastname record))
- (cons 'Organisation (car (bbdb-record-organization record)))
- (cons 'Notes (bbdb-record-xfield record 'notes))
- (cons 'Website (bbdb-record-xfield record 'url))))
-
-(defun my-bbdb-insert-record-to-org (parsed)
- (goto-char (point-min))
- (insert "\n* "(alist-get 'Name parsed))
- (insert "\n" (or
- (and (alist-get 'Notes parsed)
- (format "- %s" (alist-get 'Notes parsed)))
- ""))
- (dolist (pair parsed)
- (when (and (not (member (car pair) '(Name Notes))) (cdr pair))
- (org-set-property (symbol-name (car pair)) (cdr pair)))))
-
-(defun my--bbdb-to-org ()
- "ONLY do this in a new buffer!"
- (dolist (record (bbdb-records))
- (my-bbdb-insert-record-to-org (my-bbdb-parse-record record))))
-
-(defun my-bbdb-done ()
- "Save and quit bbdb window"
- (interactive)
- (bbdb-save) (quit-window))
-
-(defun my-bbdb-all ()
- "Dispaly all bbdb records"
- (interactive)
- (bbdb ""))
-
-(provide 'my-bbdb)
-;;; my-bbdb.el ends here
diff --git a/.emacs.d/lisp/my/my-buffer.el b/.emacs.d/lisp/my/my-buffer.el
deleted file mode 100644
index 5ff09a7..0000000
--- a/.emacs.d/lisp/my/my-buffer.el
+++ /dev/null
@@ -1,448 +0,0 @@
-;;; my-buffer.el -- Buffers and windows related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Protesilaos Stavrou <info@protesilaos.com>
-;; Maintainer: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions on buffers and windows.
-
-;;; Code:
-
-;; Much of the following is from prot-emacs
-(defun my-get-major-mode-for-buffer (buffer)
- (buffer-local-value 'major-mode (get-buffer buffer)))
-
-;;; Copied from mastering emacs
-;;; https://www.masteringemacs.org/article/demystifying-emacs-window-manager
-(defun my-buffer-make-display-matcher (major-modes)
- (lambda (buffer-name action)
- (with-current-buffer buffer-name (apply #'derived-mode-p major-modes))))
-
-(defun my-get-buffer-modes ()
- (let ((results))
- (dolist (buffer (buffer-list) results)
- (add-to-list 'results (my-get-major-mode-for-buffer buffer)))))
-
-(defun my-switch-to-buffer-matching-major-mode (mode)
- (interactive
- (list (intern (completing-read "Major mode: "
- (mapcar 'prin1-to-string (my-get-buffer-modes))))))
- (switch-to-buffer
- (read-buffer "Switch to buffer: " nil t
- (lambda (pair)
- (with-current-buffer (cdr pair)
- (derived-mode-p mode))))))
-
-(defun my--buffer-major-mode-prompt ()
- "Prompt of `my-buffers-major-mode'."
- (let ((major major-mode)
- (read-buffer-function nil))
- (read-buffer
- (format "Buffer for %s: " major)
- nil t
- (lambda (pair) ; pair is (name-string . buffer-object)
- (with-current-buffer (cdr pair) (derived-mode-p major))))))
-
-;;;###autoload
-(defun my-buffers-major-mode (&optional arg)
- "Select BUFFER matching the current one's major mode.
-
-With a prefix-arg, prompt for major mode."
- (interactive "P")
- (if arg
- (call-interactively 'my-switch-to-buffer-matching-major-mode)
- (switch-to-buffer (my--buffer-major-mode-prompt))))
-
-(defun my-buffer-quick-major-mode (mode)
- "Switch to the first buffer of a given mode."
- (let ((buffers (buffer-list)))
- (while (and buffers
- (with-current-buffer (car buffers)
- (not (derived-mode-p mode))))
- (setq buffers (cdr buffers)))
- (if buffers
- (pop-to-buffer (car buffers))
- (message "No buffers in %S" mode))))
-
-(defun my-buffer-switch-or-create-major-mode (mode)
- "Switch to or create a buffer with a chosen major mode.
-
-Prompt for a major mode, then:
-With no prefix: switch to the first buffer of the chosen major mode.
-With one prefix: prompt for a buffer of the chosen major mode.
-With two prefixes: create a buffer of the chosen major mode."
- (interactive (list (my-read-major-mode)))
- (pcase (prefix-numeric-value current-prefix-arg)
- (16 (my-buffer-create-major-mode mode))
- (4 (my-switch-to-buffer-matching-major-mode (print mode)))
- (_ (my-buffer-quick-major-mode mode))))
-
-(defvar my-buffer-create-functions nil
- "List indicating ways to create new buffer for a function, each
- element in the form of (major-mode-name
- . buffer-create-function). without specifying, the default
- buffer-create-function is `my-buffer-create-scratch'.")
-
-(defun my-read-major-mode ()
- (intern
- (completing-read
- "Major mode: "
- (cl-loop for sym symbols of obarray
- when (and (functionp sym)
- ;; we would like to include all modes
- (provided-mode-derived-p
- sym
- 'text-mode 'prog-mode
- 'comint-mode 'special-mode))
- collect sym))))
-
-(defun my-buffer-create-major-mode (mode)
- (if (alist-get mode my-buffer-create-functions)
- (call-interactively (alist-get mode my-buffer-create-functions))
- (my-buffer-scratch-setup "" mode)))
-
-(defun my-buffer-create-same-mode (&optional arg)
- (interactive "P")
- (let ((mode (if arg
- (my-read-major-mode)
- major-mode)))
- (my-buffer-create-major-mode mode)))
-
-(defvar my-buffers-same-mode nil
- "Buffers of the same mode for cycling")
-
-(defun my-buffer-with-same-major-mode-p (other-buffer)
- (let ((mode major-mode))
- (with-current-buffer other-buffer
- (derived-mode-p mode))))
-
-(defun my-buffer-cycle-same-mode ()
- (interactive)
- (unless (and (eq last-command 'my-buffer-create-or-cycle-same-mode)
- (= 1 (prefix-numeric-value last-prefix-arg)))
- (setq my-buffers-same-mode
- (seq-filter 'my-buffer-with-same-major-mode-p (buffer-list))))
- (setq my-buffers-same-mode
- (my-list-cycle my-buffers-same-mode))
- (switch-to-buffer (car my-buffers-same-mode)))
-
-(defun my-buffer-create-or-cycle-same-mode (&optional arg)
- "Create or switch to a buffer of the same major mode
-
-No prefix: cycle
-One prefix: switch to buffer with prompt by calling `my-buffers-major-mode'
-Two prefixes: create a buffer by calling `my-buffer-create-same-mode'
-"
- (interactive "P")
- (pcase (prefix-numeric-value arg)
- (16 (my-buffer-create-same-mode))
- (4 (my-buffers-major-mode))
- (_ (my-buffer-cycle-same-mode))))
-
-(defun my-copy-buffer-file-name ()
- (interactive)
- (when buffer-file-name)
- (kill-new (abbreviate-file-name buffer-file-name))
- (message "Copied %s" (abbreviate-file-name buffer-file-name)))
-
-;;;###autoload
-(defun my-kill-buffer (&optional arg)
- "Kill current buffer.
-With optional prefix ARG (\\[universal-argument]) choose which
-buffer to kill."
- (interactive "P")
- (let ((kill-buffer-query-functions nil))
- (if arg
- (call-interactively 'kill-buffer)
- (kill-buffer))))
-
-;;;###autoload
-(defun my-rename-file-and-buffer (name)
- "Apply NAME to current file and rename its buffer.
-Do not try to make a new directory or anything fancy."
- (interactive
- (list (read-file-name "Rename current file: " (buffer-file-name))))
- (let ((file (buffer-file-name)))
- (if (vc-registered file)
- (vc-rename-file file name)
- (rename-file file name))
- (set-visited-file-name name t t)))
-
-(defun my--buffer-vc-root-prompt ()
- "Prompt of `my-buffers-vc-root'."
- (let ((root (expand-file-name
- (or (vc-root-dir)
- (locate-dominating-file "." ".git"))))
- (read-buffer-function nil))
- (read-buffer
- (format "Buffers in %s: " root)
- nil t
- (lambda (pair) ; pair is (name-string . buffer-object)
- (with-current-buffer (cdr pair)
- (string-match-p root default-directory))))))
-
-;;; from prot-emacs
-;;;###autoload
-(defun my-buffers-vc-root ()
- "Select buffer matching the current one's VC root."
- (interactive)
- (switch-to-buffer (my--buffer-vc-root-prompt)))
-
-(defun my-bookmark-save-no-prompt (&rest _)
- "Run `bookmark-save' without prompts.
-
-The intent of this function is to be added as an :after advice to
-`bookmark-set-internal'. Concretely, this means that when
-`bookmark-set-internal' is called, this function is called right
-afterwards. We set this up because there is no hook after
-setting a bookmark and we want to automatically save bookmarks at
-that point."
- (funcall 'bookmark-save))
-
-(defun my-cycle-windows ()
- "Cycle all windows."
- (interactive)
- (let* ((windows (window-list nil 0))
- (first-window (pop windows))
- (buffer (window-buffer first-window))
- (temp-buffer)
- (window))
- (when windows (select-window (car windows)))
- (dolist (window windows)
- (setq temp-buffer (window-buffer window))
- (set-window-buffer window buffer)
- (setq buffer temp-buffer))
- (set-window-buffer first-window buffer)))
-
-(defun my-focus-write ()
- "Make the current window the only one centered with width 80."
- (interactive)
- (delete-other-windows)
- (let ((margin (/ (- (window-width) 80) 2)))
- (set-window-margins nil margin margin)))
-
-(defun my-select-new-window-matching-mode (mode)
- "Select a new window."
- (setq available-windows
- (delete (selected-window) (window-list)))
- (setq new-window
- (or (cl-find-if (lambda (window)
- (equal (my-get-major-mode-for-buffer
- (window-buffer window))
- mode))
- available-windows)
- (car available-windows)
- (split-window-sensibly)
- (split-window-right)))
- (select-window new-window))
-
-(defun my-toggle-lock-current-window-to-buffer ()
- (interactive)
- (my-toggle-lock-window-to-buffer (selected-window)))
-
-(defun my-toggle-lock-window-to-buffer (window)
- (if (window-dedicated-p window)
- (progn (set-window-dedicated-p window nil)
- (message "Window unlocked."))
- (set-window-dedicated-p window t)
- (message "Window locked.")))
-
-;; https://lists.gnu.org/archive/html/help-gnu-emacs/2010-01/msg00058.html
-(defun my-increase-default-face-height (&optional steps)
- "Increase the height of the default face by STEPS steps.
- Each step multiplies the height by 1.2; a negative number of steps
- decreases the height by the same amount."
- (interactive
- (list
- (cond ((eq current-prefix-arg '-) -1)
- ((numberp current-prefix-arg) current-prefix-arg)
- ((consp current-prefix-arg) -1)
- (t 1))))
- (let ((frame (selected-frame)))
- (set-face-attribute 'default frame
- :height (floor
- (* (face-attribute 'default :height frame)
- (expt 1.05 steps))))))
-
-(defun my-decrease-default-face-height (&optional steps)
- "Decrease the height of the default face by STEPS steps.
- Each step divides the height by 1.2; a negative number of steps
- increases the height by the same amount."
- (interactive
- (list
- (cond ((eq current-prefix-arg '-) -1)
- ((numberp current-prefix-arg) current-prefix-arg)
- ((consp current-prefix-arg) -1)
- (t 1))))
- (my-increase-default-face-height (- steps)))
-
-;; if file link points to the same file, do not open in other window
-(defun my-find-file-maybe-other-window (filename)
- (if (equal buffer-file-name (expand-file-name filename))
- (find-file filename)
- (find-file-other-window filename)))
-
-(defun my-buffer-empty-p ()
- "Test whether the buffer is empty."
- (or (= (point-min) (point-max))
- (save-excursion
- (goto-char (point-min))
- (while (and (looking-at "^\\([a-zA-Z]+: ?\\)?$")
- (zerop (forward-line 1))))
- (eobp))))
-
-;;;; Scratch buffers
-;; The idea is based on the `scratch.el' package by Ian Eure:
-;; <https://github.com/ieure/scratch-el>.
-
-(defun my-buffer-scratch-list-modes ()
- "List known major modes."
- (cl-loop for sym symbols of obarray
- when (and (functionp sym)
- (or (provided-mode-derived-p sym 'text-mode)
- (provided-mode-derived-p sym 'prog-mode)))
- collect sym))
-
-(defun my-buffer-scratch-setup (region &optional mode)
- "Add contents to `scratch' buffer and name it accordingly.
-
-REGION is added to the contents to the new buffer.
-
-Use the current buffer's major mode by default. With optional
-MODE use that major mode instead."
- (unless (provided-mode-derived-p mode 'text-mode 'prog-mode)
- (error "Cannot create a scratch with %s which is not derived from
-text- or prog-mode." mode))
- (let* ((major (or mode major-mode))
- (string (format "Scratch buffer for: %s\n\n" major))
- (text (concat string region))
- (buf (format "*%s scratch*" major)))
- (with-current-buffer (pop-to-buffer buf)
- (funcall major)
- (if (my-buffer-empty-p)
- ;; We could use `save-restriction' for narrowed buffers, but
- ;; it is overkill.
- (progn
- (insert text)
- (goto-char (point-min))
- (comment-region (line-beginning-position) (line-end-position))
- (goto-char (point-max)))
- (goto-char (point-max))
- (when (my-line-regexp-p 'non-empty)
- (insert "\n\n"))
- (insert region)))))
-
-;;;###autoload
-(defun my-buffer-create-scratch (&optional arg)
- "Produce a scratch buffer matching the current major mode.
-
-With optional ARG as a prefix argument (\\[universal-argument]),
-use `my-scratch-buffer-default-mode'.
-
-With ARG as a double prefix argument, prompt for a major mode
-with completion. Candidates are derivatives of `text-mode' or
-`prog-mode'.
-
-If region is active, copy its contents to the new scratch
-buffer.
-
-Buffers are named as *MAJOR-MODE scratch*. If one already exists
-for the given MAJOR-MODE, any text is appended to it."
- (interactive "P")
- (let* ((default-mode my-scratch-buffer-default-mode)
- (modes (my-buffer-scratch-list-modes))
- (region (with-current-buffer (current-buffer)
- (if (region-active-p)
- (buffer-substring-no-properties
- (region-beginning)
- (region-end))
- "")))
- mode)
- (pcase (prefix-numeric-value arg)
- (16 (progn
- (setq mode (intern (completing-read "Select major mode: " modes nil t)))
- (my-buffer-scratch-setup region mode)))
- (4 (my-buffer-scratch-setup region default-mode))
- (_ (my-buffer-scratch-setup region)))))
-
-(defcustom my-scratch-buffer-default-mode 'org-mode
- "Default major mode for `my-buffer-create-scratch'."
- :type 'symbol
- :group 'my)
-
-(defun my-base-buffer (&optional buffer)
- "Get the base buffer of BUFFER."
- (setq buffer (or buffer (current-buffer)))
- (unless (bufferp buffer) (error "Not a buffer."))
- (or (buffer-base-buffer buffer) buffer))
-
-(defun my-buffer-with-same-base-p (other-buffer &optional buffer)
- "Test that buffer has the same base buffer as the current buffer."
- (equal (my-base-buffer other-buffer)
- (my-base-buffer buffer)))
-
-(defun my-switch-indirect-buffer ()
- (interactive)
- (let* ((current (current-buffer))
- (buffer
- (read-buffer "Switch to indirect buffer: " nil t
- (lambda (buffer)
- (and
- (my-buffer-with-same-base-p
- (cdr buffer) current)
- (not (equal (cdr buffer) current)))))))
- (switch-to-buffer buffer)))
-
-(defun my-list-cycle (xs)
- "Cycle a list."
- (cdr (append xs (list (car xs)))))
-
-(defvar my-indirect-buffer-list nil)
-
-(defun my-cycle-indirect-buffer ()
- (interactive)
- (unless (and (eq last-command 'my-create-or-switch-indirect-buffers)
- (= 1 (prefix-numeric-value last-prefix-arg)))
- (setq my-indirect-buffer-list
- (seq-filter 'my-buffer-with-same-base-p (buffer-list))))
- (setq my-indirect-buffer-list
- (my-list-cycle my-indirect-buffer-list))
- (switch-to-buffer (car my-indirect-buffer-list)))
-
-(defun my-create-or-switch-indirect-buffers (arg)
- "Create or switch to an indirect buffer of the current buffer.
-
-With no prefix, cycle through indirect buffers.
-
-With optional ARG as a prefix argument (\\[universal-argument]),
-prompt for indirect buffer to choose from.
-
-With double prefix arguments, create a new indirect buffer."
- (interactive "P")
- (pcase (prefix-numeric-value arg)
- (16 (clone-indirect-buffer nil t))
- (4 (my-switch-indirect-buffer))
- (_ (my-cycle-indirect-buffer))))
-
-(provide 'my-buffer)
-;;; my-buffer.el ends here
diff --git a/.emacs.d/lisp/my/my-calibre.el b/.emacs.d/lisp/my/my-calibre.el
deleted file mode 100644
index e12028b..0000000
--- a/.emacs.d/lisp/my/my-calibre.el
+++ /dev/null
@@ -1,83 +0,0 @@
-;;; my-calibre.el -- Calibre client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it
-;; under the terms of the GNU Affero General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-
-;; dotfiles 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
-;; Affero General Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Calibre client.
-
-;;; Code:
-
-
-(defun org-attach-calibre-book (id)
- "Attach a calibre book with ID to the current org entry."
- (interactive "sCalibre book id: ")
- (let ((export-dir (org-attach-dir t)
- ))
- (call-process-shell-command
- (format "mkdir -p %s && calibredb export --dont-asciiize \\
- --replace-whitespace --single-dir --to-dir %s %s" export-dir export-dir id)
- nil "*calibredb*")
- (org-attach-sync)))
-
-;; the following should be adapted to a capture so that one can fix anything
-;; erroneous before refiling and attaching
-;; fixme: the following should be decoupled from org maybe
-(defun create-calibre-book-node (id)
- (interactive "sCalibre book ID: ")
- ;; 1. get book metadata from calibredb
- ;; 1.1. run calibredb to get metadata
- (ignore-errors (kill-buffer "*calibredb*"))
- (if (= 0
- (call-process-shell-command
- (concat "calibredb show_metadata " id) nil "*calibredb*"))
- ;; 1.2. parse the metadata to get author, title and year
- (let ((book-info (my-parse-colon-separated-output "*calibredb*")))
- ;; 2. create the node and attach it under books and papers
- ;; 2.1 create a new node
- (kill-buffer "*calibredb*")
- (org-capture nil "book")
- (insert (format
- "%s - %s - [%s]"
- (let ((full-author (alist-get "Authors" book-info nil nil 'string=)))
- ;; (pp book-info)
- (substring full-author
- (1+ (string-match "\\[.*\\]" full-author))
- (1- (match-end 0))))
- (alist-get "Title" book-info nil nil 'string=)
- (substring (alist-get "Published" book-info nil nil 'string=) 0 10)))
- ;; 2.2 use org-entry-put to add all the properties
- (dolist (pair book-info)
- (org-entry-put (point-min) (car pair) (cdr pair)))
- (attach-calibre-book id))
- (error (format "Cannot find book %s!" id))))
-
-(defun my-calibredb-search (query)
- (interactive "scalibredb search query: ")
- (ignore-errors (kill-buffer "*calibredb*"))
- (call-process-shell-command
- (format "calibredb search %s | xargs -d, -i sh -c 'echo ID: {} && calibredb show_metadata {}'" query)
- nil "*calibredb*")
- (switch-to-buffer "*calibredb*"))
-
-(provide 'my-calibre)
-;;; my-calibre.el ends here
diff --git a/.emacs.d/lisp/my/my-complete.el b/.emacs.d/lisp/my/my-complete.el
deleted file mode 100644
index 61ee31a..0000000
--- a/.emacs.d/lisp/my/my-complete.el
+++ /dev/null
@@ -1,56 +0,0 @@
-;;; my-complete.el -- Completion related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Completion related extensions for emacs core. Covering minibuffer,
-;; icomplete, recentf etc.
-
-;;; Code:
-
-
-;;; icomplete
-;; FIXME: do we still need these?
-(defun my-icomplete-vertical-forward-page ()
- "Forward page in icomplete."
- (interactive)
- (dotimes (_ (1- (window-total-height))) (icomplete-forward-completions)))
-
-(defun my-icomplete-vertical-backward-page ()
- "Backward page in icomplete."
- (interactive)
- (dotimes (_ (1- (window-total-height))) (icomplete-backward-completions)))
-
-;;; recentf
-(defun my-recentf-save-list-silently ()
- (interactive)
- (let ((inhibit-message t))
- (recentf-save-list)))
-
-(defun my-recentf-add-all-open-buffers ()
- (interactive)
- (dolist (buffer (buffer-list))
- (when-let ((filename (buffer-file-name buffer)))
- (recentf-add-file filename))))
-
-(provide 'my-complete)
-;;; my-complete.el ends here
diff --git a/.emacs.d/lisp/my/my-consult.el b/.emacs.d/lisp/my/my-consult.el
deleted file mode 100644
index bf3e385..0000000
--- a/.emacs.d/lisp/my/my-consult.el
+++ /dev/null
@@ -1,35 +0,0 @@
-;;; my-consult.el -- Extensions for consult -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for consult.
-
-;;; Code:
-
-(defun my-consult-grep-default ()
- "Like `consult-grep', but grepping the default directory."
- (interactive)
- (consult-grep default-directory nil))
-
-(provide 'my-consult)
-;;; my-consult.el ends here
diff --git a/.emacs.d/lisp/my/my-corfu.el b/.emacs.d/lisp/my/my-corfu.el
deleted file mode 100644
index 191f513..0000000
--- a/.emacs.d/lisp/my/my-corfu.el
+++ /dev/null
@@ -1,39 +0,0 @@
-;;; my-corfu.el -- Extensions for corfu -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Protesilaos Stavrou <info@protesilaos.com>
-;; Maintainer: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for corfu.
-
-;;; Code:
-
-;; Adapted from Corfu's manual.
-(defun my-corfu-enable-always-in-minibuffer ()
- "Enable Corfu in the minibuffer if icomplete is not active.
-Useful for prompts such as `eval-expression' and `shell-command'."
- (unless (bound-and-true-p icomplete--initial-input)
- (corfu-mode 1)))
-
-(provide 'my-corfu)
-;;; my-corfu.el ends here
diff --git a/.emacs.d/lisp/my/my-detached.el b/.emacs.d/lisp/my/my-detached.el
deleted file mode 100644
index 39d3085..0000000
--- a/.emacs.d/lisp/my/my-detached.el
+++ /dev/null
@@ -1,40 +0,0 @@
-;;; my-detached.el -- Extensions for detached -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for detached.
-
-;;; Code:
-
-
-(require 'detached)
-
-(defun my-execute-external-command (command)
- (interactive
- (list
- (completing-read
- "External command: " (my-external-command-collection))))
- (detached-shell-command command))
-
-(provide 'my-detached)
-;;; my-detached.el ends here
diff --git a/.emacs.d/lisp/my/my-dired.el b/.emacs.d/lisp/my/my-dired.el
deleted file mode 100644
index 21240e1..0000000
--- a/.emacs.d/lisp/my/my-dired.el
+++ /dev/null
@@ -1,109 +0,0 @@
-;;; my-dired.el -- Extension for dired -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extension for dired.
-
-;;; Code:
-
-
-(require 'my-utils)
-
-(defvar my-dired-reverse-sorting nil)
-
-(defun my-dired-find-or-alternate (arg)
- "Find if file, alternate find if dir.
-If prefix then xdg-open, dir or file."
- (interactive "P")
- (if arg (call-process "xdg-open" nil 0 nil (dired-get-filename nil t))
- (if (file-directory-p (dired-get-filename nil t))
- (dired-find-alternate-file)
- (dired-find-file))))
-
-(defun my-dired-do-rename-and-symlink-back (arg)
- (interactive "P")
- (dired-do-create-files 'move-and-symlink #'my-rename-and-symlink-back
- "Move and symlink back" arg dired-keep-marker-rename
- "Rename and symlink"))
-
-(defun my-dired-sort-by-size ()
- (interactive)
- (setq dired-actual-switches
- (concat dired-listing-switches " -S"
- (when my-dired-reverse-sorting "r")))
- (revert-buffer)
- (setq mode-name "Dired by size"))
-
-(defun my-dired-sort-by-time ()
- (interactive)
- (setq dired-actual-switches
- (concat dired-listing-switches " -t"
- (when my-dired-reverse-sorting "r")))
- (revert-buffer)
- (setq mode-name "Dired by time"))
-
-(defun my-dired-sort-by-extension ()
- (interactive)
- (setq dired-actual-switches
- ;; FIXME: reverse sorting not working
- (concat dired-listing-switches " -X"
- (when my-dired-reverse-sorting "r")))
- (revert-buffer)
- (setq mode-name "Dired by extension"))
-
-(defun my-dired-sort-by-name ()
- (interactive)
- (setq dired-actual-switches
- (concat dired-listing-switches
- (when my-dired-reverse-sorting " -r")))
- (revert-buffer)
- (setq mode-name "Dired by name"))
-
-(defun my-dired-toggle-sorting (arg)
- "Cycle dired sorting methods.
-
-With a prefix arg, toggle `my-dired-reverse-sorting' instead."
- (interactive "P")
- (if arg
- (progn
- (setq my-dired-reverse-sorting
- (not my-dired-reverse-sorting))
- (cond ((equal mode-name "Dired by name")
- (my-dired-sort-by-name))
- ((equal mode-name "Dired by time")
- (my-dired-sort-by-time))
- ((equal mode-name "Dired by size")
- (my-dired-sort-by-size))
- ((equal mode-name "Dired by extension")
- (my-dired-sort-by-extension))))
- (cond ((equal mode-name "Dired by name")
- (my-dired-sort-by-time))
- ((equal mode-name "Dired by time")
- (my-dired-sort-by-size))
- ((equal mode-name "Dired by size")
- (my-dired-sort-by-extension))
- ((equal mode-name "Dired by extension")
- (my-dired-sort-by-name)))))
-
-(provide 'my-dired)
-;;; my-dired.el ends here
diff --git a/.emacs.d/lisp/my/my-editing.el b/.emacs.d/lisp/my/my-editing.el
deleted file mode 100644
index bd3ca83..0000000
--- a/.emacs.d/lisp/my/my-editing.el
+++ /dev/null
@@ -1,340 +0,0 @@
-;;; my-editing.el -- Editing related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Protesilaos Stavrou <info@protesilaos.com>
-;; Stefan Monnier <monnier@iro.umontreal.ca>
-;; Maintainer: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Editing related extensions.
-
-;;; Code:
-
-
-
-;;; Some of the following functions are adapted from prot-dotfiles
-(defun my-comment-and-copy-selection ()
- (interactive)
- (comment-dwim nil)
- (my-yank-primary))
-
-(defun my-kill-region-if-active (beg end &optional region)
- (interactive (list (mark) (point) 'region))
- (when mark-active
- (kill-region beg end region)))
-
-;;; Stefan Monnier <foo at acm.org>. It is the opposite of fill-paragraph
-(defun my-unfill-paragraph (&optional region)
- "Takes a multi-line paragraph and makes it into a single line of text."
- (interactive (progn (barf-if-buffer-read-only) '(t)))
- (let ((fill-column (point-max))
- ;; This would override `fill-column' if it's an integer.
- (emacs-lisp-docstring-fill-column t))
- (fill-paragraph nil region)))
-
-;;; fixme: move to search
-(defun my-replace-leading-space (to-string begin end)
- (interactive (list (read-string "Replace leading whitespace by: ")
- (region-beginning) (region-end)))
- (save-excursion
- (goto-char begin)
- (while (re-search-forward "^\\ +" end t)
- (replace-match to-string))))
-
-(defun my-concat-lines (begin end)
- (interactive (list (region-beginning) (region-end)))
- (replace-regexp "\n" " " nil begin end))
-
-(defun my-save-without-formatting ()
- (interactive)
- (read-only-mode 1)
- (save-buffer)
- (read-only-mode -1))
-
-(defun my-yank-primary ()
- (interactive)
- (let ((primary (gui-get-primary-selection)))
- (push-mark)
- (insert-for-yank primary)))
-
-(defun my-beginning-of-line-or-indentation ()
- "Move to beginning of line, or indentation"
- (interactive)
- (if (bolp)
- (back-to-indentation)
- (beginning-of-line)))
-
-(defun my-copy-url-at-point ()
- (interactive)
- (when-let ((url (thing-at-point-url-at-point)))
- (kill-new url)
- (message "Copied: %s" (thing-at-point-url-at-point))))
-
-(defun my-backward-kill-path-component ()
- (interactive)
- (zap-up-to-char -1 ?/))
-
-(defun my-toggle-forward-word-viper-symbol ()
- (interactive)
- (require 'viper)
- (cond ((eq (lookup-key (current-global-map) "\M-f") 'forward-word)
- (progn
- (define-key global-map "\M-f" 'viper-forward-word)
- (define-key global-map "\M-b" 'viper-backward-word)
- (message "M-f is viper-forward-word")))
- ((eq (lookup-key (current-global-map) "\M-f") 'viper-forward-word)
- (progn
- (define-key global-map "\M-f" 'forward-symbol)
- (define-key global-map "\M-b"
- (lambda () (interactive)
- (forward-symbol -1)))
- (message "M-f is forward-symbol")))
- (t (progn
- (define-key global-map "\M-f" 'forward-word)
- (define-key global-map "\M-b" 'backward-word)
- (message "M-f is forward-word")))))
-
-(defun my-kill-line-backward ()
- "Kill from point to the beginning of the line."
- (interactive)
- (kill-line 0))
-
-(defun my--duplicate-buffer-substring (beg end &optional indent)
- "Duplicate buffer substring between BEG and END positions.
-With optional INDENT, run `indent-for-tab-command' after
-inserting the substring."
- (save-excursion
- (goto-char end)
- (insert (buffer-substring-no-properties beg end))
- (when indent
- (indent-for-tab-command))))
-
-;;;###autoload
-(defun my-copy-line-or-region (&optional duplicate)
- "Copy the current line or active region to the `kill-ring'.
-With optional DUPLICATE as a prefix argument, duplicate the
-current line or active region without adding it to the `kill-ring'."
- (interactive "P")
- (let* ((region (region-active-p))
- (beg (if region (region-beginning) (line-beginning-position)))
- (end (if region (region-end) (1+ (line-end-position))))
- (message (if region "region" "line")))
- (if duplicate
- (my--duplicate-buffer-substring beg end)
- (copy-region-as-kill beg end)
- (message "Copied current %s" message))))
-
-;;;###autoload
-(defun my-new-line-below (&optional arg)
- "Create an empty line below the current one.
-Move the point to the absolute beginning. Adapt indentation by
-passing optional prefix ARG (\\[universal-argument]). Also see
-`my-new-line-above'."
- (interactive "P")
- (end-of-line)
- (if arg
- (newline-and-indent)
- (newline)))
-
-;;;###autoload
-(defun my-new-line-above-or-below (&optional arg)
- "Create an empty line above the current one.
-Move the point to the absolute beginning. Open a new line below
-by passing optional prefix ARG (\\[universal-argument])."
- (interactive "P")
- (if arg
- (my-new-line-below)
- (if (or (bobp)
- (line-number-at-pos (point-min)))
- (progn
- (beginning-of-line)
- (newline)
- (forward-line -1))
- (forward-line -1)
- (my-new-line-below))))
-
-(defun my--pos-url-on-line (&optional char)
- "Return position of `my-url-regexp' on line or at CHAR."
- (save-excursion
- (goto-char (or char (line-beginning-position)))
- (re-search-forward my-url-regexp (line-end-position) :noerror)))
-
-;;;###autoload
-(defun my-escape-url-line (&optional char)
- "Escape all URLs or email addresses on the current line.
-By default, start operating from `line-beginning-position' to the
-end of the current line. With optional CHAR as a buffer
-position, operate from CHAR to the end of the line."
- (interactive)
- (when-let ((regexp-end (my--pos-url-on-line char)))
- (save-excursion
- (goto-char regexp-end)
- (unless (looking-at ">")
- (insert ">")
- (search-backward "\s")
- (forward-char 1)
- (insert "<")))
- (my-escape-url-line (1+ regexp-end))))
-
-;; Thanks to Bruno Boal for `my-escape-url-region'. I am
-;; just renaming it for consistency with the rest of prot-simple.el.
-;; Check Bruno's Emacs config: <https://github.com/BBoal/emacs-config>.
-
-;;;###autoload
-(defun my-escape-url-region (&optional beg end)
- "Apply `my-escape-url-line' on region lines between BEG and END."
- (interactive
- (if (region-active-p)
- (list (region-beginning) (region-end))
- (error "There is no region!")))
- (unless (> end beg)
- (cl-rotatef end beg))
- (save-excursion
- (goto-char beg)
- (setq beg (line-beginning-position))
- (while (<= beg end)
- (my-escape-url-line beg)
- (beginning-of-line 2)
- (setq beg (point)))))
-
-;;;###autoload
-(defun my-escape-url-dwim ()
- "Escape URL on the current line or lines implied by the active region.
-Call the commands `my-escape-url-line' and
-`my-escape-url-region' ."
- (interactive)
- (call-interactively
- (if (region-active-p)
- #'my-escape-url-region
- #'my-escape-url-line)))
-
-;; Got those numbers from `string-to-char'
-(defcustom my-insert-pair-alist
- '(("' Single quote" . (39 39)) ; ' '
- ("\" Double quotes" . (34 34)) ; " "
- ("` Elisp quote" . (96 39)) ; ` '
- ("‘ Single apostrophe" . (8216 8217)) ; ‘ ’
- ("“ Double apostrophes" . (8220 8221)) ; “ ”
- ("( Parentheses" . (40 41)) ; ( )
- ("{ Curly brackets" . (123 125)) ; { }
- ("[ Square brackets" . (91 93)) ; [ ]
- ("< Angled brackets" . (60 62)) ; < >
- ("« Εισαγωγικά Gr quote" . (171 187)) ; « »
- ("= Equals signs" . (61 61)) ; = =
- ("~ Tilde" . (126 126)) ; ~ ~
- ("* Asterisks" . (42 42)) ; * *
- ("/ Forward Slash" . (47 47)) ; / /
- ("_ underscores" . (95 95))) ; _ _
- "Alist of pairs for use with `my-insert-pair-completion'."
- :type 'alist
- :group 'my-editing)
-
-(defvar my--character-hist '()
- "History of inputs for `my-insert-pair-completion'.")
-
-(defun my--character-prompt (chars)
- "Helper of `my-insert-pair-completion' to read CHARS."
- (let ((def (car my--character-hist)))
- (completing-read
- (format "Select character [%s]: " def)
- chars nil t nil 'my--character-hist def)))
-
-;;;###autoload
-(defun my-insert-pair (pair &optional count)
- "Insert PAIR from `my-insert-pair-alist'.
-Operate on the symbol at point. If the region is active, use it
-instead.
-
-With optional COUNT (either as a natural number from Lisp or a
-universal prefix argument (\\[universal-argument]) when used
-interactively) prompt for the number of delimiters to insert."
- (interactive
- (list
- (my--character-prompt my-insert-pair-alist)
- current-prefix-arg))
- (let* ((data my-insert-pair-alist)
- (left (cadr (assoc pair data)))
- (right (caddr (assoc pair data)))
- (n (cond
- ((and count (natnump count))
- count)
- (count
- (read-number "How many delimiters?" 2))
- (1)))
- (beg)
- (end)
- (forward))
- (cond
- ((region-active-p)
- (setq beg (region-beginning)
- end (region-end)))
- ((when (thing-at-point 'symbol)
- (let ((bounds (bounds-of-thing-at-point 'symbol)))
- (setq beg (car bounds)
- end (cdr bounds)))))
- (t (setq beg (point)
- end (point)
- forward t)))
- (save-excursion
- (goto-char end)
- (dotimes (_ n)
- (insert right))
- (goto-char beg)
- (dotimes (_ n)
- (insert left)))
- (when forward (forward-char n))))
-
-;;;###autoload
-(defun my-delete-pair-dwim ()
- "Delete pair following or preceding point.
-For Emacs version 28 or higher, the feedback's delay is
-controlled by `delete-pair-blink-delay'."
- (interactive)
- (if (eq (point) (cdr (bounds-of-thing-at-point 'sexp)))
- (delete-pair -1)
- (delete-pair 1)))
-
-;;;###autoload
-(defun my-zap-back-to-char (char &optional arg)
- "Backward `zap-to-char' for CHAR.
-Optional ARG is a numeric prefix to match ARGth occurance of
-CHAR."
- (interactive
- (list
- (read-char-from-minibuffer "Zap to char: " nil 'read-char-history)
- (prefix-numeric-value current-prefix-arg)))
- (zap-to-char (- arg) char))
-
-(defun my-transpose-lines ()
- "Same as `transpose-lines' but move point to the original position
-
-Basically move the line up
-"
- (interactive)
- (let ((line (current-line))
- (col (current-column)))
- (call-interactively 'transpose-lines)
- (goto-line line)
- (forward-char col)))
-
-(provide 'my-editing)
-;;; my-editing.el ends here
diff --git a/.emacs.d/lisp/my/my-emms.el b/.emacs.d/lisp/my/my-emms.el
deleted file mode 100644
index dadbb55..0000000
--- a/.emacs.d/lisp/my/my-emms.el
+++ /dev/null
@@ -1,454 +0,0 @@
-;;; my-emms.el -- Extensions for emms -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for emms.
-
-;;; Code:
-
-
-
-;;; emms
-(require 'emms-playlist-mode)
-(require 'my-buffer)
-(defun my-emms-switch-to-playlist-buffer ()
- (interactive)
- (my-switch-to-buffer-matching-major-mode 'emms-playlist-mode))
-
-(require 'emms-player-mpv)
-(defun my-emms-mpv-toggle-video ()
- (interactive)
- (if (member "--no-video" emms-player-mpv-parameters)
- (progn
- (setq emms-player-mpv-parameters
- (remove "--no-video" emms-player-mpv-parameters))
- (message "emms: video enabled!"))
- (setq emms-player-mpv-parameters
- (nconc emms-player-mpv-parameters '("--no-video")))
- (message "emms: video disabled!")))
-
-(require 'emms)
-(defun my-emms-mpv-toggle-torsocks ()
- (interactive)
- (emms-pause)
- (if (string= "torsocks" emms-player-mpv-command-name)
- (progn
- (setq emms-player-mpv-command-name (pop emms-player-mpv-parameters))
- (message "Will run mpv without torsocks. Please restart mpv."))
- (push emms-player-mpv-command-name emms-player-mpv-parameters)
- (setq emms-player-mpv-command-name "torsocks")
- (message "Will run mpv with torsocks. Please restart mpv")))
-
-;;; do we need this? doesn't emms already have something like this?
-(defmacro my-with-current-buffer-as-current-emms-playlist (&rest body)
- "Run BODY with the current playlist buffer being the current buffer."
- `(let ((saved-buffer emms-playlist-buffer))
- (my-emms-playlist-mode-make-current)
- ,@body
- (emms-playlist-set-playlist-buffer saved-buffer)))
-
-(defun my-emms-playlist-save-current-buffer ()
- (interactive)
- (when (equal major-mode 'emms-playlist-mode)
- (my-with-current-buffer-as-current-emms-playlist
- (call-interactively 'emms-playlist-save))))
-
-(defun my-emms-maybe-seek-to-last-played ()
- (when-let ((last-playing-time
- (emms-track-get (emms-playlist-current-selected-track)
- 'playing-time)))
- (emms-seek-to last-playing-time)))
-
-;;; do we need this?
-(defun my-emms-playlist-mode-make-current ()
- "make the current playlist buffer current"
- (interactive)
- (when (equal major-mode 'emms-playlist-mode)
- (emms-playlist-set-playlist-buffer (current-buffer))
- (when (called-interactively-p 'interactive)
- (message "%s is the current playlist buffer."
- emms-playlist-buffer))))
-
-;; mode line and playing time go together
-(defun my-emms-mode-line-enable ()
- (interactive)
- (emms-mode-line-mode 1)
- (emms-playing-time-enable-display))
-
-(defun my-emms-mode-line-disable ()
- (interactive)
- (emms-mode-line-mode -1)
- (emms-playing-time-disable-display))
-
-(defun my-emms-mode-line-toggle ()
- (interactive)
- (emms-mode-line-mode 'toggle)
- (emms-playing-time-display-mode 'toggle))
-
-(defvar my-emms-native-playlists
- (directory-files emms-source-file-default-directory t "\\.native$"))
-
-(defun my-emms-playlist-make-buffer-name (playlist)
- "Make an emms buffer name from a playlist file name."
- (concat "emms-" (file-name-base playlist)))
-
-(defun my-emms-load-from-native (playlist &optional buffer-name)
- "Creates an emms playlist buffer with BUFFER-NAME from a native PLAYLIST."
- (unless buffer-name (setq buffer-name (my-emms-playlist-make-buffer-name playlist)))
- (let ((saved-buffer emms-playlist-buffer))
- (with-current-buffer
- (or (get-buffer buffer-name)
- (emms-playlist-new buffer-name))
- (my-emms-playlist-mode-make-current)
- (emms-playlist-clear)
- (emms-add-native-playlist playlist)
- (message (format "%s loaded in buffer %s!"
- playlist buffer-name)))
- (and saved-buffer (emms-playlist-set-playlist-buffer saved-buffer))))
-
-(defun my-emms-add-all ()
- (interactive)
- (mapc 'my-emms-load-from-native my-emms-native-playlists)
- (emms-metaplaylist-mode-go))
-
-(defun my-emms-deduplicate ()
- (interactive)
- (emms-mark-regexp ".* ([0-9])\\.[a-zA-Z0-9]+" nil)
- (emms-mark-delete-marked-tracks))
-
-(defun my-emms-reload (from to type)
- "Reload playlist buffer TO from files of url lists
-
-The content of a file in FROM is a list of urls. TYPE is
-either 'audio or 'video
-"
- (interactive)
- (when (memq (get-buffer to) emms-playlist-buffers)
- (emms-playlist-set-playlist-buffer to)
- (with-current-buffer to (emms-playlist-clear))
- (let ((emms-track-initialize-functions nil))
- (my-emms-add-url-lists from
- (alist-get type my-extension-types)))
- (with-current-buffer to (emms-sort))))
-
-(defvar my-emms-playlist-alist nil
- "alist controlling playlists, where the cdr of each item is an also an alist,
-with possible keys 'source and 'type.
-'source is a list of files of url lists.
-'type is one of 'audio, 'video, or 'audiovideo")
-
-(defun my-emms-playlist-reload-current ()
- "Reload the current playlist using info from `my-emms-playlist-alist'"
- (interactive)
- (let* ((name (buffer-name emms-playlist-buffer))
- (info (alist-get name my-emms-playlist-alist nil nil #'equal)))
- (my-emms-reload (alist-get 'source info) name (alist-get 'type info))))
-
-(defun my-emms-save-all ()
- (interactive)
- (let ((saved-buffer emms-playlist-buffer)
- (saved-overwrite emms-source-playlist-ask-before-overwrite))
- (setq emms-source-playlist-ask-before-overwrite nil)
- (dolist (pair my-emms-native-playlists)
- (let ((file (car pair))
- (buffer (cadr pair)))
- (when (get-buffer buffer)
- (with-current-buffer buffer
- (my-emms-playlist-mode-make-current)
- (emms-playlist-save 'native file)))))
- (emms-playlist-set-playlist-buffer saved-buffer)
- (setq emms-source-playlist-ask-before-overwrite saved-overwrite)))
-
-(defun my-emms-add-process-output-url (process output)
- "A process filter extracting url from a jq output."
- (let ((left (string-match "\".*\"" output)))
- (emms-add-url (substring output (1+ left) (1- (match-end 0))))))
-
-(defun my-emms-add-ytdl-playlist (url buffer-name)
- "Adds all videos on a web playlist from URL using ytdl.
-
-URL could be link to a playlist, a playlist id, videos of a channel, or a
- list of playlists on a channel
-"
- (interactive "syoutube-dl playlist url: \nsemms buffer name: ")
- (unless (get-buffer buffer-name)
- (emms-playlist-new buffer-name))
- (emms-playlist-set-playlist-buffer buffer-name)
- (set-process-filter
- (start-process-shell-command
- "ytdl-emms" nil
- (format "yt-dlp -j %s | jq '.webpage_url'" url))
- 'my-emms-add-process-output-url))
-
-(defvar my-ytdl-supported-domains
- '("youtu.be" "youtube.com" "yewtu.be" "framatube.org" "pbs.org" "v.redd.it"
- "soundcloud.com"))
-
-(defvar my-ytdl-supported-domains-re
- (string-join my-ytdl-supported-domains "\\|"))
-
-(defvar my-emms-incoming-playlists
- '((audio . "emms-incoming-audios")
- (video . "emms-incoming-videos")
- (nil . "emms-incoming"))
- "EMMS playlists to insert incoming items.")
-
-(defun my-emms-enqueue-buffer-ytdl-incoming (media-type)
- (let ((current-emms-buffer emms-playlist-buffer)
- (links (link-gopher-get-all-links-in-buffer my-ytdl-supported-domains-re)))
- (with-current-buffer (alist-get media-type my-emms-incoming-playlists)
- (my-emms-playlist-mode-make-current)
- (dolist (url links)
- (emms-add-url url)))
- (with-current-buffer current-emms-buffer
- (my-emms-playlist-mode-make-current))))
-
-(defun my-emms-playlist-set-info-title-at-point (title)
- (when (equal major-mode 'emms-playlist-mode)
- (let ((track (get-text-property (point) 'emms-track)))
- (emms-track-set track 'info-title title))))
-
-(defun my-emms-add-url-region (from to &optional filter-exts)
- "Adds a list of urls to emms separated by newlines.
-
-filter extensions from filter-exts."
- (interactive (list (region-beginning) (region-end)))
- (mapc 'emms-add-url
- (seq-filter
- (lambda (s) (and
- (not (equal s ""))
- (or (not filter-exts)
- (member
- (when (string-match "^.*\\.\\(.*\\)$" s)
- (match-string 1 s))
- filter-exts))))
- (split-string
- (buffer-substring-no-properties from to) "
-"))))
-
-(defun my-emms-add-url-list (file)
- (interactive (list (read-file-name "Add url list from file: ")))
- (with-temp-buffer
- (let ((coding-system-for-read 'utf-8))
- (find-file file))
- (my-emms-add-url-region (point-min) (point-max))))
-
-(defun my-emms-add-url-lists (files &optional filter-exts)
- (with-temp-buffer
- (let ((coding-system-for-read 'utf-8))
- (mapc 'insert-file-contents (reverse files)))
- (my-emms-add-url-region (point-min) (point-max) filter-exts)))
-
-(defun my-emms-ytdl-current-buffer-command ()
- (interactive)
- (let ((results))
- (save-excursion
- (goto-char (point-min))
- (while (not (eobp))
- (push (format "'%s'" (alist-get 'name (emms-playlist-track-at (point))))
- results)
- (beginning-of-line 2)))
- (kill-new (concat "torsocks yt-dlp -w -x -o \"%(title)s.%(ext)s\" "
- (string-join (reverse results) " ")))
- (message "Copied yt-dlp command of downloading %d urls to the kill ring"
- (length results))))
-
-;; TODO: use emms-playlist-current-selected-track instead
-(defun my-emms-get-current-track ()
- (with-current-buffer emms-playlist-buffer
- (emms-playlist-mode-center-current)
- (emms-playlist-track-at (point))))
-
-(defvar my-emms-i3bar-file (locate-user-emacs-file "emms-i3bar")
- "File to write current playing to which i3bar reads")
-(defun my-emms-get-display-name (track)
- (or (alist-get 'info-title track)
- (when-let ((name
- (alist-get 'name track)))
- (replace-regexp-in-string "^\\(.*/\\)\\(.*/.*/.*\\)" "\\2" name))))
-(defun my-emms-output-current-track-to-i3bar-file ()
- (let ((current-track
- (my-emms-get-display-name (emms-playlist-current-selected-track))))
- (with-temp-buffer
- (when current-track (insert current-track))
- (let ((inhibit-message t))
- (write-file my-emms-i3bar-file)))))
-(defun my-emms-output-current-track-to-i3bar-file-no-error ()
- (ignore-error (my-emms-output-current-track-to-i3bar-file)))
-
-(defun my-emms-get-current-track-name ()
- (emms-track-get (my-emms-get-current-track) 'name))
-
-(defun my-emms-print-current-track-display-name ()
- (interactive)
- (with-current-buffer emms-playlist-buffer
- (emms-playlist-mode-center-current)
- (message (my-get-current-line-no-properties))))
-
-(defun my-emms-print-current-track-name ()
- (interactive)
- (message
- (concat "current track: "
- (my-emms-get-current-track-name))))
-
-(defun my-emms-playlist-kill-track-name-at-point ()
- (interactive)
- (let ((name (emms-track-get (emms-playlist-track-at (point)) 'name)))
- (kill-new name)
- (message "Copied %s" name)))
-
-(defun my-emms-kill-current-track-name ()
- (interactive)
- (let ((name (my-emms-get-current-track-name)))
- (kill-new name)
- (message "Copied %s" name)))
-
-(defvar my-emms-favourites-playlist
- (file-name-concat emms-directory "favourites.native"))
-(defun my-emms-append-current-track-to-favourites ()
- (interactive)
- (with-temp-buffer
- (find-file my-emms-favourites-playlist)
- (goto-char (1+ (point-min)))
- (beginning-of-line 3)
- (insert (prin1-to-string (my-emms-get-current-track)))
- (insert "\n")
- (save-buffer)
- (message "Added %s to %s!"
- (my-emms-print-current-track-display-name)
- my-emms-favourites-playlist)
- (kill-buffer))
- (my-emms-load-from-native my-emms-favourites-playlist
- (my-emms-playlist-make-buffer-name
- my-emms-favourites-playlist)))
-
-;;; random album in emms
-(defun my-my-emms-current-album-name ()
- (file-name-directory (my-emms-get-current-track-name)))
-
-(defun my-emms-next-track-or-random-album ()
- (interactive)
- (let ((current-album (my-my-emms-current-album-name)))
- (when emms-player-playing-p (emms-stop))
- (emms-playlist-current-select-next)
- (if (string-equal (my-my-emms-current-album-name) current-album)
- (emms-start)
- (my-emms-random-album nil))))
-
-(defvar-local my-emms-albums-cache (vector))
-
-(defun my-emms-save-albums-cache ()
- (let ((album-set (make-hash-table :test 'equal))
- (album-list))
- (save-excursion
- (goto-char (point-min))
- (while (not (eobp))
- (puthash (file-name-directory
- (emms-track-get (emms-playlist-track-at (point)) 'name))
- nil album-set)
- (forward-line)))
- (maphash (lambda (key _) (push key album-list)) album-set)
- (setq my-emms-albums-cache (vconcat album-list))
- (message "Emms album cache updated.")))
-
-(defun my-emms-random-album (update-album)
- (interactive "P")
- (with-current-emms-playlist
- (when (or update-album (length= my-emms-albums-cache 0))
- (my-emms-save-albums-cache))
- (when emms-player-playing-p (emms-stop))
- (let ((saved-position (point)))
- (goto-char (point-min))
- (if (search-forward
- (elt my-emms-albums-cache (random (length my-emms-albums-cache)))
- nil t)
- (emms-playlist-mode-play-current-track)
- (goto-char saved-position)
- (error "Cannot play random album")))))
-
-;;; override the minor mode
-;;;###autoload
-(define-minor-mode emms-playing-time-display-mode
- "Minor mode to display playing time on mode line."
- :global t
- ;; When disabling the mode, don't disable `emms-playing-time-display-mode'
- ;; since that may be used by other packages.
- )
-
-;; do we really need this? emms already has some dired support builtin
-(require 'dired)
-(defun my-dired-add-to-emms ()
- (interactive)
- (let ((target (dired-get-filename)))
- (or (emms-add-file target) (emms-add-directory target))))
-
-(defun my-emms-playlist-delete-at-point ()
- (interactive)
- (let* ((track (emms-playlist-track-at (point)))
- (type (emms-track-type track))
- (name (emms-track-name track)))
- (cond ((and (eq type 'url)
- (string-match "^file://\\(.*\\)" name))
- (let ((file-name (match-string 1 name)))
- (when (and
- (not (file-attribute-type (file-attributes file-name)))
- (y-or-n-p (format "Delete file %s?" file-name)))
- (delete-file file-name)
- (message "File deleted: %s" name)
- (emms-playlist-mode-kill-track))))
- (t (message "cannot delete %s" name)))))
-
-;; wip
-(defun emms-download-at-point (audio-only)
- (interactive "P")
- (let* ((track (emms-playlist-track-at (point)))
- (type (emms-track-get track 'type))
- (url (emms-track-get track 'name)))
- (cond
- ((not (equal type 'url))
- (error "Not a url type track!"))
- ((not (or (string-prefix-p "http://" url)
- (string-prefix-p "https://" url)))
- (error "Not http(s) scheme!"))
- (t (my-shell-with-directory "~/Downloads")))
- ))
-
-;; Used to override `emms-track-simple-description' to fallback to description
-(defun my-emms-track-simple-description (track)
- "Simple function to give a user-readable description of a track.
-If it's a file track, just return the file name. Otherwise,
-return the type and the name with a colon in between.
-Hex-encoded characters in URLs are replaced by the decoded
-character."
- (let ((type (emms-track-type track)))
- (cond ((emms-track-get track 'description)
- (emms-track-get track 'description))
- ((eq 'file type)
- (emms-track-name track))
- ((eq 'url type)
- (emms-format-url-track-name (emms-track-name track)))
- (t (concat (symbol-name type)
- ": " (emms-track-name track))))))
-
-(provide 'my-emms)
-;;; my-emms.el ends here
diff --git a/.emacs.d/lisp/my/my-github.el b/.emacs.d/lisp/my/my-github.el
deleted file mode 100644
index 7dc2248..0000000
--- a/.emacs.d/lisp/my/my-github.el
+++ /dev/null
@@ -1,68 +0,0 @@
-;;; my-github.el -- Github client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Github client.
-
-;;; Code:
-
-
-(defun my-grok-github (url)
- "get github info of a project.
-url is the url of the project
-License; name; description; homepage; created at"
- (when (string-match "github.com\\(/[^/]+/[^/]+\\)/?.*$" url)
- (with-current-buffer (url-retrieve-synchronously
- (concat "https://api.github.com/repos"
- (replace-regexp-in-string
- "\\.git$" "" (match-string 1 url))))
- (set-buffer-multibyte t)
- (my-delete-http-header)
- (my-grok-github-make-info (json-read)))))
-
-(defun my-post-process-licensing-name (name)
- (cond ((equal name "MIT") "expat")
- (t name)))
-
-(defun my-grok-github-make-info (raw)
- (list (cons "Title" (alist-get 'name raw))
- (cons "Description" (alist-get 'description raw))
- (cons "Source" (alist-get 'html_url raw))
- (cons "Website" (alist-get 'homepage raw))
- (cons "Released" (substring (alist-get 'created_at raw) 0 10))
- (cons "Pushed" (substring (alist-get 'pushed_at raw) 0 10))
- (cons "Subject" (string-join (alist-get 'topics raw) ", "))
- ;; FIXME: why did we comment this out?
- ;; (cons "License" (my-post-process-licensing-name
- ;; (alist-get 'spdx_id (alist-get 'license raw))))
- (cons "Developers" (my-grok-github-get-developer-name
- (alist-get 'url (alist-get 'owner raw))))))
-
-(defun my-grok-github-get-developer-name (url)
- (with-current-buffer (url-retrieve-synchronously url)
- (set-buffer-multibyte t)
- (my-delete-http-header)
- (alist-get 'name (json-read))))
-
-(provide 'my-github)
-;;; my-github.el ends here
diff --git a/.emacs.d/lisp/my/my-gitlab.el b/.emacs.d/lisp/my/my-gitlab.el
deleted file mode 100644
index a25533f..0000000
--- a/.emacs.d/lisp/my/my-gitlab.el
+++ /dev/null
@@ -1,61 +0,0 @@
-;;; my-gitlab.el -- gitlab client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; gitlab client.
-
-;;; Code:
-
-
-(defun my-get-gitlab-project-id (url)
- (with-current-buffer (url-retrieve-synchronously
- (replace-regexp-in-string "\\.git$" "" url))
- (goto-char (point-min))
- (when (re-search-forward "Project ID: \\([0-9]+\\)" nil t)
- (match-string 1))))
-
-(defun my-grok-gitlab (url)
- (when-let* ((urlobj (url-generic-parse-url url))
- (project-id (my-get-gitlab-project-id url)))
- (with-current-buffer
- (url-retrieve-synchronously
- (concat (url-type urlobj) "://" (url-host urlobj)
- "/api/v4/projects/" project-id))
- (set-buffer-multibyte t)
- (my-delete-http-header)
- (my-grok-gitlab-make-info (json-read)))))
-
-(defun my-grok-gitlab-make-info (raw)
- (list (cons "Title" (alist-get 'name raw))
- (cons "Description" (my-clean-property-value
- (alist-get 'description raw)))
- (cons "Source" (alist-get 'web_url raw))
- (cons "Subject" (string-join
- (alist-get 'tag_list raw) ", "))
- (cons "Released" (substring (alist-get 'created_at raw) 0 10))
- (cons "Last-activity" (substring
- (alist-get 'last_activity_at raw) 0 10))
- (cons "Developers" (alist-get 'name (alist-get 'namespace raw)))))
-
-(provide 'my-gitlab)
-;;; my-gitlab.el ends here
diff --git a/.emacs.d/lisp/my/my-gnus.el b/.emacs.d/lisp/my/my-gnus.el
deleted file mode 100644
index aee03b5..0000000
--- a/.emacs.d/lisp/my/my-gnus.el
+++ /dev/null
@@ -1,327 +0,0 @@
-;;; my-gnus.el -- Email related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Email related extensions for emacs core. Covers gnus, message mode etc.
-
-;;; Code:
-
-
-
-(defun my-gnus-summary-exit-like-mu4e () (interactive)
- (if (get-buffer-window (gnus-buffer-live-p gnus-article-buffer))
- (gnus-summary-expand-window)
- (gnus-summary-exit)))
-
-(defun my-gnus-summary-next-article-like-mu4e () (interactive)
- (if (get-buffer-window (gnus-buffer-live-p gnus-article-buffer))
- (gnus-summary-next-article)
- (next-line)))
-(defun my-gnus-summary-prev-article-like-mu4e () (interactive)
- (if (get-buffer-window (gnus-buffer-live-p gnus-article-buffer))
- (gnus-summary-prev-article)
- (previous-line)))
-
-(defun my-gnus-topic-select-group (arg)
- (interactive "P")
- (if arg (gnus-topic-select-group t)
- (gnus-topic-select-group 200)))
-
-(defun my-gnus-move-article-like-mu4e ()
- (interactive)
- (call-interactively 'gnus-summary-move-article)
- (my-gnus-summary-next-article-like-mu4e))
-
-(defvar my-gnus-group-default-targets
- '((archive . "Archive") (trash . "Trash")))
-
-(defvar my-gnus-group-alist `((".*" . ,my-gnus-group-default-targets))
- "Alist of information about groups such as archive and trash
-targets. Later entries override earlier ones")
-
-(defun my-gnus-refile-article-like-mu4e (key)
- "Refile an article and move to the next, just like in mu4e.
-
-The archiving target comes from `my-gnus-group-alist'.
-KEY is either 'archive or 'trash."
- (interactive)
- (let ((target
- (alist-get key my-gnus-group-default-targets))
- (new-group-name))
- (pcase-dolist (`(,re . ,info) my-gnus-group-alist)
- (when (and (string-match re gnus-newsgroup-name)
- (alist-get key info))
- (setq target (alist-get key info))))
- (setq new-group-name
- (replace-regexp-in-string
- "/.*"
- (concat "/" target)
- gnus-newsgroup-name))
- (gnus-summary-move-article 1 new-group-name)
- (my-gnus-summary-next-article-like-mu4e)))
-
-(defun my-gnus-archive-article-like-mu4e ()
- "Archive an article and move to the next, just like in mu4e.
-
-The archiving target comes from `my-gnus-group-alist'."
- (interactive)
- (my-gnus-refile-article-like-mu4e 'archive))
-
-(defun my-gnus-trash-article-like-mu4e ()
- (interactive)
- (my-gnus-refile-article-like-mu4e 'trash))
-
-(defun my-org-open-gnus-link (link)
- (my-select-new-window-matching-mode 'gnus-summary-mode)
- (org-gnus-open link t))
-
-(defvar my-gnus-inbox-group nil
- "The default inbox to be opened with `my-gnus-open-inbox'.")
-(defun my-gnus-open-inbox ()
- (interactive)
- (gnus-group-read-group t nil my-gnus-inbox-group))
-
-(defun my-gnus-start ()
- (interactive)
- (let ((buffer (get-buffer "*Group*")))
- (if buffer
- (switch-to-buffer "*Group*")
- (gnus))))
-
-(defun my-gnus-topic-up ()
- (interactive)
- (gnus-topic-jump-to-topic (gnus-current-topic)))
-
-(defun my-gnus-group-compose ()
- (interactive) (gnus-group-mail '(4)))
-
-(defun my-gnus-group-get-new-news-quietly ()
- (interactive)
- (let ((inhibit-message t))
- (gnus-group-get-new-news)))
-
-
-;; override `mm-display-external'
-;; Removed the following nonsensical part
-;; ;; So that we pop back to the right place, sort of.
-;; (switch-to-buffer gnus-summary-buffer)
-(defun my-mm-display-external (handle method)
- "Display HANDLE using METHOD."
- (let ((outbuf (current-buffer)))
- (mm-with-unibyte-buffer
- (if (functionp method)
- (let ((cur (current-buffer)))
- (if (eq method 'mailcap-save-binary-file)
- (progn
- (set-buffer (generate-new-buffer " *mm*"))
- (setq method nil))
- (mm-insert-part handle)
- (mm-add-meta-html-tag handle)
- (let ((win (get-buffer-window cur t)))
- (when win
- (select-window win)))
- (switch-to-buffer (generate-new-buffer " *mm*")))
- (buffer-disable-undo)
- (set-buffer-file-coding-system mm-binary-coding-system)
- (insert-buffer-substring cur)
- (goto-char (point-min))
- (when method
- (message "Viewing with %s" method))
- (let ((mm (current-buffer))
- (attachment-filename (mm-handle-filename handle))
- (non-viewer (assq 'non-viewer
- (mailcap-mime-info
- (mm-handle-media-type handle) t))))
- (unwind-protect
- (if method
- (progn
- (when (and (boundp 'gnus-summary-buffer)
- (buffer-live-p gnus-summary-buffer))
- (when attachment-filename
- (with-current-buffer mm
- (rename-buffer
- (format "*mm* %s" attachment-filename) t)))
- ;; ;; So that we pop back to the right place, sort of.
- ;; (switch-to-buffer gnus-summary-buffer)
- (switch-to-buffer mm))
- (funcall method))
- (mm-save-part handle))
- (when (and (not non-viewer)
- method)
- (mm-handle-set-undisplayer handle mm)))))
- ;; The function is a string to be executed.
- (mm-insert-part handle)
- (mm-add-meta-html-tag handle)
- ;; We create a private sub-directory where we store our files.
- (let* ((dir (with-file-modes #o700
- (make-temp-file
- (expand-file-name "emm." mm-tmp-directory) 'dir)))
- (filename (or
- (mail-content-type-get
- (mm-handle-disposition handle) 'filename)
- (mail-content-type-get
- (mm-handle-type handle) 'name)))
- (mime-info (mailcap-mime-info
- (mm-handle-media-type handle) t))
- (needsterm (or (assoc "needsterm" mime-info)
- (assoc "needsterminal" mime-info)))
- (copiousoutput (assoc "copiousoutput" mime-info))
- file buffer)
- (if filename
- (setq file (expand-file-name
- (gnus-map-function mm-file-name-rewrite-functions
- (file-name-nondirectory filename))
- dir))
- ;; Use nametemplate (defined in RFC1524) if it is specified
- ;; in mailcap.
- (let ((suffix (cdr (assoc "nametemplate" mime-info))))
- (if (and suffix
- (string-match "\\`%s\\(\\..+\\)\\'" suffix))
- (setq suffix (match-string 1 suffix))
- ;; Otherwise, use a suffix according to
- ;; `mailcap-mime-extensions'.
- (setq suffix (car (rassoc (mm-handle-media-type handle)
- mailcap-mime-extensions))))
- (setq file (with-file-modes #o600
- (make-temp-file (expand-file-name "mm." dir)
- nil suffix)))))
- (let ((coding-system-for-write mm-binary-coding-system))
- (write-region (point-min) (point-max) file nil 'nomesg))
- ;; The file is deleted after the viewer exists. If the users edits
- ;; the file, changes will be lost. Set file to read-only to make it
- ;; clear.
- (set-file-modes file #o400 'nofollow)
- (message "Viewing with %s" method)
- (cond
- (needsterm
- (let ((command (mm-mailcap-command
- method file (mm-handle-type handle))))
- (unwind-protect
- (if window-system
- (set-process-sentinel
- (start-process "*display*" nil
- mm-external-terminal-program
- "-e" shell-file-name
- shell-command-switch command)
- (lambda (process _state)
- (if (eq 'exit (process-status process))
- (run-at-time
- 60.0 nil
- (lambda ()
- (ignore-errors (delete-file file))
- (ignore-errors (delete-directory
- (file-name-directory
- file))))))))
- (require 'term)
- (require 'gnus-win)
- (set-buffer
- (setq buffer
- (make-term "display"
- shell-file-name
- nil
- shell-command-switch command)))
- (term-mode)
- (term-char-mode)
- (set-process-sentinel
- (get-buffer-process buffer)
- (let ((wc gnus-current-window-configuration))
- (lambda (process _state)
- (when (eq 'exit (process-status process))
- (ignore-errors (delete-file file))
- (ignore-errors
- (delete-directory (file-name-directory file)))
- (gnus-configure-windows wc)))))
- (gnus-configure-windows 'display-term))
- (mm-handle-set-external-undisplayer handle (cons file buffer))
- (add-to-list 'mm-temp-files-to-be-deleted file t))
- (message "Displaying %s..." command))
- 'external)
- (copiousoutput
- (with-current-buffer outbuf
- (forward-line 1)
- (mm-insert-inline
- handle
- (unwind-protect
- (progn
- (call-process shell-file-name nil
- (setq buffer
- (generate-new-buffer " *mm*"))
- nil
- shell-command-switch
- (mm-mailcap-command
- method file (mm-handle-type handle)))
- (if (buffer-live-p buffer)
- (with-current-buffer buffer
- (buffer-string))))
- (progn
- (ignore-errors (delete-file file))
- (ignore-errors (delete-directory
- (file-name-directory file)))
- (ignore-errors (kill-buffer buffer))))))
- 'inline)
- (t
- ;; Deleting the temp file should be postponed for some wrappers,
- ;; shell scripts, and so on, which might exit right after having
- ;; started a viewer command as a background job.
- (let ((command (mm-mailcap-command
- method file (mm-handle-type handle))))
- (unwind-protect
- (let ((process-connection-type nil))
- (start-process "*display*"
- (setq buffer
- (generate-new-buffer " *mm*"))
- shell-file-name
- shell-command-switch command)
- (set-process-sentinel
- (get-buffer-process buffer)
- (lambda (process _state)
- (when (eq (process-status process) 'exit)
- (run-at-time
- 60.0 nil
- (lambda ()
- (ignore-errors (delete-file file))
- (ignore-errors (delete-directory
- (file-name-directory file)))))
- (when (buffer-live-p outbuf)
- (with-current-buffer outbuf
- (let ((buffer-read-only nil)
- (point (point)))
- (forward-line 2)
- (let ((start (point)))
- (mm-insert-inline
- handle (with-current-buffer buffer
- (buffer-string)))
- (put-text-property start (point)
- 'face 'mm-command-output))
- (goto-char point))))
- (when (buffer-live-p buffer)
- (kill-buffer buffer)))
- (message "Displaying %s...done" command))))
- (mm-handle-set-external-undisplayer
- handle (cons file buffer))
- (add-to-list 'mm-temp-files-to-be-deleted file t))
- (message "Displaying %s..." command))
- 'external)))))))
-
-(provide 'my-gnus)
-;;; my-gnus.el ends here
diff --git a/.emacs.d/lisp/my/my-grep.el b/.emacs.d/lisp/my/my-grep.el
deleted file mode 100644
index 324e44d..0000000
--- a/.emacs.d/lisp/my/my-grep.el
+++ /dev/null
@@ -1,48 +0,0 @@
-;;; my-grep.el -- Extensions for grep -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for grep.
-
-;;; Code:
-
-
-
-(defun my-grep-focus-buffer (buffer)
- (pop-to-buffer buffer))
-
-(defun my-rgrep-at-directory (dir)
- (my-with-default-directory dir
- (let* ((regexp (grep-read-regexp))
- (files (grep-read-files regexp)))
- (rgrep regexp files dir))))
-
-(defun my-grep-docs (project regexp)
- (interactive (list (completing-read "Docs to grep: "
- (my-get-list-of-docs))
- (grep-read-regexp)))
- (rgrep regexp (alist-get "docs" grep-files-aliases nil nil 'string=)
- (concat my-docs-root-dir "/" project)))
-
-(provide 'my-grep)
-;;; my-grep.el ends here
diff --git a/.emacs.d/lisp/my/my-help.el b/.emacs.d/lisp/my/my-help.el
deleted file mode 100644
index 27c23ce..0000000
--- a/.emacs.d/lisp/my/my-help.el
+++ /dev/null
@@ -1,138 +0,0 @@
-;;; my-help.el -- Help related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Emacs help related extensions.
-
-;;; Code:
-
-
-;; find source of external command
-(defun my-external-command-open-source (command)
- (interactive
- (list (completing-read
- "Open source of command: "
- (my-external-command-collection))))
- (let ((subject
- (cadr
- (split-string (my-shell-command-output
- (format "type %s" command))
- " is "))))
- (pcase subject
- ("a shell builtin" (error "%s is %s" command subject))
- ("a shell keyword" (error "%s is %s" command subject))
- ((guard (string-prefix-p "is aliased to " subject))
- (substring subject (error "%s is %s" command subject)))
- (_
- (pcase-let
- ((`(,path ,type)
- (split-string
- (my-shell-command-output (format "file -Li %s" subject))
- ": ")))
- (if (string-prefix-p "text/" type)
- (progn
- (message "Opening %s" path)
- (find-file path))
- (error "%s (%s) is not plaintext: %s" command path type)))))))
-
-(defun my-external-command-collection ()
- (mapcan
- (lambda (dir)
- (mapcar
- (lambda (file)
- (string-match "\\(?:.*\\)/\\(.*\\)" file)
- (match-string 1 file))
- (seq-filter
- (lambda (file)
- (and (not (file-directory-p file))
- (file-executable-p file)))
- (directory-files dir t "[^~#]$"))))
- (seq-filter
- 'file-accessible-directory-p
- (exec-path))))
-
-(defun my-woman-man (arg)
- (interactive "P")
- (if arg (call-interactively 'man)
- (call-interactively 'woman)))
-
-(defun my-help-goto-symbol (symbol)
- (interactive
- ;; copied from prompt code of help-describe-symbol
- (let* ((v-or-f (symbol-at-point))
- (found (if v-or-f (cl-some (lambda (x) (funcall (nth 1 x) v-or-f))
- describe-symbol-backends)))
- (v-or-f (if found v-or-f (function-called-at-point)))
- (found (or found v-or-f))
- (enable-recursive-minibuffers t)
- (val (completing-read (format-prompt "Describe symbol"
- (and found v-or-f))
- #'help--symbol-completion-table
- (lambda (vv)
- (cl-some (lambda (x) (funcall (nth 1 x) vv))
- describe-symbol-backends))
- t nil nil
- (if found (symbol-name v-or-f)))))
- (list (if (equal val "")
- (or v-or-f "") (intern val)))))
- (help-do-xref nil #'describe-symbol (list symbol)))
-
-(defun my-describe-local-variable (variable &optional buffer frame)
- (interactive
- (let ((v (variable-at-point))
- (enable-recursive-minibuffers t)
- (orig-buffer (current-buffer))
- val)
- (setq val (completing-read
- (format-prompt "Describe variable" (and (symbolp v) v))
- #'help--symbol-completion-table
- (lambda (vv)
- (and (local-variable-p vv)
- (or (get vv 'variable-documentation)
- (and (not (keywordp vv))
- ;; Since the variable may only exist in the
- ;; original buffer, we have to look for it
- ;; there.
- (buffer-local-boundp vv orig-buffer)))))
- t nil nil
- (if (symbolp v) (symbol-name v))))
- (list (if (equal val "")
- v (intern val)))))
- (describe-variable variable buffer frame))
-
-(defun my-info-display-manual ()
- (interactive)
- (call-interactively 'info-display-manual)
- (when (derived-mode-p 'Info-mode)
- (rename-buffer
- (generate-new-buffer-name
- (format "*info %s*"
- (file-name-sans-extension
- (file-name-nondirectory Info-current-file)))))))
-
-(defun my-describe-symbol-at-point ()
- (interactive)
- (describe-symbol (symbol-at-point)))
-
-(provide 'my-help)
-;;; my-help.el ends here
diff --git a/.emacs.d/lisp/my/my-hiedb.el b/.emacs.d/lisp/my/my-hiedb.el
deleted file mode 100644
index ef3a3c4..0000000
--- a/.emacs.d/lisp/my/my-hiedb.el
+++ /dev/null
@@ -1,73 +0,0 @@
-;;; my-hiedb.el -- Extensions for hiedb -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for hiedb.
-
-;;; Code:
-
-;;; to use, do for example:
-;; (add-hook 'haskell-mode-hook
-;; (lambda ()
-;; (add-hook 'xref-backend-functions
-;; #'hiedb--xref-backend nil t)))
-
-(defun hiedb--xref-backend () 'hiedb)
-
-(cl-defmethod xref-backend-definitions
- ((_backend (eql hiedb)) _identifiers)
- (my-hiedb-call-point-defs buffer-file-name
- (1+ (current-line)) (1+ (current-column)))
- (my-hiedb-parse-point-defs-output
- (file-name-directory buffer-file-name)
- (with-current-buffer "*hiedb*"
- (goto-char (point-min)) (kill-line) (kill-line)
- (buffer-string))
- ))
-
-(defun my-hiedb-call-point-defs (file line col)
- (let ((dir (file-name-directory file))
- (module-name (file-name-base file)))
- (with-current-buffer (get-buffer-create "*hiedb*")
- (erase-buffer))
- (call-process "hiedb" nil "*hiedb*" nil
- "-D"
- (format "%sdefault.hiedb" dir)
- "point-defs" module-name
- (number-to-string line)
- (number-to-string col))))
-
-(defun my-hiedb-parse-point-defs-output (dir output)
- "module-name:line-begin:col-begin-line-end:col-end"
- (pcase-let ((`(,module-name ,line-beg ,col-beg, line-end, col-end)
- (split-string output "[:-]" (print output))))
- (list
- (xref-make-match
- "" (xref-make-file-location
- (format "%s%s.hs" dir module-name)
- (string-to-number line-beg)
- (string-to-number col-beg))
- (- (string-to-number col-end) (string-to-number col-beg))))))
-
-(provide 'my-hiedb)
-;;; my-hiedb.el ends here
diff --git a/.emacs.d/lisp/my/my-hnreader.el b/.emacs.d/lisp/my/my-hnreader.el
deleted file mode 100644
index 4176f8b..0000000
--- a/.emacs.d/lisp/my/my-hnreader.el
+++ /dev/null
@@ -1,106 +0,0 @@
-;;; my-hnreader.el -- Extensions to hnreader -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Thanh Vuong <thanhvg@gmail.com>
-;; Maintainer: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions to hnreader.
-
-;;; Code:
-
-;; To override `hnreader--print-frontpage-item'
-(defun my-hnreader--print-frontpage-item (thing subtext)
- "Print THING dom and SUBTEXT dom."
- (let* ((url (format "https://news.ycombinator.com/item?id=%s" (dom-attr thing 'id)))
- (a-node (dom-child-by-tag (dom-by-class thing "^titleline$") 'a))
- (title-link (dom-attr a-node 'href)))
- (insert (format "\n* %s [[%s][%s]] (%s) [[elisp:(hnreader-comment \"%s\")][%s]]"
- ;; rank
- (dom-text (dom-by-class thing "^rank$"))
- title-link
- ;; title
- (dom-text a-node)
- ;; points
- (dom-text (dom-by-class subtext "^score$"))
- ;; comments
- url
- (dom-text (last (dom-by-tag subtext 'a)))))
- ))
-
-
-;; To override `hnreader--print-frontpage'
-(defun my-hnreader--print-frontpage (dom buf url)
- "Print raw DOM and URL on BUF."
- (let ((things (dom-by-class dom "^athing$"))
- (subtexts (dom-by-class dom "^subtext$")))
- (with-current-buffer buf
- (read-only-mode -1)
- (erase-buffer)
- (insert "#+STARTUP: overview indent\n")
- (hnreader--print-header)
- (insert (hnreader--get-route-top-info dom))
- (cl-mapcar #'hnreader--print-frontpage-item things subtexts)
- ;; (setq-local org-confirm-elisp-link-function nil)
- (if hnreader--history
- (insert "\n* "(format "[[elisp:(hnreader-back)][< Back]]" ) " | ")
- (insert "\n* "))
- (insert (hnreader--get-morelink dom) " | ")
- (insert (format "[[elisp:(hnreader-read-page-back \"%s\")][Reload]]" url) )
- (org-mode)
- (goto-char (point-min))
- (forward-line 2))))
-
-;; To override `hnreader--print-comments'
-(defun my-hnreader--print-comments (dom url)
- "Print DOM comment and URL to buffer."
- (let ((comments (dom-by-class dom "^athing comtr$"))
- (title (hnreader--get-title dom))
- (info (hnreader--get-post-info dom))
- (more-link (dom-by-class dom "morelink")))
- (with-current-buffer (hnreader--get-hn-comment-buffer)
- (read-only-mode -1)
- (erase-buffer)
- (insert "-*-Org-*-\n")
- (insert "#+TITLE: " (car title))
- (insert (format "\n%s\n" (cdr title)))
- (insert (car info))
- (when (cdr info)
- (insert "\n")
- (shr-insert-document (cdr info)))
- (dolist (comment comments)
- (insert (format "%s %s\n"
- (hnreader--get-indent
- (hnreader--get-img-tag-width comment))
- (hnreader--get-comment-owner comment)))
- (shr-insert-document (hnreader--get-comment comment)))
- (when more-link
- (insert "\n* " (format "[[elisp:(hnreader-comment \"%s\")][More]]" (concat "https://news.ycombinator.com/"
- (dom-attr more-link 'href)))))
- (insert "\n* " (format "[[elisp:(hnreader-comment \"%s\")][Reload]]" url))
- (org-mode)
- ;; (org-shifttab 3)
- (goto-char (point-min))
- (forward-line 2))))
-
-(provide 'my-hnreader)
-;;; my-hnreader.el ends here
diff --git a/.emacs.d/lisp/my/my-libgen.el b/.emacs.d/lisp/my/my-libgen.el
deleted file mode 100644
index 98ea409..0000000
--- a/.emacs.d/lisp/my/my-libgen.el
+++ /dev/null
@@ -1,241 +0,0 @@
-;;; my-libgen.el -- libgen client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it
-;; under the terms of the GNU Affero General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-
-;; dotfiles 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
-;; Affero General Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; libgen client.
-
-;;; Code:
-
-
-;;; todo: autoloads
-(require 'link-gopher)
-(require 'my-wget)
-(require 'my-utils)
-
-(defvar my-libgen-hosts nil "Hosts of standard libgen")
-
-(defvar my-libgen-alt-hosts nil "Hosts of libgen variants")
-
-(defvar my-libgen-library-hosts nil "Hosts of libgen library sites")
-
-(defvar my-libgen-host nil)
-(defvar my-libgen-library-host nil)
-
-(defun my-libgen-set-random-hosts ()
- "Randomly set `my-libgen-host' and `my-libgen-library-host'"
- (setq my-libgen-library-host
- (my-seq-random-element my-libgen-library-hosts)
- my-libgen-host
- (my-seq-random-element my-libgen-hosts)))
-
-(defun my-libgen-get-download-url (md5-or-url)
- (cond ((string-match "://.*/fiction/\\(.*\\)$" md5-or-url)
- (concat my-libgen-library-host "/fiction/"
- (match-string 1 md5-or-url)))
- ((string-match "\\?md5=\\(.*\\)$" md5-or-url)
- (concat my-libgen-library-host "/main/"
- (match-string 1 md5-or-url)))
- ;; defaults to libgen
- ((string-match "\\([0-9A-F]\\{32\\}\\)" md5-or-url)
- (concat my-libgen-library-host "/main/"
- (match-string 1 md5-or-url)))))
-
-;; TODO: this function looks more general than libgen
-(defun my-libgen-url-at-point ()
- (or (get-text-property (point) 'shr-url)
- (thing-at-point-url-at-point)))
-
-(defun my-libgen-get-filename-from-ipfs-url (url)
- (string-match "filename=\\(.*\\)$" link)
- (decode-coding-string (url-unhex-string (match-string 1 link)) 'utf-8))
-
-(defun my-libgen-wget (md5-or-url)
- (interactive (list (read-string "MD5 or URL: "
- (my-libgen-url-at-point))))
- (when-let ((link (car (link-gopher-get-all-links
- (my-libgen-get-download-url md5-or-url)
- "\\.\\(epub\\|pdf\\|djvu\\)$"))))
- (wget link)))
-
-(defun my-libgen-api-by-isbn (isbn)
- (my-url-fetch-json
- (format "%s/json.php?object=e&isbn=%s&fields=*"
- my-libgen-host isbn)))
-
-(defun my-libgen-format-result (info)
- (concat
- (propertize
- (format
- "%s %.1fM %s"
- (my-libgen-format-filename info)
- (/ (string-to-number (alist-get 'filesize info)) (* 1024.0 1024.0))
- (alist-get 'timelastmodified info))
- 'face 'button)
- (propertize
- (format
- "\n\n%s"
- (alist-get 'descr info))
- 'face 'default)))
-
-(defun my-libgen-api-by-id (id)
- (my-url-fetch-json
- (format "%s/json.php?object=e&ids=%s&fields=*" my-libgen-host id)))
-
-(defun my-grok-libgen-action (info)
- (interactive)
- (my-org-create-node
- (my-grok-libgen-make-info
- (elt
- (my-libgen-api-by-id
- (alist-get 'id info))
- 0))
- t))
-
-(defun my-grok-libgen-make-info (info)
- (list
- (cons "libgen-id" (alist-get 'id info))
- (cons "Title" (alist-get 'title info))
- (cons "Authors" (alist-get 'author info))
- (cons "Published" (alist-get 'year info))
- (cons "Edition" (alist-get 'edition info))
- (cons "Publisher" (alist-get 'publisher info))
- (cons "Pages" (alist-get 'pages info))
- (cons "ISBN" (alist-get 'identifier info))
- (cons "Language" (alist-get 'language info))
- (cons "DOI" (alist-get 'doi info))
- (cons "OpenLibrary-ID" (alist-get 'openlibraryid info))
- (cons "Filesize" (alist-get 'filesize info))
- (cons "Extension" (alist-get 'extension info))
- (cons "md5" (alist-get 'md5 info))
- (cons "Description" (alist-get 'descr info))
- (cons "Cover" (format "%s/covers/%s"
- my-libgen-host
- (alist-get 'coverurl info)))))
-
-(defun my-libgen-format-filename (info)
- (format
- "%s - %s (%s) [%s].%s"
- (alist-get 'author info)
- (alist-get 'title info)
- (alist-get 'year info)
- (alist-get 'identifier info)
- (alist-get 'extension info)))
-
-(defvar my-libgen-download-dir "~/Downloads")
-(defun my-libgen-download-action ()
- (interactive)
- (let ((info (get-text-property (point) 'button-data)))
- (my-wget-async
- (car (link-gopher-get-all-links
- (format "/main/%s" my-libgen-library-host
- (alist-get 'md5 info))
- (format "\\.%s$" (alist-get 'extension info))))
- (format "%s/%s" my-libgen-download-dir
- (my-libgen-format-filename info)))))
-
-(defvar my-libgen-button-keymap
- (let ((kmap (make-sparse-keymap)))
- (set-keymap-parent kmap button-map)
- (define-key kmap "d" 'my-libgen-download-action)
- (define-key kmap "p" 'my-libgen-show-more-info)
- kmap))
-
-(defun my-libgen-show-more-info ()
- (interactive)
- (pp (my-grok-libgen-make-info
- (elt
- (my-libgen-api-by-id
- (alist-get 'id
- (get-text-property (point) 'button-data)))
- 0))))
-
-(defun my-libgen-search-isbn (isbn)
- (interactive "sISBN: ")
- (generic-search-open
- (my-libgen-api-by-isbn isbn)
- (format "libgen-isbn:%s" isbn)
- `((formatter . my-libgen-format-result)
- (default-action . my-grok-libgen-action)
- (keymap . ,my-libgen-button-keymap))))
-
-(defun my-libgen-search (query)
- (interactive "sQuery: ")
- (generic-search-open
- (mapcar 'my-libgen-search-parse-tr
- (cdddr
- (dom-by-tag
- (my-url-fetch-dom
- (format "%s/search.php?req=%s&res=100"
- my-libgen-host query))
- 'tr)))
- (format "libgen-query:%s" query)
- `((formatter . my-libgen-search-format-result)
- (default-action . my-grok-libgen-action)
- (keymap . ,my-libgen-button-keymap))))
-
-(defun my-libgen-search-format-result (info)
- (format
- "%s [%s,%spp,%s,%s] %s"
- (my-libgen-format-filename info)
- (alist-get 'edition info)
- (alist-get 'pages info)
- (alist-get 'publisher info)
- (alist-get 'language info)
- (alist-get 'filesize-human info)))
-
-(defun my-libgen-search-parse-tr (tr)
- (let* ((tds (dom-by-tag tr 'td))
- (id (dom-text (pop tds)))
- (author (dom-texts (pop tds) ""))
- (title-ed-id (car (last (dom-by-tag (pop tds) 'a))))
- (md5 (elt (split-string (or (dom-attr title-ed-id 'href) "") "=") 1))
- (title (string-trim (dom-text title-ed-id)))
- (edition-id (mapconcat 'dom-texts (dom-by-tag title-ed-id 'font) ""))
- (edition)
- (identifier)
- (publisher (dom-text (pop tds)))
- (year (dom-text (pop tds)))
- (pages (dom-text (pop tds)))
- (language (dom-text (pop tds)))
- (filesize-human (dom-text (pop tds)))
- (extension (dom-text (pop tds)))
- )
- (string-match "\\(?:\\[\\(.*\\)\\]\\)?\\([0-9].*\\)?" edition-id)
- (setq edition (or (match-string 1 edition-id) "")
- identifier (or (match-string 2 edition-id) ""))
- `((id . ,id)
- (author . ,author)
- (md5 . ,md5)
- (title . ,title)
- (edition . ,edition)
- (identifier . ,identifier)
- (publisher . ,publisher)
- (year . ,year)
- (pages . ,pages)
- (language . ,language)
- (filesize-human . ,filesize-human)
- (extension . ,extension))))
-
-(provide 'my-libgen)
-;;; my-libgen.el ends here
diff --git a/.emacs.d/lisp/my/my-magit.el b/.emacs.d/lisp/my/my-magit.el
deleted file mode 100644
index 779c7c7..0000000
--- a/.emacs.d/lisp/my/my-magit.el
+++ /dev/null
@@ -1,59 +0,0 @@
-;;; my-magit.el -- Extensions for magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for magit.
-
-;;; Code:
-
-
-
-(require 'magit)
-(require 'my-project)
-(require 'org)
-
-(defun magit-clone-org-source (arg)
- (interactive "P")
- (let* ((url (org-entry-get (point) "Source"))
- (default-base-dir
- (alist-get "3p" my-projects-root-dirs nil nil 'string=))
- (default-name
- (progn (string-match "^.*/\\(.*?\\)\\(\\.git\\)?$" url)
- (match-string 1 url)))
- (dir (read-file-name
- (if arg "Clone to: " "Shallow clone to: ")
- (concat default-base-dir "/")
- nil nil
- default-name)))
- (if arg
- (magit-clone-regular url dir nil)
- (magit-clone-shallow url dir nil 1))
- (org-set-property "Local-source"
- (format "<file:%s>" dir))))
-
-(defun my-project-magit-at ()
- (interactive)
- (magit-status (my-project-read-project-root)))
-
-(provide 'my-magit)
-;;; my-magit.el ends here
diff --git a/.emacs.d/lisp/my/my-markdown.el b/.emacs.d/lisp/my/my-markdown.el
deleted file mode 100644
index 8b12bc8..0000000
--- a/.emacs.d/lisp/my/my-markdown.el
+++ /dev/null
@@ -1,37 +0,0 @@
-;;; my-markdown.el -- Extensions to markdown -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions to markdown.
-
-;;; Code:
-
-;;; markdown
-(defun my-markdown-maybe-follow-thing-at-point (arg)
- (interactive "P")
- (condition-case nil
- (markdown-follow-thing-at-point arg)
- (user-error (newline))))
-
-(provide 'my-markdown)
-;;; my-markdown.el ends here
diff --git a/.emacs.d/lisp/my/my-markup.el b/.emacs.d/lisp/my/my-markup.el
deleted file mode 100644
index 2b1c7f6..0000000
--- a/.emacs.d/lisp/my/my-markup.el
+++ /dev/null
@@ -1,68 +0,0 @@
-;;; my-markup.el -- Markup related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Markup related extensions for emacs core.
-
-;;; Code:
-
-
-;;; shr
-(defun my-shr-add-id (dom start end)
- (let ((id (dom-attr dom 'id)))
- (when id
- (put-text-property start end 'shr-frag-id id))))
-
-(defun my-shr-add-id-advice (orig-fun &rest args)
- (let ((start (point)))
- (apply orig-fun args)
- (my-shr-add-id (car args) start (point))))
-
-;;; dom
-(defun my-dom-remove-style (node)
- (dolist (to-remove (dom-by-tag node 'style))
- (dom-remove-node node to-remove))
- node)
-(defun my-dom-next-p-sibling (dom node)
- "Return the next para sibling of NODE in DOM."
- (when-let* ((parent (dom-parent dom node)))
- (let ((siblings (dom-children parent))
- (next))
- (while (and siblings (not next))
- (when (eq (pop siblings) node)
- (setq next (car siblings))))
- (while (and siblings (not (and (listp next) (eq (dom-tag next) 'p))))
- (setq next (pop siblings)))
- next)))
-(defun my-dom-first-tag-text (dom tag)
- (car (dom-by-tag dom tag)))
-
-;; xml
-(defun my-xml-get-first-child (node tag)
- (car (xml-get-children node tag)))
-(defun my-xml-get-first-child-text (node tag)
- (when-let ((text (dom-text (my-xml-get-first-child node tag))))
- (replace-regexp-in-string "\n" " " (string-trim text))))
-
-(provide 'my-markup)
-;;; my-markup.el ends here
diff --git a/.emacs.d/lisp/my/my-media-segment.el b/.emacs.d/lisp/my/my-media-segment.el
deleted file mode 100644
index 0cef817..0000000
--- a/.emacs.d/lisp/my/my-media-segment.el
+++ /dev/null
@@ -1,182 +0,0 @@
-;;; my-media-segment.el -- Media segmentation utility -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Media segmentation utility.
-
-;;; Code:
-
-
-
-;;; A utility using ffmpeg to cut a media file into smaller ones, from a
-;;; description of the timestamps.
-(defvar my-media-segment-queued-jobs nil)
-(defvar my-media-segment-max-inflight 3)
-
-(defun my-media-segment-enqueue-process (start-process-function)
- "Enqueue a process that can started by applying 'start-process'.
-
-The process can be started by applying 'start-process' on START-PROCESS-ARGS."
- ;; somehow only this version works, but not nconc or setq with append
- ;; the problem with the other two is that the operation gets stuck after the
- ;; initial 'my-media-segment-max-inflight' operations.
- (add-to-list 'my-media-segment-queued-jobs start-process-function)
- ;; (nconc my-media-segment-queued-jobs (list start-process-function))
- ;; (setq my-media-segment-queued-jobs
- ;; (append my-media-segment-queued-jobs (list start-process-function)))
- )
-
-(defun my-media-segment-dequeue-process ()
- (when my-media-segment-queued-jobs
- (funcall (pop my-media-segment-queued-jobs))))
-
-(defun my-segment-media-file-1 (media-file-name desc-file-name)
- "Run ffmpeg asynchronously to segment file-name according to description.
-
-Uses `my-media-segment-max-inflight' to limit number of inflight tasks."
- (interactive (list
- (read-file-name "Choose media file: ")
- (read-file-name "Choose description file: ")))
- (let* ((dir (file-name-sans-extension (expand-file-name media-file-name)))
- (info (my-get-media-segments
- (with-temp-buffer
- (insert-file-contents desc-file-name)
- (buffer-string))))
- (total (length info))
- (idx 0)
- (thunk))
- (dolist (media info)
- (setq idx (1+ idx))
- (ignore-errors (dired-create-directory dir))
- (let* ((title (plist-get media :title))
- (start (plist-get media :start))
- (end (plist-get media :end))
- (args (append (list "-ss" start)
- (when end (list "-to" end))
- (list "-i" (expand-file-name media-file-name)
- (format "%s/%s.%s" dir title
- (file-name-extension media-file-name))))))
- (setq thunk
- (lambda ()
- (message "Cutting %s-%s to %s (%d/%d)..."
- start (or end "") title idx total)
- (set-process-sentinel
- (apply 'start-process
- (append (list (format "ffmpeg-%s" title)
- (format "*ffmpeg-%s*" title)
- "ffmpeg")
- args))
- (lambda (_ _)
- (my-media-segment-dequeue-process)))))
- (if (<= idx my-media-segment-max-inflight)
- (funcall thunk)
- (my-media-segment-enqueue-process thunk))))))
-
-(defun my-get-media-segments (description)
- "Output title start end triplets."
- (let ((results) (title) (start) (end))
- (with-temp-buffer
- (erase-buffer)
- (insert description)
- (goto-char (point-min))
- (save-excursion
- (while (re-search-forward
- "\\(\\(?:[0-9]+:\\)?[0-9]+:[0-9]\\{2\\}\\)\\(?:[[:space:]]*-[[:space:]]*\\(\\(?:[0-9]+:\\)?[0-9]+:[0-9]\\{2\\}\\)\\)?"
- nil t)
- (setq start (match-string-no-properties 1)
- end (match-string-no-properties 2))
- (replace-match "")
- (beginning-of-line 1)
- (setq title (replace-regexp-in-string
- "^[[:punct:][:space:]]*" ""
- (replace-regexp-in-string
- "[[:punct:][:space:]]*$" ""
- (buffer-substring-no-properties
- (point)
- (progn (beginning-of-line 2) (point))))))
- (push (list :title (my-make-filename title) :start start :end end) results)
- )
- (setq end nil)
- (dolist (result results)
- (unless (plist-get result :end)
- (plist-put result :end end)
- (setq end (plist-get result :start))))
- (reverse results))
- )))
-
-(defvar my-segment-media-max-async 10)
-(defun my-segment-media-file (media-file-name desc-file-name synchronously)
- "Run ffmpeg asynchronously to segment file-name according to description.
-
-With a prefix-arg, run synchronously."
- (interactive (list
- (read-file-name "Choose media file: ")
- (read-file-name "Choose description file: ")
- current-prefix-arg))
- (let* ((dir (file-name-sans-extension (expand-file-name media-file-name)))
- (info (my-get-media-segments
- (with-temp-buffer
- (insert-file-contents desc-file-name)
- (buffer-string))))
- (total (length info))
- (idx 0))
- (when (or synchronously (<= total my-segment-media-max-async)
- (let ((choice
- (car
- (read-multiple-choice
- (format
- "Recognised many (%d) segments, continue asynchronously?"
- total)
- '((?y "yes")
- (?s "synchronously instead")
- (?n "cancel"))))))
- (cond ((eq choice ?y) t)
- ((eq choice ?s) (setq synchronously t))
- (t nil))))
- (dolist (media info)
- (setq idx (1+ idx))
- (ignore-errors (dired-create-directory dir))
- (let* ((title (plist-get media :title))
- (start (plist-get media :start))
- (end (plist-get media :end))
- (args (append (list "-ss" start)
- (when end (list "-to" end))
- (list "-i" (expand-file-name media-file-name)
- (format "%s/%s.%s" dir title
- (file-name-extension media-file-name))))))
- (message "Cutting %s-%s to %s (%d/%d)..."
- start (or end "") title idx total)
- (if synchronously
- (apply 'call-process
- (append (list "ffmpeg" nil "*ffmpeg*" t) args))
- (apply 'start-process
- (append (list (format "ffmpeg-%s" title)
- (format "*ffmpeg-%s*" title)
- "ffmpeg")
- args)))))
- (when synchronously
- (message "All %d segments splitted into %s"
- (length info) dir)))))
-
-(provide 'my-media-segment)
-;;; my-media-segment.el ends here
diff --git a/.emacs.d/lisp/my/my-net.el b/.emacs.d/lisp/my/my-net.el
deleted file mode 100644
index 7713dba..0000000
--- a/.emacs.d/lisp/my/my-net.el
+++ /dev/null
@@ -1,113 +0,0 @@
-;;; my-net.el -- Network related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Network related extensions for emacs core.
-
-;;; Code:
-
-
-;;; net utilities
-(defvar my-download-dir "~/Downloads")
-
-(defun my-make-file-name-from-url (url)
- (file-name-nondirectory
- (directory-file-name
- (car (url-path-and-query (url-generic-parse-url
- (url-unhex-string url)))))))
-
-(defun my-fetch-url (url)
- (interactive "sURL: ")
- (let ((file-name (expand-file-name (my-make-file-name-from-url url)
- my-download-dir)))
- (url-retrieve url 'my-fetch-url-save-and-switch (list file-name))))
-
-(defun my-fetch-url-save-and-switch (status file-name)
- (unless (plist-get status :error)
- (my-delete-http-header)
- (write-file file-name)
- (let ((coding-system-for-read 'utf-8))
- (revert-buffer t t))
- (switch-to-buffer (current-buffer))))
-
-(defun my-kill-http-header ()
- (my-skip-http-header)
- (let ((killed (buffer-substring-no-properties (point-min) (point))))
- (delete-region (point-min) (point))
- killed))
-
-(defun my-parse-http-header (text)
- (let ((status) (fields))
- (with-temp-buffer
- (insert text)
- (goto-char (point-min))
- (re-search-forward "^HTTP.*\\([0-9]\\{3\\}\\).*$")
- (setq status (match-string 1))
- (while (re-search-forward "^\\(.*?\\): \\(.*\\)$" nil t)
- (push (cons (intern (match-string 1)) (match-string 2)) fields)))
- (list (cons 'status status) (cons 'fields fields))))
-
-(defvar my-client-buffer-name "*my-api*")
-
-(defun my-url-fetch-json (url &optional decompression with-header)
- (my-url-fetch-internal
- url
- (lambda ()
- (json-read-from-string (decode-coding-string (buffer-string) 'utf-8)))
- decompression
- with-header))
-
-(defun my-url-fetch-dom (url &optional decompression with-header)
- (my-url-fetch-internal
- url
- (lambda () (libxml-parse-html-region (point) (point-max)))
- decompression
- with-header))
-
-(defun my-url-fetch-internal (url buffer-processor decompression with-header)
- (with-current-buffer (get-buffer-create my-client-buffer-name)
- (goto-char (point-max))
- (insert "[" (current-time-string) "] Request: " url "\n"))
- (with-current-buffer (url-retrieve-synchronously url t)
- (let ((header (my-kill-http-header)) (status) (fields))
- (goto-char (point-min))
- (setq header (my-parse-http-header header)
- status (alist-get 'status header)
- fields (alist-get 'fields header))
- (with-current-buffer my-client-buffer-name
- (insert "[" (current-time-string) "] Response: " status "\n"))
- (when decompression
- (call-process-region (point) (point-max) "gunzip" t t t)
- (goto-char (point-min)))
- (call-interactively 'delete-trailing-whitespace)
- (if (string= status "200")
- (unless (= (point) (point-max))
- (if with-header
- (list
- (cons 'header fields)
- (cons 'json (funcall buffer-processor)))
- (funcall buffer-processor)))
- (error "HTTP error: %s" (buffer-substring (point) (point-max)))))))
-
-(provide 'my-net)
-;;; my-net.el ends here
diff --git a/.emacs.d/lisp/my/my-nov.el b/.emacs.d/lisp/my/my-nov.el
deleted file mode 100644
index 863d09a..0000000
--- a/.emacs.d/lisp/my/my-nov.el
+++ /dev/null
@@ -1,56 +0,0 @@
-;;; my-nov.el -- Extensions for nov.el -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for nov.el.
-
-;;; Code:
-
-(require 'nov)
-
-;; override nov-render-title
-;; this is because header line does not work with follow mode
-(defun my-nov-render-title (dom)
- "Custom <title> rendering function for DOM.
-Sets `header-line-format' to a combination of the EPUB title and
-chapter title."
- (let ((title (cdr (assq 'title nov-metadata)))
- (chapter-title (car (esxml-node-children dom))))
- (when (not chapter-title)
- (setq chapter-title "No title"))
- ;; this shouldn't happen for properly authored EPUBs
- (when (not title)
- (setq title "No title"))
- (setq mode-line-buffer-identification
- (concat title ": " chapter-title))
- ))
-
-(defun my-nov-scroll-up (arg)
- "Scroll with `scroll-up' or visit next chapter if at bottom."
- (interactive "P")
- (if (>= (follow-window-end) (point-max))
- (nov-next-document)
- (follow-scroll-up arg)))
-
-(provide 'my-nov)
-;;; my-nov.el ends here
diff --git a/.emacs.d/lisp/my/my-openlibrary.el b/.emacs.d/lisp/my/my-openlibrary.el
deleted file mode 100644
index 559ecba..0000000
--- a/.emacs.d/lisp/my/my-openlibrary.el
+++ /dev/null
@@ -1,147 +0,0 @@
-;;; my-openlibrary.el -- openlibrary client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; openlibrary client.
-
-;;; Code:
-
-
-;;; an openlibrary client
-(require 'generic-search)
-(require 'my-net)
-
-(defvar my-openlibrary-host "https://openlibrary.org")
-(defun my-openlibrary-api-book-by-olid (olid)
- (my-url-fetch-json
- (format "%s/api/books?bibkeys=OLID:%s&format=json&jscmd=data"
- my-openlibrary-host olid)))
-
-(defun my-openlibrary-html-book-by-url (url)
- (list
- (cons 'description
- (string-trim
- (dom-texts
- (dom-by-class
- (my-url-fetch-dom url)
- "book-description-content restricted-view"))))))
-
-(defun my-grok-openlibrary (url)
- "grok openlibrary.
-title, subtitle, description, subjects, authors (by_statement?), classification, publisher, publish_places, publish_date, subjects, cover"
- (when (string-match
- (concat my-openlibrary-host "/books/\\([^/]+\\)") url)
- (my-grok-openlibrary-make-info
- (append
- (my-openlibrary-api-book-by-olid (match-string 1 url))
- (my-openlibrary-html-book-by-url url)))))
-
-(defun my-grok-openlibrary-make-info (info)
- (list
- (cons "Title" (alist-get 'title info))
- (cons "Subtitle" (alist-get 'subtitle info))
- (cons "Authors" (string-join
- (mapcar (lambda (author) (alist-get 'name author))
- (alist-get 'authors info))
- ", "))
- (cons "Pages"
- (when (alist-get 'number_of_pages info)
- (number-to-string (alist-get 'number_of_pages info))))
- (cons "OpenLibrary-link" (alist-get 'url info))
- (cons "OpenLibrary-ID" (string-join (alist-get 'openlibrary info) ","))
- (cons "ISBN" (string-join
- (vconcat
- (alist-get 'isbn_13
- (alist-get 'identifiers info))
- (alist-get 'isbn_10
- (alist-get 'identifiers info)))
- ", "))
- (cons "Dewey-Decimal" (alist-get 'dewey_decimal_class info))
- (cons "Subject" (string-join
- (seq-take
- (remove-duplicates
- (mapcar (lambda (subject) (alist-get 'name subject))
- (alist-get 'subjects info))
- :test 'string=)
- 20)
- ", "))
- (cons "Cover" (alist-get 'large (alist-get 'cover info)))
- (cons "Published" (alist-get 'publish_date info))
- (cons "Description" (alist-get 'description info))))
-
-(defun my-openlibrary-api-book-by-isbn (isbn)
- (my-url-fetch-json
- (format
- "%s/api/books?bibkeys=ISBN:%s&format=json&jscmd=data"
- my-openlibrary-host isbn)))
-
-(defun my-grok-openlibrary-isbn (isbn)
- (unless isbn (error "isbn not supplied"))
- (let* ((info-json (alist-get (intern (format "ISBN:%s" isbn))
- (my-openlibrary-api-book-by-isbn isbn)))
- (url (alist-get 'url info-json))
- (info-html (my-openlibrary-html-book-by-url url)))
- (my-grok-openlibrary-make-info
- (append info-json info-html))))
-
-(defun my-openlibrary-api-search (query)
- (my-url-fetch-json
- (format "%s/search.json?q=%s" my-openlibrary-host query)))
-
-(defun my-openlibrary-format-result (info)
- (format "%s - %s [%s] (%s)"
- (string-join (alist-get 'author_name info) ", ")
- (alist-get 'title info)
- (string-join (alist-get 'isbn info) ",")
- (alist-get 'publish_date info)))
-
-(defun my-openlibrary-action (info)
- (interactive)
- (my-org-create-node
- (my-grok-openlibrary-isbn (elt (alist-get 'isbn info) 0))
- t))
-
-(defun my-openlibrary-show-more-info ()
- (interactive)
- (pp (my-grok-openlibrary-isbn
- (elt
- (alist-get 'isbn (get-text-property (point) 'button-data))
- 0))))
-
-(defvar my-openlibrary-button-keymap
- (let ((kmap (make-sparse-keymap)))
- (set-keymap-parent kmap button-map)
- (define-key kmap "p" 'my-openlibrary-show-more-info)
- kmap))
-
-(defun my-openlibrary-search (query)
- (interactive "sQuery: ")
- (generic-search-open
- (alist-get 'docs (my-openlibrary-api-search query))
- (format "openlibrary-query:%s" query)
- `((formatter . my-openlibrary-format-result)
- (default-action . my-openlibrary-action)
- (keymap . ,my-openlibrary-button-keymap))))
-
-(provide 'my-openlibrary)
-;;; my-openlibrary.el ends here
diff --git a/.emacs.d/lisp/my/my-org.el b/.emacs.d/lisp/my/my-org.el
deleted file mode 100644
index cb72677..0000000
--- a/.emacs.d/lisp/my/my-org.el
+++ /dev/null
@@ -1,1003 +0,0 @@
-;;; my-org.el -- Extensions for org -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for org.
-
-;;; Code:
-
-
-(require 'org)
-
-;;; org mode
-(defun my-org-open-shell-at-attach-dir ()
- (interactive)
- (require 'my-prog)
- (my-shell-with-directory (concat (org-attach-dir-get-create) "/")))
-
-(defun my-org-links-in-entry ()
- "Get all link urls in an entry"
- (save-excursion
- (org-back-to-heading t)
- (let (links
- (end (save-excursion (outline-next-heading) (point))))
- (while (re-search-forward org-link-any-re end t)
- (push
- (org-unbracket-string "<" ">"
- (or
- ;; [[target][desc]]
- (match-string-no-properties 2)
- ;; plain link or <...>
- (match-string-no-properties 0)))
- links))
- links)))
-
-(defun my-org-http-s-links-in-entry ()
- "Get all http(s) urls in an entry"
- (seq-filter (lambda (link)
- (string-prefix-p
- "http"
- (progn (string-match org-link-types-re link)
- (match-string 1 link))))
- (my-org-links-in-entry)))
-
-(defun my-org-insert-date-range (inactive)
- "Insert two dates to form an active date range.
-
-With a prefix, insert inactive dates.
-"
- (interactive "P")
- (org-time-stamp nil inactive)
- (insert "--")
- (org-time-stamp nil inactive))
-
-(defun my-org-follow-link-after ()
- (when (eq major-mode 'mhtml-mode)
- (browse-url-of-buffer)))
-
-;; navigation
-(defun my-org-jump-to-last-visible-child ()
- "Goto the last visible child."
- (interactive)
- (let (level (pos (point)) (re org-outline-regexp-bol))
- (when (ignore-errors (org-back-to-heading t))
- (setq level (outline-level))
- (forward-char 1)
- (while (and (re-search-forward re nil t) (> (outline-level) level))
- (when (and (= (outline-level) (1+ level))
- (not (get-char-property (point) 'invisible)))
- (setq pos (match-beginning 0)))))
- (goto-char pos)))
-
-(defun my-org-entry-toggle-drawer-visibility ()
- (interactive)
- (save-excursion
- (save-restriction
- (org-narrow-to-subtree)
- (goto-char (point-min))
- (when (re-search-forward "^\\s-*:PROPERTIES:" nil t)
- (org-hide-drawer-toggle)))))
-
-(defun my-org-open-default-notes-file ()
- (interactive)
- (find-file org-default-notes-file))
-
-;; links
-(defun my-org-substitute-gnus-link-after-archiving ()
- "Fix a captured gnus article link after they've been archived"
- (interactive)
- (when (org-in-regexp org-link-bracket-re)
- ;; We do have a link at point, and we are going to edit it.
- (save-excursion
- (let ((remove (list (match-beginning 0) (match-end 0)))
- (desc (when (match-end 2) (match-string-no-properties 2)))
- (link (match-string-no-properties 1))
- (target (alist-get 'archive my-gnus-group-default-targets)))
- (pcase-dolist (`(,re . ,info) my-gnus-group-alist)
- (when (and (string-match re link)
- (alist-get 'archive info))
- (setq target (alist-get 'archive info))))
- (setq new-link
- (replace-regexp-in-string "/.*?#" (format "/%s#" target)
- link))
- (apply #'delete-region remove)
- (insert (org-link-make-string new-link desc))
- (sit-for 0)))))
-
-;; editing heading
-(defun my-org-orgzly-merge-link ()
- "Fixes orgzly entries with links separated from headlines.
-Find the first link in the entry, and add that to the headline
-title, and remove the body."
- (interactive)
- (save-restriction
- (save-excursion
- (org-narrow-to-subtree)
- (goto-char (point-min))
- (forward-line)
- (when (re-search-forward org-link-any-re)
- (let ((link (buffer-substring-no-properties
- (match-beginning 0) (match-end 0)))
- (unused (replace-match "" nil))
- (desc (org-entry-get (point) "ITEM"))
- (title-loc))
- (goto-char (point-min))
- (search-forward desc nil t)
- (setq title-loc (match-beginning 0))
- (replace-match "" nil)
- (while (search-forward desc nil t) (replace-match "" nil))
- (goto-char title-loc)
- (insert (org-link-make-string link desc))))))
- (my-org-node-flush-empty-lines))
-
-(defun my-org-node-flush-empty-lines ()
- (save-restriction
- (save-excursion
- (org-narrow-to-subtree)
- (flush-lines "^$"))))
-
-(defun my-org-element-contents-at-point ()
- (let ((element (org-element-at-point)))
- (buffer-substring-no-properties
- (org-element-property :contents-begin element)
- (org-element-property :contents-end element))))
-
-
-(defun my-org-append-subheading (arg)
- "Append a subheading as a first child, or with an arg as a last child."
- (interactive "P")
- (if arg
- (org-insert-subheading '(4))
- (let ((required-level (1+ (or (org-current-level) 0))))
- (org-show-children)
- (org-next-visible-heading 1)
- (org-insert-subheading nil)
- (while (> (org-current-level) required-level)
- (org-promote-subtree))
- (while (< (org-current-level) required-level)
- (org-demote-subtree)))))
-
-;; copy a link
-;;; fixme: do we still need this?
-(defun my-org-copy-link-at-point ()
- (interactive)
- (let ((link (my-org-link-at-point)))
- (if link
- (progn
- (kill-new link)
- (message "Copied: %s" link))
- (message "Point is not an org link!"))))
-
-(defun my-org-link-at-point ()
- (interactive)
- (when (org-in-regexp org-link-any-re)
- (org-unbracket-string "<" ">"
- (or
- ;; [[target][desc]]
- (match-string-no-properties 2)
- ;; plain link or <...>
- (match-string-no-properties 0)))))
-
-(defun my-org-store-link-and-return ()
- "run org-goto to select a heading, stores its link and insert it."
- (interactive)
- (save-restriction
- (widen)
- (save-excursion
- (call-interactively 'org-goto)
- (call-interactively 'org-store-link)))
- (call-interactively 'org-insert-last-stored-link))
-
-;; overload org-insert-all-links (do we need autoload as in the original file?)
-(defun my-org-insert-all-links (arg &optional pre post)
- "Insert all links in `org-stored-links'.
-When a universal prefix, do not delete the links from `org-stored-links'.
-When `ARG' is a number, insert the last N link(s).
-`PRE' and `POST' are optional arguments to define a string to
-prepend or to append."
- (interactive "P")
- (let ((org-link-keep-stored-after-insertion (equal arg '(4)))
- (links (copy-sequence org-stored-links))
- (pr (or pre "- "))
- (po (or post "\n"))
- (cnt 1) l)
- (if (null org-stored-links)
- (message "No link to insert")
- (while (and (or (listp arg) (>= arg cnt))
- (setq l (if (listp arg)
- (pop links)
- (pop org-stored-links))))
- (setq cnt (1+ cnt))
- (insert pr)
- (org-insert-link nil (car l) (or (cadr l) ""))
- (insert po)))))
-
-;; overload org-open-at-point-global to fix bug property link not
-;; opened in external browser (2d0e61c8-da74-417e-8ccd-c4099ccd88d8)
-(defun my-org-open-at-point-global (&optional arg)
- "Follow a link or a time-stamp like Org mode does.
-Also follow links and emails as seen by `thing-at-point'.
-This command can be called in any mode to follow an external
-link or a time-stamp that has Org mode syntax. Its behavior
-is undefined when called on internal links like fuzzy links.
-Raise a user error when there is nothing to follow."
- (interactive "P")
- (let ((tap-url (thing-at-point 'url))
- (tap-email (thing-at-point 'email)))
- (cond ((org-in-regexp org-link-any-re)
- (org-link-open-from-string (match-string-no-properties 0) arg))
- ((or (org-in-regexp org-ts-regexp-both nil t)
- (org-in-regexp org-tsr-regexp-both nil t))
- (org-follow-timestamp-link))
- (tap-url (org-link-open-from-string tap-url))
- (tap-email (org-link-open-from-string
- (concat "mailto:" tap-email)))
- (t (user-error "No link found")))))
-
-;; overload org-refile-get-targets
-(defun my-org-refile-get-targets (&optional default-buffer)
- "Produce a table with refile targets."
- (let ((case-fold-search nil)
- ;; otherwise org confuses "TODO" as a kw and "Todo" as a word
- (entries (or org-refile-targets '((nil . (:level . 1)))))
- targets tgs files desc descre)
- (message "Getting targets...")
- (with-current-buffer (or default-buffer (current-buffer))
- (dolist (entry entries)
- (setq files (car entry) desc (cdr entry))
- (cond
- ((null files) (setq files (list (current-buffer))))
- ((eq files 'org-agenda-files)
- (setq files (org-agenda-files 'unrestricted)))
- ((and (symbolp files) (fboundp files))
- (setq files (funcall files)))
- ((and (symbolp files) (boundp files))
- (setq files (symbol-value files))))
- (when (stringp files) (setq files (list files)))
- (cond
- ((eq (car desc) :tag)
- (setq descre (concat "^\\*+[ \t]+.*?:" (regexp-quote (cdr desc)) ":")))
- ((eq (car desc) :todo)
- (setq descre (concat "^\\*+[ \t]+" (regexp-quote (cdr desc)) "[ \t]")))
- ((eq (car desc) :regexp)
- (setq descre (cdr desc)))
- ((eq (car desc) :level)
- (setq descre (concat "^\\*\\{" (number-to-string
- (if org-odd-levels-only
- (1- (* 2 (cdr desc)))
- (cdr desc)))
- "\\}[ \t]")))
- ((eq (car desc) :maxlevel)
- (setq descre (concat "^\\*\\{1," (number-to-string
- (if org-odd-levels-only
- (1- (* 2 (cdr desc)))
- (cdr desc)))
- "\\}[ \t]")))
- (t (error "Bad refiling target description %s" desc)))
- (dolist (f files)
- (with-current-buffer (if (bufferp f) f (org-get-agenda-file-buffer f))
- (or
- (setq tgs (org-refile-cache-get
- (buffer-file-name
- (when (bufferp f) (buffer-base-buffer f)))
- descre))
- (progn
- (when (bufferp f)
- (setq f (buffer-file-name (buffer-base-buffer f))))
- (setq f (and f (expand-file-name f)))
- (when (eq org-refile-use-outline-path 'file)
- (push (list (and f (file-name-nondirectory f)) f nil nil) tgs))
- (when (eq org-refile-use-outline-path 'buffer-name)
- (push (list (buffer-name (buffer-base-buffer)) f nil nil) tgs))
- (when (eq org-refile-use-outline-path 'full-file-path)
- (push (list (and (buffer-file-name (buffer-base-buffer))
- (file-truename (buffer-file-name (buffer-base-buffer))))
- f nil nil) tgs))
- (org-with-wide-buffer
- (goto-char (point-min))
- (setq org-outline-path-cache nil)
- (while (re-search-forward descre nil t)
- (beginning-of-line)
- (let ((case-fold-search nil))
- (looking-at org-complex-heading-regexp))
- (let ((begin (point))
- (heading (match-string-no-properties 4)))
- (unless (or (and
- org-refile-target-verify-function
- (not
- (funcall org-refile-target-verify-function)))
- (not heading))
- (let ((re (format org-complex-heading-regexp-format
- (regexp-quote heading)))
- (target
- (if (not org-refile-use-outline-path) heading
- (mapconcat
- #'identity
- (append
- (pcase org-refile-use-outline-path
- (`file (list
- (and (buffer-file-name (buffer-base-buffer))
- (file-name-nondirectory
- (buffer-file-name (buffer-base-buffer))))))
- (`full-file-path
- (list (buffer-file-name
- (buffer-base-buffer))))
- (`buffer-name
- (list (buffer-name
- (buffer-base-buffer))))
- (_ nil))
- (mapcar (lambda (s) (replace-regexp-in-string
- "/" "\\/" s nil t))
- (org-get-outline-path t t)))
- "/"))))
- (push (list target f re (org-refile-marker (point)))
- tgs)))
- (when (= (point) begin)
- ;; Verification function has not moved point.
- (end-of-line)))))))
- (when org-refile-use-cache
- (org-refile-cache-put tgs (buffer-file-name) descre))
- (setq targets (append tgs targets))))))
- (message "Getting targets...done")
- (delete-dups (nreverse targets))))
-
-;; shadow org-insert-last-stored-link (do not insert \n at the end)
-(defun my-org-insert-last-stored-link (arg)
- "Insert the last link stored in `org-stored-links'."
- (interactive "p")
- (org-insert-all-links arg "" ""))
-
-(defun my-org-info-open-new-window (path)
- "Open info in a new buffer"
- (my-select-new-window-matching-mode 'Info-mode)
- (org-info-follow-link path))
-
-(defun my-org-rt-open-new-window (path)
- "Open rt in a new buffer"
- (my-select-new-window-matching-mode 'rt-liber-browser-mode)
- (rt-org-open path))
-
-;; fix org src overlay face
-(defun my-org-src--make-source-overlay (beg end edit-buffer)
- "Create overlay between BEG and END positions and return it.
-EDIT-BUFFER is the buffer currently editing area between BEG and
-END."
- (let ((overlay (make-overlay beg end)))
- (overlay-put overlay 'face 'region)
- (overlay-put overlay 'edit-buffer edit-buffer)
- (overlay-put overlay 'help-echo
- "Click with mouse-1 to switch to buffer editing this segment")
- (overlay-put overlay 'face 'region)
- (overlay-put overlay 'keymap
- (let ((map (make-sparse-keymap)))
- (define-key map [mouse-1] 'org-edit-src-continue)
- map))
- (let ((read-only
- (list
- (lambda (&rest _)
- (user-error
- "Cannot modify an area being edited in a dedicated buffer")))))
- (overlay-put overlay 'modification-hooks read-only)
- (overlay-put overlay 'insert-in-front-hooks read-only)
- (overlay-put overlay 'insert-behind-hooks read-only))
- overlay))
-
-(defun my-org-copy-property-value (name)
- (interactive
- (list (completing-read "Copy property: " (org-entry-properties))))
- (let ((value (org-entry-get (point) name)))
- (kill-new value)
- (message "Copied %s" value)))
-
-(defvar my-org-common-properties nil
- "Property list for completion when setting the property of an org node, to
- avoid scanning the whole notes.")
-
-(defun my-org-set-common-property ()
- (interactive)
- (let* ((property
- (completing-read "Which property to set: "
- my-org-common-properties))
- (value
- (org-read-property-value property)))
- (org-set-property property value)))
-
-(defun my-org-copy-src-block-at-point ()
- (interactive)
- (when (org-in-src-block-p)
- (kill-new (nth 1 (org-babel-get-src-block-info t)))
- (message "org src block copied!")))
-(defun my-org-in-or-at-block-p ()
- (or (org-at-block-p)
- (org-in-block-p '("example" "source" "export"
- "center" "quote" "verse"))))
-(defun my-org-copy-block-at-point ()
- (interactive)
- (save-excursion
- (unless (org-at-block-p)
- (org-previous-block 1)
- (let ((element (org-element-at-point)))
- (kill-new (or
- (org-element-property :value element)
- (buffer-substring
- (org-element-property :contents-begin element)
- (org-element-property :contents-end element))))
- (message "org block copied!")))))
-
-;; clock save timer doesn't seem to be working
-(defun my-org-clock-maybe-save ()
- (when (equal major-mode 'org-mode)
- (org-clock-save)))
-
-(defun my-org-refile-cache-rebuild ()
- (org-refile-cache-clear)
- (org-refile-get-targets))
-
-(defun my-org-store-agenda-view-A ()
- (interactive)
- (org-store-agenda-views)
- (my-org-agenda-ensure-A))
-
-(defun my-org-agenda-priority-0 ()
- (interactive)
- (org-agenda-priority ?\ ))
-(defun my-org-agenda-priority-A ()
- (interactive)
- (org-agenda-priority ?A))
-(defun my-org-agenda-priority-B ()
- (interactive)
- (org-agenda-priority ?B))
-(defun my-org-agenda-priority-C ()
- (interactive)
- (org-agenda-priority ?C))
-
-(defun my-org-next-block-or-results (arg &optional backward)
- "Jump to the next block or results.
-
-With a prefix argument ARG, jump forward ARG many blocks.
-
-When BACKWARD is non-nil, jump to the previous block.
-
-When BLOCK-REGEXP is non-nil, use this regexp to find blocks.
-Match data is set according to this regexp when the function
-returns.
-
-Return point at beginning of the opening line of found block.
-Throw an error if no block is found."
- (interactive "p")
- (let ((re "^[ \t]*#\\+\\(BEGIN\\|RESULTS:\\)")
- (case-fold-search t)
- (search-fn (if backward #'re-search-backward #'re-search-forward))
- (count (or arg 1))
- (origin (point))
- last-element)
- (if backward (beginning-of-line) (end-of-line))
- (while (and (> count 0) (funcall search-fn re nil t))
- (let ((element (save-excursion
- (goto-char (match-beginning 0))
- (save-match-data (org-element-at-point)))))
- (when (and (memq (org-element-type element)
- '(center-block comment-block dynamic-block
- example-block export-block quote-block
- special-block src-block verse-block fixed-width))
- (<= (match-beginning 0)
- (org-element-property :post-affiliated element)))
- (setq last-element element)
- (cl-decf count))))
- (if (= count 0)
- (prog1 (goto-char (org-element-property :post-affiliated last-element))
- (save-match-data (org-show-context)))
- (goto-char origin)
- (user-error "No %s code blocks" (if backward "previous" "further")))))
-
-(defun my-org-previous-block-or-results (arg)
- "Jump to the previous block or results.
-With a prefix argument ARG, jump backward ARG many source blocks.
-When BLOCK-REGEXP is non-nil, use this regexp to find blocks."
- (interactive "p")
- (my-org-next-block-or-results arg t))
-
-;; override org-next-link to include search in any places, including property
-;; drawers.
-;; TODO: not working yet
-;; https://lists.gnu.org/archive/html/emacs-orgmode/2020-01/msg00186.html
-(defun my-org-next-link ()
- (interactive)
- (when (org-in-regexp org-any-link-re)
- (re-search-forward org-any-link-re nil t))
- (re-search-forward org-any-link-re nil t)
- (re-search-backward org-any-link-re nil t)
- (when-let ((link (org-element-lineage (org-element-context) '(link) t)))
- (goto-char (org-element-property :begin link)))
- (when (org-invisible-p) (org-show-context)))
-
-(defun my-org-previous-link ()
- (interactive)
- (re-search-backward org-any-link-re nil t)
- (when-let ((link (org-element-lineage (org-element-context) '(link) t)))
- (goto-char (org-element-property :begin link)))
- (when (org-invisible-p) (org-show-context)))
-
-(defun my-org-attach-edit-attached-image ()
- (interactive)
- (start-process
- "pinta" nil "/usr/bin/pinta"
- (concat (org-attach-dir) "/"
- (org-element-property :path (org-element-context)))))
-
-(defun my-org-capture-place-template-dont-delete-windows (oldfun args)
- (cl-letf (((symbol-function 'delete-other-windows) 'ignore))
- (apply oldfun args)))
-
-(defvar my-org-attach-copy-attached-targets nil
- "Alist of targets to copy attached to, in the form of (name . path)")
-(defvar my-org-attach-copy-attached-doc-exts
- '("epub" "pdf" "mobi"))
-(defvar my-org-attach-copy-attached-doc-re
- (format "\\.\\(%s\\)$"
- (string-join
- my-org-attach-copy-attached-doc-exts "\\|")))
-
-(defun my-org-attach-copy-attached-docs ()
- (interactive)
- (let* ((name
- (completing-read "Copy attached docs to: "
- my-org-attach-copy-attached-targets))
- (path (alist-get name my-org-attach-copy-attached-targets
- nil nil #'equal)))
- (let ((basedir (org-attach-dir)))
- (dolist (attached (org-attach-file-list basedir))
- (when (string-match my-org-attach-copy-attached-doc-re attached)
- (message "Copying %s to %s (%s)..." attached name path)
- (copy-file (file-name-concat basedir attached)
- (file-name-concat
- path
- (replace-regexp-in-string ":" "_" attached)))
- (message "Done!")))))
- )
-
-(defun my-org-attach-all-url-plaintext (arg)
- (interactive "P")
- (dolist (url (my-org-http-s-links-in-entry))
- (my-org-attach-url-plaintext url)))
-
-(defun my-org-attach-url-plaintext (url)
- (interactive (list (completing-read "Url to fetch: " (my-org-http-s-links-in-entry))))
- (my-org-attach-url-plaintext-internal url current-prefix-arg t))
-
-(defun my-org-attach-url-plaintext-all-media (url)
- (interactive (list (completing-read "Url to fetch: "
- (my-org-http-s-links-in-entry))))
- (my-org-attach-url-plaintext-internal url current-prefix-arg t t))
-
-(defun my-org-attach-url (url)
- (interactive (list (completing-read "Url to fetch: "
- (my-org-http-s-links-in-entry))))
- (let* ((url (my-rewrite-url url))
- (filename (expand-file-name (my-make-filename-from-url url)
- (org-attach-dir t))))
- (my-wget-async url filename current-prefix-arg)))
-
-(defun my-org-attach-url-plaintext-internal (url &optional no-tor move-if-large save-all-media)
- (let* ((lynx-buffer (format "*lynx %s*" url))
- (url (my-rewrite-url url))
- (filename (expand-file-name (my-make-filename-from-url url)
- (org-attach-dir t)))
- (coding-system-for-write 'utf-8))
- (ignore-errors (kill-buffer lynx-buffer))
- (my-touch-new-file filename)
- (org-attach-sync)
- (set-process-sentinel
- (my-start-process-with-torsocks
- current-prefix-arg
- "org-lynx" lynx-buffer "lynx" "-dump" "--display_charset" "utf-8" url)
- (lambda (process event)
- (with-current-buffer (process-buffer process)
- (goto-char (point-min))
- (write-file filename)
- (message "Lynx dumped to: %s" filename)
- (when save-all-media
- (when-let ((urls (http-s-media-links-in-buffer)))
- (message "Downloading %d media files..." (length urls))
- (wget-async-urls-with-prefix
- urls (concat filename "-") no-tor move-if-large))))))))
-
-;; node creation; start of grok
-;; FIXME: decouple clients from org
-(defun my-org-create-node (info &optional attach)
- (cond ((alist-get "Authors" info nil nil 'string=)
- (my-org-create-book-node info attach))
- ((alist-get "Director" info nil nil 'string=)
- (my-org-create-video-node info attach))
- ((and (alist-get "Developers" info nil nil 'string=)
- (string-match "\\<game\\>"
- (alist-get "Description" info nil nil 'string=)))
- (my-org-create-video-game-node info attach))
- ((alist-get "Developers" info nil nil 'string=)
- (my-org-create-software-node info attach))
- ((alist-get "Designers" info nil nil 'string=)
- (my-org-create-game-node info attach))
- ((alist-get "Founded" info nil nil 'string=)
- (my-org-create-organisation-node info attach))
- ((alist-get "Latitude" info nil nil 'string=)
- (my-org-create-location-node info attach))
- ((alist-get "Born" info nil nil 'string=)
- (my-org-create-people-node info attach))
- (t (my-org-create-entity-node info attach))))
-
-(defun my-org-attach-and-add-properties-to-node (info attach)
- (when (and attach (alist-get "Cover" info nil nil 'string=))
- (ignore-error 'file-already-exists
- (org-attach-url (alist-get "Cover" info nil nil 'string=)))
- (setq info (assoc-delete-all "Cover" info 'string=)))
- (dolist (pair info)
- (when (and (cdr pair) (string> (cdr pair) ""))
- (org-entry-put (point)
- (decode-coding-string (car pair) 'utf-8)
- (decode-coding-string (cdr pair) 'utf-8))))
- (org-entry-put (point) "CREATED"
- (format-time-string "[%Y-%m-%d %a %H:%M]" (current-time)))
- (org-attach-sync)
- (when (buffer-narrowed-p)
- (goto-char (point-min))))
-
-(defun my-org-create-book-node (book-info attach)
- (org-capture nil "book")
- (insert (format
- "%s - %s - %s"
- (or (alist-get "Authors" book-info "" nil 'string=) "")
- (alist-get "Title" book-info "" nil 'string=)
- (my-extract-year
- (alist-get "Published" book-info "" nil 'string=))))
- (my-org-attach-and-add-properties-to-node book-info attach))
-(defun my-org-create-video-node (video-info attach)
- (org-capture nil "video")
- (insert (format
- "%s - %s - %s"
- (alist-get "Director" video-info "" nil 'string=)
- (alist-get "Title" video-info "" nil 'string=)
- (my-extract-year
- (alist-get "Released" video-info "" nil 'string=))))
- (my-org-attach-and-add-properties-to-node video-info attach))
-(defun my-org-create-location-node (book-info attach)
- (org-capture nil "location")
- (insert (format
- "%s"
- (alist-get "Title" book-info "" nil 'string=)))
- (my-org-attach-and-add-properties-to-node book-info attach))
-(defun my-org-create-game-node (game-info attach)
- (org-capture nil "game")
- (insert (format
- "%s - %s - %s"
- (alist-get "Designers" game-info "" nil 'string=)
- (alist-get "Title" game-info "" nil 'string=)
- (my-extract-year
- (alist-get "Published" game-info "" nil 'string=))))
- (my-org-attach-and-add-properties-to-node game-info attach))
-(defun my-org-create-video-game-node (game-info attach)
- (org-capture nil "videogame")
- (insert (format
- "%s - %s - %s"
- (alist-get "Developers" game-info "" nil 'string=)
- (alist-get "Title" game-info "" nil 'string=)
- (my-extract-year
- (alist-get "Released" game-info "" nil 'string=))))
- (my-org-attach-and-add-properties-to-node game-info attach))
-(defun my-org-create-software-node (software-info attach)
- (org-capture nil "software")
- (insert (format
- "%s - %s"
- (alist-get "Title" software-info "" nil 'string=)
- (my-extract-year
- (alist-get "Released" software-info "" nil 'string=))))
- (my-org-attach-and-add-properties-to-node software-info attach))
-(defun my-org-create-organisation-node (organisation-info attach)
- (org-capture nil "organisation")
- (insert (format
- "%s - %s"
- (alist-get "Title" organisation-info "" nil 'string=)
- (my-extract-year
- (alist-get "Founded" organisation-info "" nil 'string=))))
- (my-org-attach-and-add-properties-to-node organisation-info attach))
-(defun my-org-create-people-node (people-info attach)
- (org-capture nil "people")
- (insert (format
- "%s - %s-%s"
- (alist-get "Title" people-info "" nil 'string=)
- (my-extract-year (alist-get "Born" people-info "" nil 'string=))
- (my-extract-year (alist-get "Died" people-info "" nil 'string=))))
- (my-org-attach-and-add-properties-to-node people-info attach))
-(defun my-org-create-pacman-software-node (package)
- (interactive "sPacman package name: ")
- (my-org-create-software-node (my-grok-pacman package) nil))
-(defun my-org-create-entity-node (entity-info attach)
- (org-capture nil "entity")
- (insert (format
- "%s"
- (alist-get "Title" entity-info "" nil 'string=)))
- (my-org-attach-and-add-properties-to-node entity-info attach))
-(defun my-org-create-audio-node (audio-info attach)
- (org-capture nil "ya")
- (insert (format
- "%s - %s - %s"
- (or (alist-get "Authors" audio-info "" nil 'string=) "")
- (alist-get "Title" audio-info "" nil 'string=)
- (my-extract-year
- (alist-get "Published" audio-info "" nil 'string=))))
- (my-org-attach-and-add-properties-to-node audio-info attach))
-
-;; TODO: these requires are unnecessary for more essential functionalities of
-;; org customisation. Find a way to delay them
-(require 'my-wikipedia)
-(require 'my-github)
-(require 'my-gitlab)
-(require 'my-pacman)
-(require 'my-openlibrary)
-(defun my-grok-dispatcher (url)
- (when-let ((host (url-host (url-generic-parse-url url))))
- (cond ((string-match "wikipedia\\.org" host) 'my-grok-wikipedia)
- ((string-match "github\\.com" host) 'my-grok-github)
- ((string-match "\\(gitlab\\.\\|salsa.debian.org\\)" host)
- 'my-grok-gitlab)
- ((string-match "openlibrary.org" host) 'my-grok-openlibrary)
- (t nil))))
-(defun my-grok-update-properties ()
- (interactive)
- (when-let* ((url (org-entry-get (point) "Source"))
- (source-dispatcher (my-grok-dispatcher url)))
- (my-org-attach-and-add-properties-to-node
- (funcall source-dispatcher url) t))
- (when-let ((isbn (org-entry-get (point) "ISBN")))
- (my-org-attach-and-add-properties-to-node (my-grok-openlibrary-isbn isbn) t))
- (when-let ((url (org-entry-get (point) "OpenLibrary-link")))
- (my-org-attach-and-add-properties-to-node (my-grok-openlibrary url) t))
- (when-let ((package (org-entry-get (point) "Pacman-package-name")))
- (my-org-attach-and-add-properties-to-node (my-grok-pacman package) nil))
- (when-let ((url (org-entry-get (point) "Wikipedia-link")))
- (my-org-attach-and-add-properties-to-node (my-grok-wikipedia url) t)))
-(defun my-org-protocol-grok (data)
- (when-let ((url (plist-get data :url)))
- (my-org-grok url))
- nil)
-
-(defun my-org-grok (url)
- (when-let* ((grok-fun (my-grok-dispatcher url))
- (info (funcall grok-fun url)))
- (my-org-create-node info t)))
-
-(defun my-eww-org-protocol-grok ()
- "grok from eww"
- (interactive)
- (org-protocol-grok
- (list :url (plist-get eww-data :url))))
-
-;; org capture rss
-(defun my-org-rss-xml-create-audio-node (url)
- (interactive (list (read-string "Feed URL: "
- (thing-at-point-url-at-point))))
- (my-org-rss-xml-create-node url 'my-org-create-audio-node))
-(defun my-org-rss-xml-create-book-node (url)
- (interactive (list (read-string "Feed URL: "
- (thing-at-point-url-at-point))))
- (my-org-rss-xml-create-node url 'my-org-create-book-node))
-(defun my-org-rss-xml-create-node (url create-node-fun)
- (let* ((xml
- (with-current-buffer (url-retrieve-synchronously url)
- (my-skip-http-header)
- (car (xml-parse-region (point) (point-max)))))
- (channel (my-xml-get-first-child xml 'channel))
- )
- (funcall create-node-fun
- (list
- (cons "Feed-url" url)
- (cons "Title" (decode-coding-string
- (my-xml-get-first-child-text channel 'title) 'utf-8))
- (cons "Description"
- (decode-coding-string
- (my-xml-get-first-child-text channel 'description) 'utf-8))
- (cons "Website" (my-xml-get-first-child-text channel 'link))
- (cons "Cover"
- (or (my-xml-get-first-child-text
- (my-xml-get-first-child channel 'image) 'url)
- (dom-attr
- (my-xml-get-first-child channel 'itunes:image) 'href)))
- (cons "Authors" (my-xml-get-first-child-text
- channel 'itunes:author)))
- t)))
-
-(require 'my-algo)
-(defun my-radix-org-from-tree (tree)
- (let ((radix-tree-type 'vector))
- (radix-tree-iter-subtrees
- tree
- (my-radix-org-iter-n 1 []))))
-
-(defun my-radix-org-iter-n (depth prefix)
- (lambda (p s)
- (let ((nprefix (seq-concatenate radix-tree-type prefix p)))
- (insert (make-string depth ?*) " ")
- (pcase s
- ((radix-tree-leaf v) (insert "[[" (string-join nprefix "/") "][" (string-join p "/") "]]" "\n"))
- (_
- (insert (string-join p "/") "\n")
- (radix-tree-iter-subtrees s (my-radix-org-iter-n (1+ depth) nprefix)))))))
-
-(defun my-radix-org ()
- (interactive)
- (let* ((file-name (buffer-file-name))
- (buffer-name (file-name-with-extension
- (file-name-base file-name)
- "org"))
- (save-file-name (file-name-with-extension file-name "org"))
- (tree (let ((max-lisp-eval-depth 32000))
- (save-excursion (my-radix-tree-from-list)))))
- (with-current-buffer (get-buffer-create buffer-name)
- (org-mode)
- (erase-buffer)
- (my-radix-org-from-tree tree)
- (goto-char (point-min)))
- (switch-to-buffer buffer-name)))
-
-;;; format org mode elements
-(defun my-org-format-link (url text)
- (format "[[%s][%s]]" url text))
-
-(defun my-org-format-heading (text level)
- (format "%s %s"
- (make-string level ?*) text))
-
-(defun my-org-update-updated ()
- (interactive)
- (when (derived-mode-p 'org-mode)
- (org-entry-put
- (point) "UPDATED"
- (format-time-string "[%Y-%m-%d %a %H:%M]" (current-time)))))
-
-;;; override org-recoll-format-results
-(defun my-org-recoll-format-results ()
- (require 'org-recoll)
- "Format recoll results in buffer."
- ;; Format results in org format and tidy up
- (org-recoll-regexp-replace-in-buffer
- "^.*?\\[\\(.*?\\)\\]\\s-*\\[\\(.*?\\)\\]\\(.*\\)$"
- "* [[\\1][\\2]] <\\1>\\3")
- (org-recoll-regexp-replace-in-buffer
- (format "<file://.*?%s\\(.*/\\).*>" (substring my-docs-root-dir 1))
- "(\\1)")
- (org-recoll-regexp-replace-in-buffer "\\/ABSTRACT" "")
- (org-recoll-regexp-replace-in-buffer "ABSTRACT" "")
- ;; Justify results
- (goto-char (point-min))
- (org-recoll-fill-region-paragraphs)
- ;; Add emphasis
- (highlight-phrase (org-recoll-reformat-for-file-search
- org-recoll-search-query)
- 'bold-italic))
-
-(defun my-org-recoll-mdn (query)
- (interactive "sSearch mdn: ")
- (org-recoll-search (format "%s dir:mdn" query)))
-
-(defun my-org-recoll-python (query)
- (interactive "sSearch python: ")
- (org-recoll-search (format "%s dir:python-3.9.7-docs-html" query)))
-
-(defun my-org-recoll-php (query)
- (interactive "sSearch php: ")
- (org-recoll-search (format "%s dir:php-chunked-xhtml" query)))
-
-(defun my-org-recoll-yesod (query)
- (interactive "sSearch yesod: ")
- (org-recoll-search (format "%s dir:yesod-cookbook OR dir:yesodweb.com" query)))
-
-(defun my-org-entry-at-point-to-tsv (id)
- (string-join
- (cons (number-to-string id)
- (mapcar
- (lambda (key) (org-entry-get (point) key))
- (list "ITEM" "Referral" "Wikipedia-link" "IMDB-link")))
- "\t"))
-
-(defvar org-entries-tsv-buffer "*org-entries-tsv*")
-(defun my-org-entries-at-point-to-tsv (beg end)
- (interactive "r")
- (with-current-buffer (get-buffer-create org-entries-tsv-buffer)
- (erase-buffer))
- (let ((row) (id 0))
- (save-excursion
- (goto-char beg)
- (while (< (point) end)
- (when (equal (org-entry-get (point) "TODO") "TODO")
- (setq row (my-org-entry-at-point-to-tsv id))
- (with-current-buffer org-entries-tsv-buffer
- (insert row "\n"))
- (setq id (1+ id)))
- (org-next-visible-heading 1))))
- (switch-to-buffer-other-window org-entries-tsv-buffer))
-
-(defun my-org-entries-attach-plaintext-all-media (beg end)
- (interactive "r")
- (save-excursion
- (goto-char beg)
- (while (< (point) end)
- (my-org-attach-url-plaintext-all-media (car (my-org-http-s-links-in-entry)))
- (org-next-visible-heading 1))))
-
-(defvar my-org-doc-dir nil "Directory to docs written in org.")
-(defun my-org-open-org-doc (filename)
- (interactive
- (list
- (completing-read
- "Open org doc: "
- (mapcar (lambda (name) (substring name (length my-org-doc-dir)))
- (directory-files-recursively my-org-doc-dir "\\.org$")))))
- (find-file (concat my-org-doc-dir filename)))
-
-(defun my-org-open-org-file (filename)
- (interactive
- (list
- (completing-read
- "Open org file: "
- (directory-files org-directory nil "\\.org$"))))
- (find-file (file-name-concat org-directory filename)))
-
-(defun my-org-agenda-after-show () (beginning-of-line 1))
-
-(defun my-org-agenda-ensure-A ()
- (org-agenda nil "A")
- (unless (get-text-property (point) 'org-series-redo-cmd)
- (kill-buffer)
- (org-agenda nil "A")))
-
-(defun my-org-agenda-redo-all ()
- (interactive)
- (message "time now is %s"
- (format-time-string "%Y-%m-%d %a %H:%M:%S" (current-time)))
- (my-org-agenda-ensure-A)
- (dolist (buffer (buffer-list))
- (with-current-buffer buffer
- (when (derived-mode-p 'org-agenda-mode)
- (print buffer)
- (org-agenda-redo t)))))
-
-(defun my-org-copy-dwim ()
- (interactive)
- (cond ((org-in-src-block-p)
- (my-org-copy-src-block-at-point))
- ((my-org-in-or-at-block-p) (my-org-copy-block-at-point))
- (t (org-refile-copy))))
-
-;; to override `org--mouse-open-at-point' - we don't want
-;; `org-open-at-point' to toggle a checkbox when point is at the
-;; beginning of a link
-(defun my-org--mouse-open-at-point (orig-fun &rest args)
- (let ((context (org-context)))
- (cond
- ((assq :headline-stars context) (org-cycle))
- ((assq :item-bullet context)
- (let ((org-cycle-include-plain-lists t)) (org-cycle)))
- ((org-footnote-at-reference-p) nil)
- (t (apply orig-fun args)))))
-
-(provide 'my-org)
-;;; my-org.el ends here
diff --git a/.emacs.d/lisp/my/my-osm.el b/.emacs.d/lisp/my/my-osm.el
deleted file mode 100644
index 6c3b607..0000000
--- a/.emacs.d/lisp/my/my-osm.el
+++ /dev/null
@@ -1,56 +0,0 @@
-;;; my-osm.el -- Extensions for osm.el -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for osm.el.
-
-;;; Code:
-
-
-
-(defun my-org-osm-goto ()
- (interactive)
- (when-let ((lat (string-to-number (org-entry-get (point) "Latitude")))
- (lon (string-to-number (org-entry-get (point) "Longitude"))))
- (osm-goto lat lon 17)))
-
-(defun my-osm-org-add-properties ()
- "find the latest osm buffer, and add the lon and lat to the current org node."
- (interactive)
- (let ((lat) (lon))
- (with-current-buffer
- (window-buffer
- (cl-find-if (lambda (window)
- (with-current-buffer (window-buffer window)
- (equal major-mode 'osm-mode)))
- (window-list)))
- (setq lat (osm--lat) lon (osm--lon)))
- (org-entry-put (point) "Latitude" (number-to-string lat))
- (org-entry-put (point) "Longitude" (number-to-string lon))))
-
-(defun my-osm-show-center ()
- (interactive)
- (osm--put-transient-pin 'osm-center osm--x osm--y "Center"))
-
-(provide 'my-osm)
-;;; my-osm.el ends here
diff --git a/.emacs.d/lisp/my/my-package.el b/.emacs.d/lisp/my/my-package.el
deleted file mode 100644
index 1f35a5e..0000000
--- a/.emacs.d/lisp/my/my-package.el
+++ /dev/null
@@ -1,263 +0,0 @@
-;;; my-package.el -- Package related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Protesilaos Stavrou <info@protesilaos.com>
-;; Maintainer: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Package related extensions for emacs core.
-
-;;; Code:
-
-
-;;; Needed by `my-keybind' for barebone profiles like "emms".
-(require 'cl-lib)
-;;; Much of the following is adapted from prot-dotfiles
-(defcustom my-omit-packages nil
- "List of package names to not load.
-This instructs the relevant macros to not `require' the given
-package."
- :group 'my
- :type '(repeat symbol))
-
-(defcustom my-allowed-packages nil
- "List of package names to load.
-This instructs the relevant macros to not `require' packages not
-in this list. Nil means all packages can be required."
- :group 'my
- :type '(repeat symbol))
-
-(defun my-package-install (package &optional method)
- "Install PACKAGE with optional METHOD.
-
-If METHOD is nil or the `builtin' symbol, PACKAGE is not
-installed as it is considered part of Emacs.
-
-If METHOD is any non-nil value, install PACKAGE using
-`package-install'."
- (unless (or (eq method 'builtin) (null method))
- (unless (package-installed-p package)
- (unless package-archive-contents
- (package-refresh-contents))
- (package-install package))))
-
-(defmacro my-package (package &rest body)
- "Require PACKAGE with BODY configurations.
-
-PACKAGE is an unquoted symbol that is passed to `require'. It
-thus conforms with `featurep'.
-
-BODY consists of ordinary Lisp expressions. There are,
-nevertheless, two unquoted plists that are treated specially:
-
-1. (:install METHOD)
-2. (:delay NUMBER)
-
-These plists can be anywhere in BODY and are not part of its
-final expansion.
-
-The :install property is the argument passed to
-`my-package-install' and has the meaning of METHOD
-described therein.
-
-The :delay property makes the evaluation of PACKAGE with the
-expanded BODY happen with `run-with-timer'.
-
-Also see `my-configure'."
- (declare (indent 1))
- (when (or (not my-allowed-packages)
- (memq package my-allowed-packages))
- (unless (memq package my-omit-packages)
- (let (install delay)
- (dolist (element body)
- (when (let ((len (proper-list-p element)))
- (and len (zerop (% len 2))))
- (pcase (car element)
- (:install (setq install (cdr element)
- body (delq element body)))
- (:delay (setq delay (cadr element)
- body (delq element body))))))
- (let ((common `(,(when install
- `(my-package-install ',package ,@install))
- (require ',package)
- ,@body
- )))
- (cond
- ((featurep package)
- `(progn ,@body))
- (delay
- `(run-with-timer ,delay nil (lambda () ,@(delq nil common))))
- (t
- `(progn ,@(delq nil common)))))))))
-
-(defmacro my-keybind (keymap &rest definitions)
- "Expand key binding DEFINITIONS for the given KEYMAP.
-DEFINITIONS is a sequence of string and command pairs."
- (declare (indent 1))
- (unless (zerop (% (length definitions) 2))
- (error "Uneven number of key+command pairs"))
- (let ((keys (seq-filter #'stringp definitions))
- ;; We do accept nil as a definition: it unsets the given key.
- (commands (seq-remove #'stringp definitions)))
- `(when-let (((keymapp ,keymap))
- (map ,keymap))
- ,@(mapcar
- (lambda (pair)
- (unless (and (null (car pair))
- (null (cdr pair)))
- `(define-key map (kbd ,(car pair)) ,(cdr pair))))
- (cl-mapcar #'cons keys commands)))))
-
-(defmacro my-configure (&rest body)
- "Evaluate BODY as a `progn'.
-BODY consists of ordinary Lisp expressions. The sole exception
-is an unquoted plist of the form (:delay NUMBER) which evaluates
-BODY with NUMBER seconds of `run-with-timer'.
-
-Note that `my-configure' does not try to autoload
-anything. Use it only for forms that evaluate regardless.
-
-Also see `my-package'."
- (declare (indent 0))
- (let (delay)
- (dolist (element body)
- (when (let ((len (proper-list-p element)))
- (and len (zerop (% len 2))))
- (pcase (car element)
- (:delay (setq delay (cadr element)
- body (delq element body))))))
- (if delay
- `(run-with-timer ,delay nil (lambda () ,@body))
- `(progn ,@body))))
-
-(defvar my-local-config-file
- (locate-user-emacs-file "local-config")
- "Local emacs-lisp-data config file for machine-specific and personal
- information. The content of the file should be an alist of (var-name
- . var-value)")
-
-(defun my-read-local-config ()
- "Read local-config.
-
-Read from `my-local-config-file' into `local-config'."
- (interactive)
- (setq my-local-config
- (with-temp-buffer
- (insert-file-contents my-local-config-file)
- (read (current-buffer)))))
-
-(defmacro my-setq-from-local (&rest var-names)
- "Set variables with values from `local-config'.
-
-Does not set variables that do not appear in `local-config'.
-Note that symbols or list values in `local-config' need to be
-quoted."
- (cons 'setq
- (mapcan
- (lambda (var-name)
- (when-let ((pair (assoc `,var-name my-local-config)))
- `(,(car pair) ',(cdr pair))))
- var-names)))
-
-(defmacro my-setq-from-local-1 (&rest var-names)
- "Update the local config before calling `my-setq-from-local'"
- `(progn (my-read-local-config)
- (my-setq-from-local ,@var-names)))
-
-(defmacro my-get-from-local (var-name)
- "Get the value of a variable from `local-config'"
- `(alist-get ',var-name my-local-config))
-
-(defmacro my-get-from-local-1 (var-name)
- "Update the local config before calling `my-get-from-local'"
- `(progn (my-read-local-config)
- (my-get-from-local ,var-name)))
-
-(defmacro my-override (func-name)
- "Override a function named foo with a function named my-foo"
- `(advice-add ',func-name :override #',(intern (format "my-%s" func-name))))
-
-(defmacro my-server-idle-timer (var-name secs repeat function)
- "Create an idle timer if we are in an emacsclient.
-
-The timer has name VAR-NAME. If there is an existing time with the
-same name, cancel that one first."
-
- `(when (my-server-p)
- (when (and (boundp ',var-name) (timerp ,var-name))
- (cancel-timer ,var-name))
- (setq ,var-name (run-with-idle-timer ,secs ,repeat ,function))))
-
-(defmacro my-server-timer (var-name secs repeat function)
- "Create a timer if we are in an emacsclient.
-
-The timer has name VAR-NAME. If there is an existing time with the
-same name, cancel that one first."
-
- `(when (my-server-p)
- (when (and (boundp ',var-name) (timerp ,var-name))
- (cancel-timer ,var-name))
- (setq ,var-name (run-with-timer ,secs ,repeat ,function))))
-
-(defun my-describe-package-from-url (url)
- (interactive "sUrl: ")
- (when (string-match
- "\\b\\(?:elpa.gnu.org/packages/\\|elpa.gnu.org/devel/\\|elpa.nongnu.org/nongnu/\\)\\(.*\\).html"
- url)
- (describe-package (intern (match-string 1 url)))))
-
-(defun my-generate-local-config ()
- "Generate a local config and insert it to a buffer named *local-config*"
- (with-current-buffer (get-buffer-create "*local-config*")
- (erase-buffer)
- (insert
- (pp
- (seq-map
- (lambda (var)
- (cons var (when (boundp var) (symbol-value var))))
- (seq-uniq
- (my-collect-my-setqd-vars
- (with-temp-buffer
- (insert "(progn ")
- (dolist (el (directory-files "~/.emacs.d/init" t
- directory-files-no-dot-files-regexp))
- (insert-file-contents el)
- (goto-char (point-max)))
- (insert ")")
- (goto-char (point-min))
- (read (current-buffer))
- )))))))
- (pop-to-buffer "*local-config*")
- )
-
-(defun my-collect-my-setqd-vars (xs)
- "Collect vars that have been `my-setq-from-local''d"
- (cond
- ((not (listp xs)) nil)
- ((not xs) nil)
- ((eq (car xs) 'my-setq-from-local)
- (cdr xs))
- (t (append (my-collect-my-setqd-vars (car xs))
- (my-collect-my-setqd-vars (cdr xs))))))
-
-(provide 'my-package)
-;;; my-package.el ends here
diff --git a/.emacs.d/lisp/my/my-pacman.el b/.emacs.d/lisp/my/my-pacman.el
deleted file mode 100644
index 01cbfdd..0000000
--- a/.emacs.d/lisp/my/my-pacman.el
+++ /dev/null
@@ -1,46 +0,0 @@
-;;; my-pacman.el -- pacman client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; pacman client.
-
-;;; Code:
-
-;;; a pacman client
-(defun my-grok-pacman (package)
- (ignore-errors (kill-buffer "*pacman*"))
- (if (= 0
- (call-process-shell-command
- (concat "pacman -Si " package) nil "*pacman*"))
- (my-process-pacman-info
- (my-parse-colon-separated-output "*pacman*"))
- (error (format "Failed to find package %s!" package))))
-
-(defun my-process-pacman-info (info)
- (list (cons "Description" (alist-get "Description" info nil nil 'string=))
- (cons "Website" (alist-get "URL" info nil nil 'string=))
- (cons "License" (alist-get "Licenses" info nil nil 'string=))
- (cons "Pacman-package-name" (alist-get "Name" info nil nil 'string=))))
-
-(provide 'my-pacman)
-;;; my-pacman.el ends here
diff --git a/.emacs.d/lisp/my/my-pdf-tools.el b/.emacs.d/lisp/my/my-pdf-tools.el
deleted file mode 100644
index 8fe884c..0000000
--- a/.emacs.d/lisp/my/my-pdf-tools.el
+++ /dev/null
@@ -1,200 +0,0 @@
-;;; my-pdf-tools.el -- Extensions for pdf-tools -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for pdf-tools.
-
-;;; Code:
-
-(require 'pdf-tools)
-(defvar my-pdf-view-current-node nil)
-(defvar my-pdf-view-navigation-functions
- '(my-pdf-view-forward-node
- my-pdf-view-backward-node
- my-pdf-view-forward-node-same-depth
- my-pdf-view-backward-node-same-depth
- my-pdf-view-backward-node-lower-depth))
-
-(defun my-pdf-outline-update-with-path (outline)
- (let ((path) (depth 0))
- (dolist (node outline)
- (let* ((node-depth (alist-get 'depth node))
- (node-title (alist-get 'title node))
- (depth-diff (- node-depth depth 1)))
- (cond ((< depth-diff 0) (dotimes (unused (- depth-diff))
- (pop path)))
- ((> depth-diff 0) (dotimes (unused depth-diff)
- (push "" path))))
- (push node-title path)
- (setq depth node-depth))
- (setf (alist-get 'title node) (string-join (reverse path) "/")))
- outline))
-
-(defun my-pdf-jump-and-set-current-node (node)
- (pdf-links-action-perform node)
- (setq my-pdf-view-current-node node))
-
-(defun my-pdf-outline-jump ()
- (interactive)
- (let ((outline (my-pdf-outline-update-with-path
- (pdf-info-outline (current-buffer)))))
- (if (not outline) (message "PDF has no outline")
- (let ((title (completing-read
- "Jump to: "
- (mapcar (lambda (node) (alist-get 'title node))
- outline))))
- (pdf-links-action-perform
- (cl-find-if (lambda (node) (equal (alist-get 'title node) title))
- outline))))))
-
-(defun my-pdf-view-next-node-by-page (outline)
- (cl-find-if (lambda
- (node)
- (> (alist-get 'page node) (pdf-view-current-page))) outline))
-
-(defun my-pdf-view-next-node-by-node (current-node outline &optional depth-req)
- (let ((next-node
- (catch 'ret
- (while outline
- (when (equal (car outline) current-node)
- (throw 'ret (cadr outline)))
- (setq outline (cdr outline))))))
- (cond ((not depth-req) next-node)
- ((eq depth-req 'same-depth)
- (cl-find-if (lambda (node) (= (alist-get 'depth node)
- (alist-get 'depth current-node)))
- (cdr outline)))
- (t (error "Unknown depth-req")))))
-
-(defun my-pdf-view-forward-node ()
- (interactive)
- (let ((outline (pdf-info-outline (current-buffer))))
- (if (not outline) (message "PDF has no outline")
- (my-pdf-jump-and-set-current-node
- (if (and my-pdf-view-current-node
- (memq last-command my-pdf-view-navigation-functions))
- (my-pdf-view-next-node-by-node my-pdf-view-current-node outline)
- (my-pdf-view-next-node-by-page outline))))))
-
-(defun my-pdf-view-lowest-node-current-page (outline)
- "returns the last node of the lowest depth on the current page"
- (let ((result) (current-page (pdf-view-current-page)))
- (catch 'ret
- (while outline
- (let ((node (car outline)))
- (cond ((= (alist-get 'page node) current-page)
- (when (or (not result)
- (<= (alist-get 'depth node)
- (alist-get 'depth result)))
- (setq result node)))
- ((> (alist-get 'page node) current-page)
- (throw 'ret result))))
- (setq outline (cdr outline))))))
-
-(defun my-pdf-view-highest-node-current-page (outline)
- "returns the first node of the highest depth on the current page"
- (let ((result) (current-page (pdf-view-current-page)))
- (catch 'ret
- (while outline
- (let ((node (car outline)))
- (cond ((= (alist-get 'page node) current-page)
- (when (or (not result)
- (> (alist-get 'depth node)
- (alist-get 'depth result)))
- (setq result node)))
- ((> (alist-get 'page node) current-page)
- (throw 'ret result))))
- (setq outline (cdr outline))))))
-
-(defun my-pdf-view-forward-node-same-depth ()
- (interactive)
- (let ((outline (pdf-info-outline (current-buffer))))
- (if (not outline) (message "PDF has no outline")
- (my-pdf-jump-and-set-current-node
- (my-pdf-view-next-node-by-node
- (if (and my-pdf-view-current-node
- (memq last-command my-pdf-view-navigation-functions))
- my-pdf-view-current-node
- (my-pdf-view-lowest-node-current-page outline))
- outline 'same-depth)))))
-
-(defun my-pdf-view-prev-node-by-node (current-node outline &optional depth-req)
- (let ((prev-node) (depth (alist-get 'depth current-node)))
- (catch 'ret
- (dolist (node outline)
- (if (equal node current-node)
- (throw 'ret prev-node)
- (when (or (not depth-req)
- (and (eq depth-req 'same-depth)
- (eq (alist-get 'depth node) depth))
- (and (eq depth-req 'lower-depth)
- (< (alist-get 'depth node) depth)))
- (setq prev-node node)))))))
-
-(defun my-pdf-view-prev-node-by-page (outline)
- (let ((prev-node))
- (catch 'ret
- (dolist (node outline)
- (if (>= (alist-get 'page node) (pdf-view-current-page))
- (throw 'ret prev-node)
- (setq prev-node node))))))
-
-(defun my-pdf-view-backward-node ()
- (interactive)
- (let ((outline (pdf-info-outline (current-buffer))))
- (if (not outline) (message "PDF has no outline")
- (my-pdf-jump-and-set-current-node
- (if (and my-pdf-view-current-node
- (memq last-command my-pdf-view-navigation-functions))
- (my-pdf-view-prev-node-by-node my-pdf-view-current-node outline)
- (my-pdf-view-prev-node-by-page outline))))))
-
-(defun my-pdf-view-backward-node-same-depth ()
- (interactive)
- (let ((outline (pdf-info-outline (current-buffer))))
- (if (not outline) (message "PDF has no outline")
- (my-pdf-jump-and-set-current-node
- (my-pdf-view-prev-node-by-node
- (if (and my-pdf-view-current-node
- (memq last-command my-pdf-view-navigation-functions))
- my-pdf-view-current-node
- (my-pdf-view-lowest-node-current-page outline))
- outline 'same-depth)))))
-
-(defun my-pdf-view-backward-node-lower-depth ()
- (interactive)
- (let ((outline (pdf-info-outline (current-buffer))))
- (if (not outline) (message "PDF has no outline")
- (my-pdf-jump-and-set-current-node
- (my-pdf-view-prev-node-by-node
- (if (and my-pdf-view-current-node
- (memq last-command my-pdf-view-navigation-functions))
- my-pdf-view-current-node
- (my-pdf-view-lowest-node-current-page outline))
- outline 'lower-depth)))))
-
-(defun my-pdf-view-enlarge-a-bit () (interactive) (pdf-view-enlarge 1.01))
-(defun my-pdf-view-shrink-a-bit () (interactive) (pdf-view-enlarge .99))
-
-(provide 'my-pdf-tools)
-;;; my-pdf-tools.el ends here
diff --git a/.emacs.d/lisp/my/my-prog.el b/.emacs.d/lisp/my/my-prog.el
deleted file mode 100644
index 6b7c705..0000000
--- a/.emacs.d/lisp/my/my-prog.el
+++ /dev/null
@@ -1,142 +0,0 @@
-;;; my-prog.el -- Programming related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Programming related extensions for emacs core. Covers comint,
-;; shell, eshell, elisp, prog-mode, c, c++, etc.
-
-;;; Code:
-
-;;; comint, shell, eshell
-(defvar comint-buffer-list nil)
-(setq display-buffer-alist
- '(("\\*shell\\*.*" . (display-buffer-same-window))))
-
-(defun my-shell-with-directory (dir)
- "Starts a new shell with prompted directory as the cwd"
- (interactive (list
- (read-directory-name "Current dir: ")))
- (let ((tmp-dir default-directory)
- (old-buffer (current-buffer)))
- (setq default-directory dir)
- (shell (generate-new-buffer-name "*shell*"))
- (with-current-buffer old-buffer (setq default-directory tmp-dir))))
-
-(defun my-comint-send-input-and-return-prompt ()
- (interactive)
- (comint-send-input)
- (comint-previous-prompt 1)
- (recenter 0 t))
-
-;; FIXME: not working properly
-(defun my-restart-shell ()
- (interactive)
- (ignore-error (comint-send-eof))
- (shell (current-buffer))
- (message "Shell restarted!"))
-
-(defun my-shell-disable-company-if-remote ()
- (when (and (fboundp 'company-mode)
- (file-remote-p default-directory))
- (company-mode -1)))
-
-(defun my-eshell-insert-prompt-prefix ()
- (interactive)
- (let ((prompt (funcall eshell-prompt-function)))
- (string-match "\\(^.*:\\).*$" prompt)
- (when (match-string 1 prompt)
- (insert (match-string 1 prompt)))))
-
-(defun my-eshell-send-input-and-return-prompt ()
- (interactive)
- (eshell-send-input)
- (eshell-previous-prompt 1))
-
-;;; c
-(defun my-c-set-compile-command ()
- (unless (file-exists-p "Makefile")
- (setq compile-command
- (let ((file (file-name-nondirectory buffer-file-name)))
- (format "%s -o %s %s %s %s"
- ;;"%s -c -o %s.o %s %s %s"
- (or (getenv "CC") "gcc")
- (file-name-sans-extension file)
- (or (getenv "CPPFLAGS") "-DDEBUG=9")
- (or (getenv "CFLAGS")
- "-ansi -pedantic -Wall -g")
- file)))))
-
-;;; To override `xref-query-replace-in-results'.
-(defun my-xref-query-replace-in-results (from to)
- "Perform interactive replacement of FROM with TO in all displayed xrefs.
-
-This function interactively replaces FROM with TO in the names of the
-references displayed in the current *xref* buffer.
-
-When called interactively, it uses '.*' as FROM, which means replace
-the whole name, and prompts the user for TO.
-If invoked with prefix argument, it prompts the user for both FROM and TO.
-
-As each match is found, the user must type a character saying
-what to do with it. Type SPC or `y' to replace the match,
-DEL or `n' to skip and go to the next match. For more directions,
-type \\[help-command] at that time.
-
-Note that this function cannot be used in *xref* buffers that show
-a partial list of all references, such as the *xref* buffer created
-by \\[xref-find-definitions] and its variants, since those list only
-some of the references to the identifiers."
- (interactive
- (let* ((fr
- (if current-prefix-arg
- (read-regexp "Query-replace (regexp)" ".*")
- "\\(.*\\)"))
- (prompt (if current-prefix-arg
- (format "Query-replace (regexp) %s with: " fr)
- "Query-replace all matches with: ")))
- (list fr (read-regexp prompt))))
- (let* (item xrefs iter)
- (save-excursion
- (while (setq item (xref--search-property 'xref-item))
- (when (xref-match-length item)
- (push item xrefs))))
- (unwind-protect
- (progn
- (goto-char (point-min))
- (setq iter (xref--buf-pairs-iterator (nreverse xrefs)))
- (xref--query-replace-1 from to iter))
- (funcall iter :cleanup))))
-
-(defun my-set-tab-width-to-8 ()
- (interactive)
- (setq tab-width 8))
-
-(defun my-toggle-debug-on-error-quit (arg)
- (interactive "P")
- (if arg
- (toggle-debug-on-quit)
- (toggle-debug-on-error))
- )
-
-(provide 'my-prog)
-;;; my-prog.el ends here
diff --git a/.emacs.d/lisp/my/my-project.el b/.emacs.d/lisp/my/my-project.el
deleted file mode 100644
index 21a05f1..0000000
--- a/.emacs.d/lisp/my/my-project.el
+++ /dev/null
@@ -1,104 +0,0 @@
-;;; my-project.el -- Project related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Project related extensions for emacs core.
-
-;;; Code:
-
-
-
-(defvar my-projects-root-dirs nil
- "List of directories to look for projects. Each element in the form
- of (tag . path). One of the tags should be \"3p\" which is a default
- target for cloning a project")
-(defun my-get-list-of-projects ()
- (flatten-list
- (mapcar (lambda (pair)
- (mapcar
- (lambda (dir-name) (format "%s(%s)" dir-name (car pair)))
- (directory-files
- (cdr pair) nil directory-files-no-dot-files-regexp)))
- my-projects-root-dirs)))
-
-(defun my-project-guess-project-name ()
- (file-name-nondirectory (directory-file-name
- (project-root (project-current)))))
-
-(defvar my-licenses nil
- "List of licenses in the form of (licence-id . license-text-file)")
-
-(defun my-project-copy-license-file-to-project (license)
- (interactive (list (completing-read "License to copy to project root: "
- (mapcar 'car my-licenses))))
- (let ((from (alist-get (intern license) my-licenses))
- (to (concat (project-root (project-current))
- "COPYING." license)))
- (copy-file from to)
- (message "Copied license of %s to %s" license to)))
-
-(defun my-project-remember-all-projects ()
- "Remember all projects under `my-projects-root-dirs'."
- (pcase-dolist (`(_ . ,dir) my-projects-root-dirs)
- (project-remember-projects-under dir)))
-;; FIXME: do we really need this or does the project package already
-;; do so?
-(defun my-project-read-project ()
- (let ((key-val
- (completing-read "Choose projects: "
- (my-get-list-of-projects) nil t)))
- (string-match "^\\(.*\\)(\\(.*\\))$" key-val)
- (cons (match-string 2 key-val) (match-string 1 key-val))))
-(defun my-project-get-project-directory (pair)
- (concat
- (alist-get (car pair) my-projects-root-dirs nil nil 'string=)
- "/" (cdr pair)))
-(defun my-project-read-project-root ()
- (my-project-get-project-directory (my-project-read-project)))
-(defun my-project-shell-at (arg)
- (interactive "P")
- (if arg (project-shell)
- (my-shell-with-directory (my-project-read-project-root))))
-(defun my-project-dired-at (arg)
- (interactive "P")
- (if arg (project-dired)
- (dired (my-project-read-project-root))))
-(defun my-project-rgrep-at (arg)
- (interactive "P")
- (if arg (project-query-replace-regexp)
- (my-rgrep-at-directory (my-project-read-project-root))))
-(defun my-project-org-set-local-source ()
- (interactive)
- (org-set-property "Local-source" (my-project-read-project-root)))
-(defun my-project-code-stats ()
- (interactive)
- (switch-to-buffer-other-window (get-buffer-create "*cloc*"))
- (erase-buffer)
- (my-with-default-directory (my-project-read-project-root)
- (message default-directory)
- (insert default-directory "\n")
- (call-process "cloc" nil "*cloc*" nil "HEAD" "--quiet")))
-
-
-(provide 'my-project)
-;;; my-project.el ends here
diff --git a/.emacs.d/lisp/my/my-rtliber.el b/.emacs.d/lisp/my/my-rtliber.el
deleted file mode 100644
index cefc5eb..0000000
--- a/.emacs.d/lisp/my/my-rtliber.el
+++ /dev/null
@@ -1,72 +0,0 @@
-;;; my-rtliber.el -- Extensions for rt-liberation -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for rt-liberation.
-
-;;; Code:
-
-
-(require 'rt-liberation)
-;;; fixme: fsf credentials
-(defun my-rt-liber-my-open-tickets () (interactive)
- (rt-liber-browse-query
- (format "owner = '%s' and status != 'resolved'"
- rt-liber-username)))
-
-(defun my-rt-liber-my-tickets () (interactive)
- (rt-liber-browse-query
- (format "owner = '%s'" rt-liber-username)))
-
-(defun my-rt-liber-backlog ()
- (interactive)
- (rt-liber-browse-query
- "created >= '90 days ago' and owner = 'nobody' and status != 'resolved'"))
-
-(defun my-rt-liber-get-ticket-by-id (id)
- (interactive "sTicket ID: ") (rt-liber-browse-query (concat "id = "
- id)))
-
-(defun my-rt-liber-query-by-subject (query)
- (interactive "sQuery in subject: ")
- (rt-liber-browse-query
- (concat "subject like '" query "'")))
-
-;;; Used to override `rt-liber-viewer-visit-in-browser'
-(defun my-rt-liber-viewer-visit-in-browser (&optional external)
- "Visit this ticket section in the RT Web interface.
-With a prefix arg, browse using secondary browser."
- (interactive "P")
- (let ((id (rt-liber-ticket-id-only rt-liber-ticket-local))
- (browser-function
- (if external browse-url-secondary-browser-function
- 'browse-url)))
- (if id
- (funcall browser-function
- (concat rt-liber-base-url "Ticket/Display.html?id=" id
- "#txn-"
- (alist-get 'id (rt-liber-viewer2-get-section-data))))
- (error "no ticket currently in view"))))
-
-(provide 'my-rtliber)
-;;; my-rtliber.el ends here
diff --git a/.emacs.d/lisp/my/my-scihub.el b/.emacs.d/lisp/my/my-scihub.el
deleted file mode 100644
index 8d9f66b..0000000
--- a/.emacs.d/lisp/my/my-scihub.el
+++ /dev/null
@@ -1,53 +0,0 @@
-;;; my-scihub.el -- scihub client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; scihub client.
-
-;;; Code:
-
-
-(require 'link-gopher)
-
-(defvar my-scihub-host nil "Scihub host")
-(defun my-get-scihub-pdf-link (doi)
- (let ((link (car (link-gopher-get-all-links
- (concat my-scihub-host doi) "\\.pdf$"))))
- (when (not link)
- (message "Scihub pdf link not found for %s with eww, trying firefox..."
- doi)
- (browse-url-firefox (concat my-scihub-host doi)))
- link))
-
-(defun my-download-scihub-doi (doi)
- (interactive "sDOI: ")
- (when-let ((link (my-get-scihub-pdf-link doi))) (wget link)))
-
-(defun my-org-attach-scihub ()
- (interactive)
- (require 'org-attach)
- (when-let ((doi (org-entry-get (point) "DOI")))
- (org-attach-url (my-get-scihub-pdf-link doi))))
-
-(provide 'my-scihub)
-;;; my-scihub.el ends here
diff --git a/.emacs.d/lisp/my/my-semantic-scholar.el b/.emacs.d/lisp/my/my-semantic-scholar.el
deleted file mode 100644
index 4b22390..0000000
--- a/.emacs.d/lisp/my/my-semantic-scholar.el
+++ /dev/null
@@ -1,100 +0,0 @@
-;;; my-semantic-scholar.el -- Semantic Scholar client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Semantic Scholar client.
-
-;;; Code:
-
-(require 'my-utils)
-(require 'my-scihub)
-
-(defvar my-semantic-scholar-host
- "https://api.semanticscholar.org/graph/v1")
-(defun my-semantic-scholar-fetch-papers-for-completion (query)
- (with-current-buffer
- (url-retrieve-synchronously
- (format "%s/paper/search?query=%s" my-semantic-scholar-host query))
- (my-skip-http-header)
- (mapcar
- (lambda (entry)
- (concat
- (alist-get 'title entry)
- (propertize
- (concat " "
- (alist-get 'paperId entry))
- 'invisible t)))
- (alist-get 'data (json-read)))))
-
-(defun my-semantic-scholar-make-paper-alist (paper-info)
- (list (cons "Authors"
- (string-join
- (mapcar (lambda (entry) (alist-get 'name entry))
- (alist-get 'authors paper-info))
- " and "))
- (cons "Title" (alist-get 'title paper-info))
- (cons "Published"
- (number-to-string (alist-get 'year paper-info)))
- (cons "Abstract" (my-clean-property-value
- (alist-get 'abstract paper-info)))
- (cons "Venue" (alist-get 'venue paper-info))
- (cons "arXiv" (alist-get
- 'ArXiv (alist-get 'externalIds paper-info)))
- (cons "DOI" (alist-get
- 'DOI (alist-get 'externalIds paper-info)))
- (cons "Semantic-scholar" (alist-get 'paperId paper-info))))
-
-(defun my-semantic-scholar-lookup-paper ()
- "looks up a paper using semantic scholar api, prompts for selection and creates a org entry."
- (interactive)
- (let* ((query (read-string "Query: "))
- (selected (completing-read
- "Select paper:" ;; '("a" "b")
- (my-semantic-scholar-fetch-papers-for-completion query))))
- (with-current-buffer
- (url-retrieve-synchronously
- (format
- "%s/paper/%s?fields=title,abstract,authors,venue,year,externalIds"
- my-semantic-scholar-host
- (progn (string-match "^.* \\(.*\\)$" selected)
- (match-string 1 selected))))
- (my-skip-http-header)
- (my-org-create-node (my-semantic-scholar-make-paper-alist (json-read)))
- (my-org-attach-scihub))))
-
-(defun my-semantic-scholar-lookup-doi ()
- "looks up a paper using semantic scholar api, prompts for selection and creates a org entry."
- (interactive)
- (let ((doi (read-string "DOI: ")))
- (with-current-buffer
- (url-retrieve-synchronously
- (format
- "%s/paper/%s?fields=title,abstract,authors,venue,year,externalIds"
- my-semantic-scholar-host
- doi))
- (my-skip-http-header)
- (my-org-create-node (my-semantic-scholar-make-paper-alist (json-read)))
- (my-org-attach-scihub))))
-
-(provide 'my-semantic-scholar)
-;;; my-semantic-scholar.el ends here
diff --git a/.emacs.d/lisp/my/my-servall.el b/.emacs.d/lisp/my/my-servall.el
deleted file mode 100644
index 81478e9..0000000
--- a/.emacs.d/lisp/my/my-servall.el
+++ /dev/null
@@ -1,39 +0,0 @@
-;;; my-servall.el -- Extensions to servall -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions to servall.
-
-;;; Code:
-
-
-(require 'org)
-(require 'servall-wikipedia)
-(defun my-servall-wikipedia-grok ()
- "grok from servall"
- (interactive)
- (org-protocol-grok
- (list :url (format "https://en.wikipedia.org/wiki/%s" servall-wikipedia-title))))
-
-(provide 'my-servall)
-;;; my-servall.el ends here
diff --git a/.emacs.d/lisp/my/my-tempel.el b/.emacs.d/lisp/my/my-tempel.el
deleted file mode 100644
index c0834d4..0000000
--- a/.emacs.d/lisp/my/my-tempel.el
+++ /dev/null
@@ -1,68 +0,0 @@
-;;; my-tempel.el -- Extensions for tempel -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Protesilaos Stavrou <info@protesilaos.com>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for tempel.
-
-;;; Code:
-
-
-;;; taken from tempel info manual
-(defun my-tempel-include (elt)
- "A tempel element to include another element"
- (when (eq (car-safe elt) 'i)
- (if-let (template (alist-get (cadr elt) (tempel--templates)))
- (cons 'l template)
- (message "Template %s not found" (cadr elt))
- nil)))
-(add-to-list 'tempel-user-elements #'my-tempel-include)
-
-;; Setup completion at point
-(defun my-tempel-setup-capf ()
- ;; Add the Tempel Capf to `completion-at-point-functions'.
- ;; `tempel-expand' only triggers on exact matches. Alternatively use
- ;; `tempel-complete' if you want to see all matches, but then you
- ;; should also configure `tempel-trigger-prefix', such that Tempel
- ;; does not trigger too often when you don't expect it. NOTE: We add
- ;; `tempel-expand' *before* the main programming mode Capf, such
- ;; that it will be tried first.
- (setq-local completion-at-point-functions
- (cons #'tempel-expand
- completion-at-point-functions)))
-
-;; Setup completion at point
-(defun my-tempel-setup-capf ()
- ;; Add the Tempel Capf to `completion-at-point-functions'.
- ;; `tempel-expand' only triggers on exact matches. Alternatively use
- ;; `tempel-complete' if you want to see all matches, but then you
- ;; should also configure `tempel-trigger-prefix', such that Tempel
- ;; does not trigger too often when you don't expect it. NOTE: We add
- ;; `tempel-expand' *before* the main programming mode Capf, such
- ;; that it will be tried first.
- (setq-local completion-at-point-functions
- (cons #'tempel-expand
- completion-at-point-functions)))
-
-(provide 'my-tempel)
-;;; my-tempel.el ends here
diff --git a/.emacs.d/lisp/my/my-tide.el b/.emacs.d/lisp/my/my-tide.el
deleted file mode 100644
index 58b2b8b..0000000
--- a/.emacs.d/lisp/my/my-tide.el
+++ /dev/null
@@ -1,43 +0,0 @@
-;;; my-tide.el -- Extensions for tide -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it
-;; under the terms of the GNU Affero General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-
-;; dotfiles 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
-;; Affero General Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for tide.
-
-;;; Code:
-
-(defun my-setup-tide-mode ()
- (interactive)
- (tide-setup)
- (flycheck-mode +1)
- (setq flycheck-check-syntax-automatically '(save mode-enabled))
- (eldoc-mode +1)
- (tide-hl-identifier-mode +1)
- ;; company is an optional dependency. You have to
- ;; install it separately via package-install
- ;; `M-x package-install [ret] company`
- (company-mode +1))
-
-(provide 'my-tide)
-;;; my-tide.el ends here
diff --git a/.emacs.d/lisp/my/my-time.el b/.emacs.d/lisp/my/my-time.el
deleted file mode 100644
index c1f2329..0000000
--- a/.emacs.d/lisp/my/my-time.el
+++ /dev/null
@@ -1,51 +0,0 @@
-;;; my-time.el -- Time related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it
-;; under the terms of the GNU Affero General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-
-;; dotfiles 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
-;; Affero General Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Time related extensions for emacs core. Covers time, date, diary, etc.
-
-;;; Code:
-
-
-
-;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
-(defun my-diary-offset (sexp days)
- "Offsetted diary entry.
-Entry applies if the date is DAYS days after another diary-sexp SEXP."
- (with-no-warnings (defvar date) (defvar entry))
- (integerp days)
- (let ((date
- (calendar-gregorian-from-absolute
- (- (calendar-absolute-from-gregorian date) days))))
- (eval sexp)))
-
-(defun my-appt-display-window (min-to-appt new-time appt-msg)
- (or (listp min-to-appt)
- (setq min-to-appt (list min-to-appt)
- appt-msg (list appt-msg)))
- (org-notify (format
- "In %s minutes: %s" (car min-to-appt) (car appt-msg))))
-
-(provide 'my-time)
-;;; my-time.el ends here
diff --git a/.emacs.d/lisp/my/my-utils.el b/.emacs.d/lisp/my/my-utils.el
deleted file mode 100644
index 7f36fae..0000000
--- a/.emacs.d/lisp/my/my-utils.el
+++ /dev/null
@@ -1,409 +0,0 @@
-;;; my-utils.el -- Basic utilities used by other extensions -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Basic utilities used by other extensions.
-
-;;; Code:
-
-
-;; time and date
-(defun my-date-part (td)
- (nthcdr 3 td))
-
-(defun my-tomorrow ()
- (decode-time (time-add 86400 (current-time))))
-
-(defun my-skip-http-header ()
- (goto-char (point-min))
- (re-search-forward "\r?\n\r?\n"))
-
-(defun my-seq-random-element (xs)
- "Returns a random element of sequence."
- (elt xs (random (length xs))))
-
-(defun my-delete-http-header ()
- (delete-region (point-min) (progn (my-skip-http-header) (point))))
-
-(defun my-get-current-line-no-properties ()
- (save-excursion
- (let ((beg (progn (beginning-of-line)
- (point)))
- (end (progn (beginning-of-line 2)
- (point))))
- (buffer-substring-no-properties beg (1- end)))))
-
-(defun my-sudo-find-file ()
- (interactive)
- (let* ((maybe-filename (thing-at-point 'filename t))
- (matched (and maybe-filename
- (string-match "^\\(.*/\\)\\(.*\\)$" maybe-filename)))
- (file (read-file-name
- "Open as root: "
- (and matched (match-string 1 maybe-filename)) nil nil
- (and matched (match-string 2 maybe-filename)))))
- (unless (file-writable-p file)
- (find-file (concat "/sudo::" file)))))
-
-(defvar my-url-regexp
- (concat
- "~?\\<\\([-a-zA-Z0-9+&@#/%?=~_|!:,.;]*\\)"
- "[.@]"
- "\\([-a-zA-Z0-9+&@#/%?=~_|!:,.;]+\\)\\>/?")
- "Regular expression to match (most?) URLs or email addresses.")
-
-
-(defun my-clean-property-value (value)
- (when value
- (replace-regexp-in-string
- "\n" ", "
- (string-trim (replace-regexp-in-string " " "_" value)
- "[ \t\n\r_]+" "[ \t\n\r_]+"))))
-
-;; rewriting urls
-(defvar my-max-url-rewrite 100 "Max number of URL redirect")
-(defun my-rewrite-url (url)
- (let ((new-url url)
- (tmp-url)
- (i 0))
- (catch 'done
- (while (< i my-max-url-rewrite)
- (setq tmp-url (my-rewrite-url-once new-url))
- (when (equal tmp-url new-url) (throw 'done nil))
- (setq new-url tmp-url
- i (1+ i))))
- (unless (equal url new-url)
- (message "Rewriting %s to %s" url new-url))
- new-url))
-
-(defvar my-simple-url-rewrites
- '((:name http-to-https
- :description "Rewrite http to https."
- :from "^http://\\(.*\\)$"
- :to "https://%s"
- :parts (1))
- (:name ddg-result
- :description "duckduckgo result transform."
- :from "^https://duckduckgo.com/l/\\?uddg=\\(.*\\)&rut=.*$"
- :to "%s"
- :parts (1)
- :match-processor url-unhex-string)
- (:name youtube-to-yewtu-be
- :description "youtube to yewtu.be"
- :from "^https://\\(www\\.\\)?youtube.com/\\(.*\\)$"
- :to "https://yewtu.be/%s"
- :parts (2))
- (:name reddit-to-teddit
- :description "Reddit to Teddit"
- :from "^https://\\(www\\.\\|old\\.\\)?reddit.com/\\(.*\\)$"
- :to "https://teddit.net/%s"
- :parts (2))
- (:name twitter-to-nitter
- :description "Twitter to nitter."
- :from "^https://twitter.com/\\(.*\\)$"
- :to "https://nitter.eu/%s"
- :parts (1))
- (:name google-to-ddg
- :description "Google to duckduckgo"
- :from "^https://www.google.com/search\\?q=\\(.*\\)$"
- :to "https://html.duckduckgo.com/html?q=%s"
- :parts (1))
- (:name php-manual-to-english
- :descripton "PHP manual to English"
- :from "^https://www.php.net/manual/../\\(.*\\)$"
- :to "https://www.php.net/manual/en/%s"
- :parts (1))
- (:name google-sheets-to-csv
- :description "Google sheets to csv"
- :from "https://docs.google.com/spreadsheets/\\(.*\\)/.*"
- :to "https://docs.google.com/spreadsheets/%s/export?format=csv"
- :parts (1))
- (:name google-docs-to-odt
- :description "Google docs to odt"
- :from "https://docs.google.com/document/\\(.*\\)/.*"
- :to "https://docs.google.com/document/%s/export?format=odt"
- :parts (1))
- (:name utm-remover-not-last
- :description "Removing a utm_foo query that is not the last query"
- :from "\\(.*\\)\\butm_[a-z_]+=[^&]*&\\(.*\\)"
- :to "%s%s"
- :parts (1 2))
- (:name utm-remover-last
- :description "Removing a utm_foo query that is the last query"
- :from "\\(.*\\)[&?]utm_[a-z_]+=[^#]*\\(.*\\)"
- :to "%s%s"
- :parts (1 2))))
-
-(defun my-simple-rewrite-function-name (data)
- (intern (format "my-simple-url-rewrite-%s"
- (plist-get data :name))))
-
-(defmacro my-def-simple-rewrite (data)
- (let ((processor (plist-get data :match-processor)))
- `(defun ,(my-simple-rewrite-function-name data) (url)
- ,(plist-get data :description)
- (when (string-match ,(plist-get data :from) url)
- ,(append `(format ,(plist-get data :to))
- (mapcar (lambda (part)
- (if processor
- `(,processor (match-string ,part url))
- `(match-string ,part url)))
- (plist-get data :parts)))))))
-
-;; TODO: why do we need an eval here?
-;; Because we are using plist-get in the defmacro
-(dolist (data my-simple-url-rewrites)
- (eval `(my-def-simple-rewrite ,data)))
-
-(defvar my-url-rewrite-functions
- (mapcar 'my-simple-rewrite-function-name my-simple-url-rewrites))
-
-(defun my-rewrite-url-once (url)
- (let* ((rewriters my-url-rewrite-functions)
- (rewritten) (rewriter) (result))
- (while (and rewriters (not rewritten))
- (setq rewriter (car rewriters)
- rewriters (cdr rewriters)
- rewritten (funcall rewriter url)))
- (or rewritten url)))
-
-(defun my-shell-command-output (command)
- (let ((inhibit-message t))
- (if (= 0
- (shell-command command))
- (with-current-buffer shell-command-buffer-name
- (string-trim (buffer-string)))
- (error (with-current-buffer shell-command-buffer-name
- (string-trim (buffer-string)))))))
-
-;; mailman utils
-(defun my-mailman-to-listinfo-url (url)
- (when (string-match "^\\(.*\\)/archive/html/\\(.*\\)" url)
- (format "%s/mailman/listinfo/%s"
- (match-string 1 url) (match-string 2 url))))
-
-(defun my-mailman-to-archive-url (url)
- (when (string-match "^\\(.*\\)/mailman/listinfo/\\(.*\\)" url)
- (format "%s/archive/html/%s"
- (match-string 1 url) (match-string 2 url))))
-
-;; filenames
-
-(defun my-make-filename (name &optional sep)
- "Convert name to filename by replacing special chars with sep."
- (unless sep (setq sep "-"))
- (replace-regexp-in-string "[[:punct:][:space:]\n\r]+" sep
- (string-trim name)))
-
-(defun my-make-filename-from-url (url)
- (let* ((urlobj (url-generic-parse-url url))
- (filename (url-filename urlobj))
- (host (url-host urlobj)))
- (replace-regexp-in-string
- "^-+" ""
- (replace-regexp-in-string
- "-+$" "" (my-make-filename (concat host "-" filename))))))
-
-(defun my-clean-property-key (key)
- (when key
- (let ((new-key
- (replace-regexp-in-string
- "[ \t\n\r_]+" "-" (string-trim
- (replace-regexp-in-string " " "_" key)))))
- (cond ((string-match "Publication-date" new-key)
- "Published")
- ((string= new-key "Publication") "Published")
- ((string= new-key "出版時間") "Published")
- ((string= new-key "出生") "Born")
- ((string= new-key "逝世") "Died")
- ((string= new-key "Formed") "Founded")
- ((string-match "^成立" new-key) "Founded")
- ((string= new-key "网站") "Website")
- ((string= new-key "網站") "Website")
- ((string= new-key "出版日期") "Published")
- ((string= new-key "Author") "Authors")
- ((string= new-key "作者") "Authors")
- ((string= new-key "Designer") "Designers")
- ((string-match "Directed" new-key) "Director")
- ((string= new-key "Created-by") "Director")
- ((string-match "导演" new-key) "Director")
- ((string-match "[Rr]elease-date" new-key) "Released")
- ((string-match "上映日期" new-key) "Released")
- ((string-match "[Oo]riginal-release" new-key) "Released")
- ((string-match "[Ii]nitial-release" new-key) "Released")
- ((string-match "^Release$" new-key) "Released")
- ((string-match "^Developer" new-key) "Developers")
- ((string-match "^Repository" new-key) "Source")
- ((string-match "^URL" new-key) "Website")
- ((string-match "^Official-website" new-key) "Website")
- (t new-key)))))
-
-(defun my-parse-colon-separated-output (buffer)
- (with-current-buffer buffer
- (goto-char (point-min))
- (let ((result) (field) (value))
- (while (not (eobp))
- (if (re-search-forward "\\(.*?\\)\\ +:" nil t)
- (progn
- (setq field
- (replace-regexp-in-string
- "[()]" ""
- (replace-regexp-in-string "\\ " "-" (match-string 1))))
- (re-search-forward "\\ *\\(.*?\\)\n")
- (setq value (match-string 1))
- (push (cons field value) result))
- (message "Failed search in parsing!")
- (goto-char (point-max))))
- result)))
-
-(defvar my-docs-root-dir nil "Root directory of documentation")
-(defun my-get-list-of-docs ()
- (directory-files my-docs-root-dir nil directory-files-no-dot-files-regexp))
-
-(defmacro my-with-default-directory (dir &rest body)
- "Run BODY with the default directory."
- (declare (indent 1) (debug t))
- `(let ((saved default-directory))
- (setq default-directory ,dir)
- ,@body
- (setq default-directory saved)))
-
-(defun my-call-process-with-torsocks
- (program &optional infile destination display &rest args)
- (apply 'call-process
- (append (list "torsocks" infile destination display program) args)))
-
-(defun my-start-process-with-torsocks (no-tor name buffer program &rest program-args)
- (if no-tor
- (apply 'start-process (append (list name buffer program) program-args))
- (apply 'start-process
- (append (list name buffer "torsocks" program) program-args))))
-
-(defun my-touch-new-file (filename)
- "Touch a new file."
- (with-temp-buffer (write-file filename)))
-
-(defvar my-extension-types
- '((audio . ("asf" "cue" "flac" "m4a" "m4r" "mid" "mp3" "ogg" "opus"
- "wav" "wma"))
- (video . ("avi" "m4v" "mkv" "mp4" "mpg" "ogg" "ogv" "rmvb" "webm" "wmv"))))
-
-;;; files
-(defun my-rename-and-symlink-back (file newname ok-if-already-exists)
- (when (directory-name-p newname)
- (setq newname (concat newname (file-name-nondirectory file))))
- (rename-file file newname ok-if-already-exists)
- (make-symbolic-link newname file ok-if-already-exists)
- newname)
-
-(defun my-rewrite-url-advice (args)
- (let ((url (car args)))
- (setcar args (my-rewrite-url url)))
- args)
-
-(defun my-server-p ()
- "nonnil if the emacs is a server or daemon"
- (and (boundp 'server-process) server-process))
-
-;; cleaning utilities
-(defun my-extract-year (text)
- (if (string-match "\\([0-9]\\{4\\}\\)" text)
- (match-string 1 text)
- ""))
-
-(defun my-rename-file-and-buffer (name)
- "Apply NAME to current file and rename its buffer.
-Do not try to make a new directory or anything fancy."
- (interactive
- (list (read-file-name "Rename current file to: ")))
- (let ((file (buffer-file-name)))
- (if (vc-registered file)
- (vc-rename-file file name)
- (rename-file file name))
- (set-visited-file-name name t t)))
-
-(defun my-delete-file-and-kill-buffer ()
- "Delete the buffer and the file
-
-Only accept if the file is vc-registered (easy to recover from mistakes)"
- (interactive)
- (let ((file (buffer-file-name)))
- (unless (vc-registered file)
- (error "Cannot delete file not under vc"))
- (vc-revert-file file)
- (vc-refresh-state)
- (vc-delete-file file))
- (kill-buffer))
-
-;;; Some of the following functions are adapted from prot-dotfiles
-;;;###autoload
-(defun my-keyboard-quit-dwim ()
- "Do-What-I-Mean behaviour for a general `keyboard-quit'.
-
-The generic `keyboard-quit' does not do the expected thing when
-the minibuffer is open. Whereas we want it to close the
-minibuffer, even without explicitly focusing it.
-
-The DWIM behaviour of this command is as follows:
-
-- When the region is active, disable it.
-- When a minibuffer is open, but not focused, close the minibuffer.
-- When the Completions buffer is selected, close it.
-- In every other case use the regular `keyboard-quit'."
- (interactive)
- (cond
- ((region-active-p)
- (keyboard-quit))
- ((derived-mode-p 'completion-list-mode)
- (delete-completion-window))
- ((> (minibuffer-depth) 0)
- (abort-recursive-edit))
- (t
- (keyboard-quit))))
-
-;; The `my-line-regexp-p' and `my--line-regexp-alist'
-;; are contributed by Gabriel: <https://github.com/gabriel376>.
-(defvar my--line-regexp-alist
- '((empty . "[\s\t]*$")
- (indent . "^[\s\t]+")
- (non-empty . "^.+$")
- (list . "^\\([\s\t#*+]+\\|[0-9]+[^\s]?[).]+\\)")
- (heading . "^[=-]+"))
- "Alist of regexp types used by `my-line-regexp-p'.")
-
-(defun my-line-regexp-p (type &optional n)
- "Test for TYPE on line.
-TYPE is the car of a cons cell in
-`my--line-regexp-alist'. It matches a regular
-expression.
-
-With optional N, search in the Nth line from point."
- (save-excursion
- (goto-char (line-beginning-position))
- (and (not (bobp))
- (or (beginning-of-line n) t)
- (save-match-data
- (looking-at
- (alist-get type my--line-regexp-alist))))))
-
-(provide 'my-utils)
diff --git a/.emacs.d/lisp/my/my-web.el b/.emacs.d/lisp/my/my-web.el
deleted file mode 100644
index c8517de..0000000
--- a/.emacs.d/lisp/my/my-web.el
+++ /dev/null
@@ -1,129 +0,0 @@
-;;; my-web.el -- web related extensions for emacs core -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; web related extensions for emacs core. Covers eww etc.
-
-;;; Code:
-
-
-
-(defun my-eww-next-path ()
- (interactive)
- (let ((url (plist-get eww-data :url)))
- (when (string-match "^\\(.*?\\)\\([0-9]+\\)\\(.*\\)$" url)
- (eww (concat
- (match-string 1 url)
- (number-to-string
- (1+ (string-to-number (match-string 2 url))))
- (match-string 3 url))))))
-
-(defun my-eww-prev-path ()
- (interactive)
- (let ((url (plist-get eww-data :url)))
- (when (string-match "^\\(.*\\)\\([0-9]+\\)\\(.*\\)$" url)
- (eww (concat
- (match-string 1 url)
- (number-to-string
- (1- (string-to-number (match-string 2 url))))
- (match-string 3 url))))))
-
-(defun my-eww-up-path ()
- (interactive)
- (let ((url (plist-get eww-data :url)))
- (when (and (string-match "^\\(.*//.*/\\)[^/]+\\(/\\)?$" url)
- (match-string 1 url))
- (eww (match-string 1 url)))))
-
-(defun my-eww-top-path ()
- (interactive)
- (let ((url (plist-get eww-data :url)))
- (when (and (string-match "^\\(.*//.*?/\\).*$" url)
- (match-string 1 url))
- (eww (match-string 1 url)))))
-
-(defun my-browse-url-tor-browser (url)
- "Browse URL with tor-browser."
- (setq url (browse-url-encode-url url))
- (start-process (concat "tor-browser " url) nil "tor-browser"
- "--allow-remote" url))
-
-(defun my-browse-url-firefox-private (url)
- "Browse URL in a private firefox window."
- (setq url (browse-url-encode-url url))
- (start-process (concat "firefox-private " url) nil "firefox"
- "--private-window" url))
-
-;; TODO: change to using hmm matching url with default app
-;; override browse-url
-(defun my-browse-url (url &optional arg)
- (interactive "P")
- (cond ((equal arg '(4))
- (funcall browse-url-secondary-browser-function url))
- ((equal arg '(16))
- (my-browse-url-tor-browser url))
- (t (luwak-open url))))
-
-;; this fixes clicking url buttons like those in gnus messages
-(defalias 'browse-url-button-open-url 'my-browse-url)
-
-(defun my-browse-url-at-point (arg)
- (interactive "P")
- (my-browse-url (browse-url-url-at-point) arg))
-
-;; override eww-copy-page-url to work with bookmark id frags.
-(defun eww-copy-page-url ()
- "Copy the URL of the current page into the kill ring."
- (interactive)
- (let* ((url (plist-get eww-data :url))
- (id (get-text-property (point) 'shr-frag-id))
- (url-no-frag
- (if (string-match "^\\(.*\\)#.*$" url)
- (match-string 1 url)
- url))
- (final-url
- (if id (concat url-no-frag "#" id)
- url))
- )
- (message "%s" final-url)
- (kill-new final-url)))
-
-(defun my-eww-switch-by-title (title-and-buffer)
- "Switches to an eww buffer with selected title."
- (interactive
- (list
- (let ((com-table))
- (dolist (buffer (buffer-list))
- (with-current-buffer buffer
- (when (equal major-mode 'eww-mode)
- (add-to-list
- 'com-table
- (concat (plist-get eww-data :title)
- (propertize (concat " " (buffer-name))
- 'invisible t))))))
- (completing-read "Eww buffer title: " com-table))))
- (string-match "^.* \\(.*\\)$" title-and-buffer)
- (switch-to-buffer (match-string 1 title-and-buffer)))
-
-(provide 'my-web)
-;;; my-web.el ends here
diff --git a/.emacs.d/lisp/my/my-wget.el b/.emacs.d/lisp/my/my-wget.el
deleted file mode 100644
index 5349257..0000000
--- a/.emacs.d/lisp/my/my-wget.el
+++ /dev/null
@@ -1,79 +0,0 @@
-;;; my-wget.el -- Extensions for emacs-wget -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Extensions for emacs-wget.
-
-;;; Code:
-
-
-;; wget
-(require 'wget)
-(require 'my-utils)
-(defvar my-wget-video-archive-directory)
-;; FIXME: this list is rather random...
-(setq my-wget-video-extensions '("mp4" "flv" "mkv" "webm" "ogv" "avi"
- "rmvb"))
-(defun my-wget-ensure-buffer-exists ()
- (get-buffer-create (or wget-process-buffer " *wget*")))
-(defun my-eww-wget-save-page ()
- (interactive)
- (my-wget-ensure-buffer-exists)
- (let* ((filename
- (concat (my-make-filename (plist-get eww-data :title)) ".html"))
- (full-path (concat wget-download-directory "/" filename)))
- (wget-uri (plist-get eww-data :url)
- wget-download-directory
- (list (concat "-O" filename)))
- (kill-new full-path)
- (message "Saved webpage to %s (path copied)." full-path)))
-
-(defun my-wget-async (url filename &optional no-tor move-if-video-or-large)
- (set-process-sentinel
- (my-start-process-with-torsocks
- no-tor "wget" "*wget*" "wget" url "-c" "-O" filename)
- (lambda (_process _event)
- (when (and move-if-video-or-large
- (or
- (> (file-attribute-size (file-attributes filename))
- my-wget-size-threshold)
- (member (file-name-extension filename) my-wget-video-extensions)))
- (setq filename
- (my-rename-and-symlink-back
- filename (expand-file-name my-wget-video-archive-directory) nil)))
- (message "Fetched %s and saved to: %s" url filename))))
-
-(defun wget-async-urls-with-prefix (urls prefix &optional no-tor move-if-video-or-large)
- (let ((i 1))
- (dolist (url urls)
- (my-wget-async
- url
- (concat prefix
- (make-string (- 4 (length (number-to-string i))) ?0)
- (number-to-string i)
- "." (file-name-extension url))
- no-tor move-if-video-or-large)
- (setq i (1+ i)))))
-
-(provide 'my-wget)
-;;; my-wget.el ends here
diff --git a/.emacs.d/lisp/my/my-wikipedia.el b/.emacs.d/lisp/my/my-wikipedia.el
deleted file mode 100644
index 557c553..0000000
--- a/.emacs.d/lisp/my/my-wikipedia.el
+++ /dev/null
@@ -1,182 +0,0 @@
-;;; my-wikipedia.el -- wikipedia client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; wikipedia client.
-
-;;; Code:
-
-
-(require 'my-utils)
-(require 'my-markup)
-(require 'my-net)
-
-;; TODO: much of these can be generalised to any mediawiki site
-(defvar my-wikipedia-lang "en")
-(defvar my-wikipedia-host
- (format "https://%s.wikipedia.org" my-wikipedia-lang))
-(defun my-grok-wikipedia (url)
- "groks wikipedia by url and returns the info of the wikipedia entry."
- (with-current-buffer (url-retrieve-synchronously url)
- (my-delete-http-header)
- (goto-char (point-min))
- (let ((results (my-grok-wikipedia-get-imdb-rating))
- (html
- (libxml-parse-html-region (point-min) (point-max))))
- (append (my-grok-wikipedia-html html url) results))))
-
-(defun my-grok-wikipedia-get-imdb-rating ()
- (when (re-search-forward
- "\\(https://\\(www\\.\\)?imdb.com/title/tt[0-9]+/\\)" nil t)
- (let ((url (match-string 1)))
- (with-current-buffer (url-retrieve-synchronously
- (concat url "ratings"))
- (goto-char (point-min))
- (when
- (re-search-forward
- "\\([0-9,]+\\)\\s-*IMDb.*?\\([0-9\\.]+\\) / 10" nil t)
- (list (cons "IMDB-link" url)
- (cons "IMDB-rating" (match-string 2))
- (cons "IMDB-rated-by" (match-string 1))))))))
-
-(defun my-wikipedia-api-summary (title)
- (my-url-fetch-json
- (format "%s/api/rest_v1/page/summary/%s" my-wikipedia-host title)))
-
-(defun my-grok-wikipedia-summary (url)
- "get wikipedia summary using the rest api"
- (let ((resp (my-wikipedia-api-summary
- (replace-regexp-in-string ".*/wiki/" "" url))))
- (list (cons "Wikipedia-link"
- (alist-get 'page
- (alist-get 'desktop
- (alist-get 'content_urls resp))))
- (cons "Description" (my-clean-property-value
- (alist-get 'extract resp)))
- (cons "Title" (alist-get 'title resp))
- (cons "Cover" (alist-get 'source
- (alist-get 'thumbnail resp)))
- (cons "Latitude" (when-let (coord (alist-get 'coordinates resp))
- (number-to-string (alist-get 'lat coord))))
- (cons "Longitude" (when-let (coord (alist-get 'coordinates resp))
- (number-to-string
- (alist-get 'lon coord)))))))
-(defun my-grok-wikipedia-html (html url)
- (let* ((result (my-grok-wikipedia-summary url))
- (info (car (dom-by-class html "infobox")))
- (ths (dom-by-tag info 'th))
- (tds (mapcar (lambda (th)
- (my-dom-remove-style
- (car (dom-by-tag (dom-parent info th) 'td))))
- ths))
- (len (length ths)))
- (dotimes (unused len)
- (let* ((key (my-clean-property-key
- (dom-texts (pop ths) "")))
- (value (my-clean-property-value
- (dom-texts (pop tds) "")))
- (to-push
- (cond ((string-empty-p key) nil)
- ((string-empty-p value) nil)
- ((string= key "Coordinates")
- (my-grok-wikipedia-clean-coordinates value))
- ((or (member key '("Website" "Source" "URL")))
- (list (cons key (my-grok-wikipedia-fix-url value))))
- (t (list (cons key value))))))
- (mapc (lambda (pair) (push pair result)) to-push)))
- (reverse result)))
-(defun my-grok-wikipedia-clean-coordinates (raw)
- (let ((float-re "\\([-+]?[0-9]+\\(?:\\.[0-9]*\\)?\\)"))
- (string-match (format "%s; %s$" float-re float-re) raw)
- (list (cons "Latitude" (match-string 1 raw))
- (cons "Longitude" (match-string 2 raw)))))
-
-(defun my-grok-wikipedia-fix-url (url)
- (let* ((urlobj (url-generic-parse-url url))
- (filename (url-filename urlobj)))
- (unless (url-type urlobj)
- (setf (url-type urlobj) "https")
- (string-match "^\\([^/]+\\)\\(/.*\\)?$" filename)
- (setf (url-host urlobj) (match-string 1 filename))
- (setf (url-filename urlobj) (or (match-string 2 filename) ""))
- (setf (url-fullness urlobj) t))
- (url-recreate-url urlobj)))
-
-(defun my-wikipedia-api-search (query)
- (my-url-fetch-json
- (format
- "%s/w/api.php?action=query&format=json&list=search&srsearch=%s"
- my-wikipedia-host query)))
-
-(defun my-wikipedia-search (query)
- (interactive "sQuery: ")
- (generic-search-open
- (alist-get 'search
- (alist-get 'query
- (my-wikipedia-api-search query)))
- (format "wikipedia-query:%s" query)
- `((formatter . my-wikipedia-format-result)
- (default-action . my-wikipedia-grok-action)
- (keymap . ,my-wikipedia-button-keymap))))
-
-(defun my-wikipedia-format-result (result)
- (concat
- (format "%s (%d words)"
- (alist-get 'title result)
- (alist-get 'wordcount result))
- (propertize
- (format "\n\n%s"
- (my-wikipedia-highlight-snippet-matches
- (alist-get 'snippet result)))
- 'face 'default)))
-
-(defun my-wikipedia-highlight-snippet-matches (snippet)
- (with-temp-buffer
- (insert snippet)
- (goto-char (point-min))
- (while (re-search-forward "<span class=\"searchmatch\">\\(.*?\\)</span>" nil t)
- (replace-match
- (propertize (match-string 1) 'face 'match)))
- (buffer-string)))
-
-(defun my-wikipedia-grok-action (info)
- (interactive)
- (my-org-grok (format "%s/wiki/%s"
- my-wikipedia-host
- (alist-get 'title info))))
-
-(defun my-wikipedia-fetch-wiki ()
- (interactive)
- (my-fetch-url (format "/wiki/%s?action=raw"
- my-wikipedia-host
- (alist-get 'title
- (get-text-property (point) 'button-data)))))
-
-(defvar my-wikipedia-button-keymap
- (let ((kmap (make-sparse-keymap)))
- (set-keymap-parent kmap button-map)
- (define-key kmap "f" 'my-wikipedia-fetch-wiki)
- kmap))
-
-(provide 'my-wikipedia)
-;;; my-wikipedia.el ends here
diff --git a/.emacs.d/lisp/my/my-ytdl.el b/.emacs.d/lisp/my/my-ytdl.el
deleted file mode 100644
index 0571682..0000000
--- a/.emacs.d/lisp/my/my-ytdl.el
+++ /dev/null
@@ -1,78 +0,0 @@
-;;; my-ytdl.el -- ytdl client -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Free Software Foundation.
-
-;; Author: Yuchen Pei <id@ypei.org>
-;; Package-Requires: ((emacs "28.2"))
-
-;; This file is part of dotfiles.
-
-;; dotfiles is free software: you can redistribute it and/or modify it under
-;; the terms of the GNU Affero General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; dotfiles 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 Affero General
-;; Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public
-;; License along with dotfiles. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; ytdl client. Works with youtube-dl, yt-dlp etc.
-
-;;; Code:
-
-
-(defvar my-ytdl-program "yt-dlp")
-
-(defvar my-ytdl-video-args
- '("--download-archive" "yt-dlp-archive" "-o"
-;; "%(id)s.%(ext)s" ;; for long names
- "%(playlist|.)s/%(playlist_index|)s%(playlist_index&-|)s%(title)s.%(ext)s"
- ;; https://github.com/yt-dlp/yt-dlp/issues/5630
- "-f" "bv*[height<=?720]+ba/best[height<=?720]"
- "--write-subs" "--sub-langs" "en"
- "--write-description"
- "--write-thumbnail"))
-
-(defvar my-ytdl-video-download-dir "~/Downloads"
- "Directory for ytdl to download videos to.")
-
-(defvar my-ytdl-audio-args
- '("-x" "--download-archive" "yt-dlp-archive" "-o"
- ;; "%(id)s.%(ext)s" ;; for long names
- "%(playlist|.)s/%(playlist_index|)s%(playlist_index&-|)s%(title)s.%(ext)s"
- "--write-description"
- "--write-thumbnail"))
-
-(defvar my-ytdl-audio-download-dir "~/Downloads"
- "Directory for ytdl to download audios to.")
-
-(defun my-ytdl-internal (urls type &optional cut-segments)
- (my-with-default-directory (if (eq type 'video)
- my-ytdl-video-download-dir
- my-ytdl-audio-download-dir)
- (apply 'my-start-process-with-torsocks
- (append
- (list nil (format "ytdl-%s" urls) (format "*ytdl-%s*" urls)
- my-ytdl-program)
- (if (eq type 'video) my-ytdl-video-args my-ytdl-audio-args)
- (split-string urls)))))
-
-;;; fixme: autoload
-(defun my-ytdl-video (urls)
- "Download videos with ytdl."
- (interactive "sURL(s): ")
- (my-ytdl-internal urls 'video))
-
-(defun my-ytdl-audio (urls)
- "Download audio with ytdl."
- (interactive "sURL(s): ")
- (my-ytdl-internal urls 'audio))
-
-(provide 'my-ytdl)
-;;; my-ytdl.el ends here
diff --git a/.emacs.d/lisp/my/radix-tree.el b/.emacs.d/lisp/my/radix-tree.el
deleted file mode 100644
index f001198..0000000
--- a/.emacs.d/lisp/my/radix-tree.el
+++ /dev/null
@@ -1,258 +0,0 @@
-;;; radix-tree.el --- A simple library of radix trees -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2016-2022 Free Software Foundation, Inc.
-
-;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
-;; Keywords:
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs 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 General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; NOTE: This is a modified version of radix-tree that comes builtin
-;; with emacs. It allows different compare functions and type. One use
-;; is to build a radix tree of list of string, e.g. from a filesystem
-;; hierarchy.
-
-;; There are many different options for how to represent radix trees
-;; in Elisp. Here I chose a very simple one. A radix-tree can be either:
-;; - a node, of the form ((PREFIX . PTREE) . RTREE) where PREFIX is a string
-;; meaning that everything that starts with PREFIX is in PTREE,
-;; and everything else in RTREE. It also has the property that
-;; everything that starts with the first letter of PREFIX but not with
-;; that whole PREFIX is not in RTREE (i.e. is not in the tree at all).
-;; - anything else is taken as the value to associate with the empty string.
-;; So every node is basically an (improper) alist where each mapping applies
-;; to a different leading letter.
-;;
-;; The main downside of this representation is that the lookup operation
-;; is slower because each level of the tree is an alist rather than some kind
-;; of array, so every level's lookup is O(N) rather than O(1). We could easily
-;; solve this by using char-tables instead of alists, but that would make every
-;; level take up a lot more memory, and it would make the resulting
-;; data structure harder to read (by a human) when printed out.
-
-;;; Code:
-(defvar radix-tree-compare-function 'compare-strings)
-(defvar radix-tree-type 'string)
-
-(defun radix-tree--insert (tree key val i)
- (pcase tree
- (`((,prefix . ,ptree) . ,rtree)
- (let* ((ni (+ i (length prefix)))
- (cmp (funcall radix-tree-compare-function prefix nil nil key i ni)))
- (if (eq t cmp)
- (let ((nptree (radix-tree--insert ptree key val ni)))
- `((,prefix . ,nptree) . ,rtree))
- (let ((n (if (< cmp 0) (- -1 cmp) (- cmp 1))))
- (if (zerop n)
- (let ((nrtree (radix-tree--insert rtree key val i)))
- `((,prefix . ,ptree) . ,nrtree))
- (let* ((nprefix (substring prefix 0 n))
- (kprefix (substring key (+ i n)))
- (pprefix (substring prefix n))
- (ktree (if (equal kprefix "") val
- `((,kprefix . ,val)))))
- `((,nprefix
- . ((,pprefix . ,ptree) . ,ktree))
- . ,rtree)))))))
- (_
- (if (= (length key) i) val
- (let ((prefix (substring key i)))
- `((,prefix . ,val) . ,tree))))))
-
-(defun radix-tree--remove (tree key i)
- (pcase tree
- (`((,prefix . ,ptree) . ,rtree)
- (let* ((ni (+ i (length prefix)))
- (cmp (funcall radix-tree-compare-function prefix nil nil key i ni)))
- (if (eq t cmp)
- (pcase (radix-tree--remove ptree key ni)
- ('nil rtree)
- (`((,pprefix . ,pptree))
- `((,(seq-concatenate radix-tree-type prefix pprefix) . ,pptree) .
- ,rtree))
- (nptree `((,prefix . ,nptree) . ,rtree)))
- (let ((n (if (< cmp 0) (- -1 cmp) (- cmp 1))))
- (if (zerop n)
- (let ((nrtree (radix-tree--remove rtree key i)))
- `((,prefix . ,ptree) . ,nrtree))
- tree)))))
- (_
- (if (= (length key) i) nil tree))))
-
-
-(defun radix-tree--lookup (tree string i)
- (pcase tree
- (`((,prefix . ,ptree) . ,rtree)
- (let* ((ni (+ i (length prefix)))
- (cmp (funcall radix-tree-compare-function prefix nil nil string i ni)))
- (if (eq t cmp)
- (radix-tree--lookup ptree string ni)
- (let ((n (if (< cmp 0) (- -1 cmp) (- cmp 1))))
- (if (zerop n)
- (radix-tree--lookup rtree string i)
- (+ i n))))))
- (val
- (if (and val (equal (length string) i))
- (if (integerp val) `(t . ,val) val)
- i))))
-
-;; (defun radix-tree--trim (tree string i)
-;; (if (= i (length string))
-;; tree
-;; (pcase tree
-;; (`((,prefix . ,ptree) . ,rtree)
-;; (let* ((ni (+ i (length prefix)))
-;; (cmp (funcall radix-tree-compare-function prefix nil nil string i ni))
-;; ;; FIXME: We could compute nrtree more efficiently
-;; ;; whenever cmp is not -1 or 1.
-;; (nrtree (radix-tree--trim rtree string i)))
-;; (if (eq t cmp)
-;; (pcase (radix-tree--trim ptree string ni)
-;; (`nil nrtree)
-;; (`((,pprefix . ,pptree))
-;; `((,(concat prefix pprefix) . ,pptree) . ,nrtree))
-;; (nptree `((,prefix . ,nptree) . ,nrtree)))
-;; (let ((n (if (< cmp 0) (- -1 cmp) (- cmp 1))))
-;; (cond
-;; ((equal (+ n i) (length string))
-;; `((,prefix . ,ptree) . ,nrtree))
-;; (t nrtree))))))
-;; (val val))))
-
-(defun radix-tree--prefixes (tree string i prefixes)
- (pcase tree
- (`((,prefix . ,ptree) . ,rtree)
- (let* ((ni (+ i (length prefix)))
- (cmp (funcall radix-tree-compare-function prefix nil nil string i ni))
- ;; FIXME: We could compute prefixes more efficiently
- ;; whenever cmp is not -1 or 1.
- (prefixes (radix-tree--prefixes rtree string i prefixes)))
- (if (eq t cmp)
- (radix-tree--prefixes ptree string ni prefixes)
- prefixes)))
- (val
- (if (null val)
- prefixes
- (cons (cons (substring string 0 i)
- (if (eq (car-safe val) t) (cdr val) val))
- prefixes)))))
-
-(defun radix-tree--subtree (tree string i)
- (if (equal (length string) i) tree
- (pcase tree
- (`((,prefix . ,ptree) . ,rtree)
- (let* ((ni (+ i (length prefix)))
- (cmp (funcall radix-tree-compare-function prefix nil nil string i ni)))
- (if (eq t cmp)
- (radix-tree--subtree ptree string ni)
- (let ((n (if (< cmp 0) (- -1 cmp) (- cmp 1))))
- (cond
- ((zerop n) (radix-tree--subtree rtree string i))
- ((equal (+ n i) (length string))
- (let ((nprefix (substring prefix n)))
- `((,nprefix . ,ptree))))
- (t nil))))))
- (_ nil))))
-
-;;; Entry points
-
-(defconst radix-tree-empty nil
- "The empty radix-tree.")
-
-(defun radix-tree-insert (tree key val)
- "Insert a mapping from KEY to VAL in radix TREE."
- (when (consp val) (setq val `(t . ,val)))
- (if val (radix-tree--insert tree key val 0)
- (radix-tree--remove tree key 0)))
-
-(defun radix-tree-lookup (tree key)
- "Return the value associated to KEY in radix TREE.
-If not found, return nil."
- (pcase (radix-tree--lookup tree key 0)
- (`(t . ,val) val)
- ((pred numberp) nil)
- (val val)))
-
-(defun radix-tree-subtree (tree string)
- "Return the subtree of TREE rooted at the prefix STRING."
- (radix-tree--subtree tree string 0))
-
-;; (defun radix-tree-trim (tree string)
-;; "Return a TREE which only holds entries \"related\" to STRING.
-;; \"Related\" is here defined as entries where there's a `string-prefix-p' relation
-;; between STRING and the key."
-;; (radix-tree-trim tree string 0))
-
-(defun radix-tree-prefixes (tree string)
- "Return an alist of all bindings in TREE for prefixes of STRING."
- (radix-tree--prefixes tree string 0 nil))
-
-(pcase-defmacro radix-tree-leaf (vpat)
- "Pattern which matches a radix-tree leaf.
-The pattern VPAT is matched against the leaf's carried value."
- ;; We used to use `(pred atom)', but `pcase' doesn't understand that
- ;; `atom' is equivalent to the negation of `consp' and hence generates
- ;; suboptimal code.
- `(or `(t . ,,vpat) (and (pred (not consp)) ,vpat)))
-
-(defun radix-tree-iter-subtrees (tree fun)
- "Apply FUN to every immediate subtree of radix TREE.
-FUN is called with two arguments: PREFIX and SUBTREE.
-You can test if SUBTREE is a leaf (and extract its value) with the
-pcase pattern (radix-tree-leaf PAT)."
- (while tree
- (pcase tree
- (`((,prefix . ,ptree) . ,rtree)
- (funcall fun prefix ptree)
- (setq tree rtree))
- (_ (funcall fun "" tree)
- (setq tree nil)))))
-
-(defun radix-tree-iter-mappings (tree fun &optional prefix)
- "Apply FUN to every mapping in TREE.
-FUN is called with two arguments: KEY and VAL.
-PREFIX is only used internally."
- (radix-tree-iter-subtrees
- tree
- (lambda (p s)
- (let ((nprefix (seq-concatenate radix-tree-type prefix p)))
- (pcase s
- ((radix-tree-leaf v) (funcall fun nprefix v))
- (_ (radix-tree-iter-mappings s fun nprefix)))))))
-
-;; (defun radix-tree->alist (tree)
-;; (let ((al nil))
-;; (radix-tree-iter-mappings tree (lambda (p v) (push (cons p v) al)))
-;; al))
-
-(defun radix-tree-count (tree)
- (let ((i 0))
- (radix-tree-iter-mappings tree (lambda (_k _v) (setq i (1+ i))))
- i))
-
-(declare-function map-apply "map" (function map))
-
-(defun radix-tree-from-map (map)
- ;; Aka (cl-defmethod map-into (map (type (eql 'radix-tree)))) ...)
- (require 'map)
- (let ((rt nil))
- (map-apply (lambda (k v) (setq rt (radix-tree-insert rt k v))) map)
- rt))
-
-(provide 'radix-tree)
-;;; radix-tree.el ends here