changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > infra > home / .emacs.d/ellis.el

changeset 86: a86cb552d6df
parent: 862659891933
child: 978ce75e54af
author: Richard Westhaver <ellis@rwest.io>
date: Wed, 21 Aug 2024 20:29:13 -0400
permissions: -rw-r--r--
description: stumpwm utils
1 ;;; ellis.el --- user Emacs config -*- lexical-binding: t -*-
2 
3 ;; Copyright (C) 2024
4 
5 ;; Author: Richard Westhaver <ellis@rwest.io>
6 
7 ;; This program is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, either version 3 of the License, or
10 ;; (at your option) any later version.
11 
12 ;; This program is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
16 
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
19 
20 ;;; Commentary:
21 
22 ;; This is an example of what you may want to add to your custom
23 ;; config file. Feel free to rip.
24 
25 ;;; Code:
26 (require 'inbox)
27 (require 'sk)
28 (require 'sxp)
29 (require 'ulang)
30 
31 (defalias 'make #'compile)
32 
33 (setopt default-theme 'ef-dream
34  user-lab-directory (join-paths user-home-directory "lab")
35  company-source-directory (join-paths user-home-directory "comp"))
36 
37 ;; (unless (display-graphic-p) (setq default-theme 'wheatgrass))
38 
39 (when (linux-p) (setq dired-listing-switches "-alsh"))
40 
41 (defvar emacs-config-source (join-paths company-source-directory "core/emacs"))
42 
43 ;;;###autoload
44 (defun edit-emacs-config (&optional src)
45  (interactive (list current-prefix-arg))
46  (let ((file (if src
47  (expand-file-name "default.el" emacs-config-source)
48  user-custom-file)))
49  (find-file file)))
50 
51 (keymap-set user-map "e c" #'edit-emacs-config)
52 (keymap-set emacs-lisp-mode-map "C-c C-l" #'load-file)
53 (keymap-set emacs-lisp-mode-map "C-c M-k" #'elisp-byte-compile-file)
54 (keymap-set user-map "v t" #'org-tags-view)
55 
56 (require 'paredit)
57 (repeat-mode)
58 
59 (keymap-set lisp-mode-shared-map "C-(" #'paredit-open-round)
60 (keymap-set lisp-mode-shared-map "M-(" #'paredit-wrap-sexp)
61 (keymap-set lisp-mode-shared-map "M-;" #'paredit-comment-dwim)
62 (keymap-set lisp-mode-shared-map "C-{" #'paredit-backward-barf-sexp)
63 (keymap-set lisp-mode-shared-map "C-}" #'paredit-forward-barf-sexp)
64 (keymap-set lisp-mode-shared-map "C-M-{" #'paredit-forward-slurp-sexp)
65 (keymap-set lisp-mode-shared-map "C-M-}" #'paredit-backward-slurp-sexp)
66 
67 (defun remember-project ()
68  (interactive)
69  (project-remember-project (project-current))
70  project--list)
71 
72 (defun remember-lab-projects ()
73  (interactive)
74  (project-remember-projects-under user-lab-directory t))
75 
76 (defun remember-comp-projects ()
77  (interactive)
78  (project-remember-projects-under company-source-directory t))
79 
80 (keymap-global-set "C-<tab>" #'hippie-expand)
81 (keymap-set minibuffer-local-map "C-<tab>" #'hippie-expand)
82 (keymap-set ctl-x-x-map "p p" #'remember-project)
83 (keymap-set ctl-x-x-map "p l" #'remember-lab-projects)
84 (keymap-set ctl-x-x-map "p c" #'remember-comp-projects)
85 
86 (add-hook 'prog-mode-hook #'skel-minor-mode)
87 (add-hook 'org-mode-hook #'skel-minor-mode)
88 ;; (add-hook 'prog-mode-hook #'company-mode)
89 
90 (add-hook 'notmuch-message-mode-hook #'turn-on-orgtbl)
91 (
92 ouse-package ef-themes :ensure t)
93 
94 (use-package markdown-mode :ensure t)
95 
96 (use-package ol-notmuch :ensure t)
97 
98 (use-package notmuch
99  :ensure t
100  :init
101  (setopt
102  mail-user-agent 'message-user-agent
103  smtpmail-smtp-server "smtp.gmail.com"
104  message-send-mail-function 'message-smtpmail-send-it
105  smtpmail-debug-info t
106  message-default-mail-headers "Cc: \nBcc: \n"
107  message-kill-buffer-on-exit t
108  user-mail-address "richard.westhaver@gmail.com"
109  user-full-name "Richard Westhaver"
110  notmuch-hello-sections '(notmuch-hello-insert-saved-searches
111  notmuch-hello-insert-search
112  notmuch-hello-insert-recent-searches
113  notmuch-hello-insert-alltags)
114  notmuch-show-logo nil
115  notmuch-search-oldest-first nil
116  notmuch-hello-hide-tags '("kill")
117  notmuch-saved-searches '((:name "inbox" :query "tag:inbox" :key "i")
118  (:name "unread" :query "tag:unread" :key "u")
119  (:name "new" :query "tag:new" :key "n")
120  (:name "sent" :query "tag:sent" :key "e")
121  (:name "drafts" :query "tag:draft" :key "d")
122  (:name "all mail" :query "*" :key "a")
123  (:name "todo" :query "tag:todo" :key "t")))
124  :config
125  ;;;###autoload
126  (defun notmuch-exec-offlineimap ()
127  "execute offlineimap command and tag new mail with notmuch"
128  (interactive)
129  (start-process-shell-command "offlineimap"
130  "*offlineimap*"
131  "offlineimap -o")
132  (notmuch-refresh-all-buffers))
133 
134  (defun offlineimap-get-password (host port)
135  (let* ((netrc (netrc-parse (expand-file-name "~/.netrc.gpg")))
136  (hostentry (netrc-machine netrc host port port)))
137  (when hostentry (netrc-get hostentry "password"))))
138 
139  (defun mark-as-read ()
140  "mark message as read."
141  (interactive)
142  (notmuch-search-tag '("-new" "-unread" "-inbox")))
143 
144  (defun mark-as-todo ()
145  "mark message as todo."
146  (interactive)
147  (mark-as-read)
148  (notmuch-search-tag '("-new" "-unread" "-inbox" "+todo")))
149 
150  (defun mark-as-spam ()
151  "mark message as spam."
152  (interactive)
153  (mark-as-read)
154  (notmuch-search-tag (list "+spam")))
155 
156  (keymap-set user-map "e m" #'notmuch)
157  (keymap-set user-map "e M" #'notmuch-exec-offlineimap)
158  (keymap-set notmuch-search-mode-map "S" #'mark-as-spam)
159  (keymap-set notmuch-search-mode-map "R" #'mark-as-read)
160  (keymap-set notmuch-search-mode-map "T" #'mark-as-todo))
161 
162 (use-package elfeed
163  :ensure t
164  :custom
165  elfeed-feeds
166  '(("http://threesixty360.wordpress.com/feed/" blog math)
167  ("http://www.50ply.com/atom.xml" blog dev)
168  ("http://blog.cryptographyengineering.com/feeds/posts/default" blog)
169  ("http://abstrusegoose.com/feed.xml" comic)
170  ("http://accidental-art.tumblr.com/rss" image math)
171  ("http://researchcenter.paloaltonetworks.com/unit42/feed/" security)
172  ("http://curiousprogrammer.wordpress.com/feed/" blog dev)
173  ("http://feeds.feedburner.com/amazingsuperpowers" comic)
174  ("http://amitp.blogspot.com/feeds/posts/default" blog dev)
175  ("http://pages.cs.wisc.edu/~psilord/blog/rssfeed.rss" blog)
176  ("http://www.anticscomic.com/?feed=rss2" comic)
177  ("http://feeds.feedburner.com/blogspot/TPQSS" blog dev)
178  ("http://techchrunch.com/feeds" tech news)
179  ("https://rss.nytimes.com/services/xml/rss/nyt/Technology.xml" tech news)
180  ("https://static.fsf.org/fsforg/rss/news.xml" tech news)
181  ("https://feeds.npr.org/1001/rss.xml" news)
182  ("https://search.cnbc.com/rs/search/combinedcms/view.xml?partnerId=wrss01&id=10000664" fin news)
183  ("https://search.cnbc.com/rs/search/combinedcms/view.xml?partnerId=wrss01&id=19854910" tech news)
184  ("https://search.cnbc.com/rs/search/combinedcms/view.xml?partnerId=wrss01&id=100003114" us news)
185  ("http://arxiv.org/rss/cs" cs rnd)
186  ("http://arxiv.org/rss/math" math rnd)
187  ("http://arxiv.org/rss/q-fin" q-fin rnd)
188  ("http://arxiv.org/rss/stat" stat rnd)
189  ("http://arxiv.org/rss/econ" econ rnd)
190  ;; John Wiegley
191  ("http://newartisans.com/rss.xml" dev blog)
192  ;; comp
193  ;; ("https://lab.rwest.io/comp.atom?feed_token=pHu9qwLkjy4CWJHx9rrJ" comp vc)
194  ("https://www.reddit.com/r/listentothis/.rss" music reddit)
195  ("https://www.ftc.gov/feeds/press-release-consumer-protection.xml" gov ftc)
196  ("https://api2.fcc.gov/edocs/public/api/v1/rss/" gov fcc)
197  )
198  :init
199  (defun yt-dl-it (url)
200  "Downloads the URL in an async shell"
201  (let ((default-directory user-stash-directory))
202  (async-shell-command (format "yt-dlp %s" url))))
203 
204  (defun elfeed-youtube-dl (&optional use-generic-p)
205  "Youtube-DL link"
206  (interactive "P")
207  (let ((entries (elfeed-search-selected)))
208  (cl-loop for entry in entries
209  do (elfeed-untag entry 'unread)
210  when (elfeed-entry-link entry)
211  do (yt-dl-it it))
212  (mapc #'elfeed-search-update-entry entries)
213  (unless (use-region-p) (forward-line))))
214  :config
215  (keymap-set elfeed-search-mode-map "d" 'elfeed-youtube-dl)
216  (keymap-set user-map "e f" #'elfeed)
217  (keymap-set user-map "e F" #'elfeed-update))
218 
219 (use-package elfeed-tube
220  :ensure t
221  :after elfeed
222  :config
223  ;; (elfeed-tube-setup)
224  (elfeed-tube-add-feeds '("detroit techno" "boiler room dj" "brad mehldau" "chris 'daddy' dave"))
225  :bind (:map elfeed-show-mode-map
226  ("F" . elfeed-tube-fetch)
227  ([remap save-buffer] . elfeed-tube-save)
228  :map elfeed-search-mode-map
229  ("F" . elfeed-tube-fetch)
230  ([remap save-buffer] . elfeed-tube-save)))
231 
232 (use-package elfeed-tube-mpv
233  :ensure t
234  :bind (:map elfeed-show-mode-map
235  ("C-c C-f" . elfeed-tube-mpv-follow-mode)
236  ("C-c C-w" . elfeed-tube-mpv-where)))
237 
238 (use-package org-mime :ensure t)
239 
240 (use-package sh-script
241  :hook (sh-mode . flymake-mode))
242 
243 ;;; Org Config
244 (setq publish-dir "/ssh:rurik:/srv/http/compiler.company")
245 (keymap-set user-map "t" #'org-todo)
246 
247 ;; populate org-babel
248 (org-babel-do-load-languages
249  ;; TODO 2021-10-24: bqn, apl, k
250  'org-babel-load-languages '((shell . t)
251  (emacs-lisp . t)
252  (lisp . t)
253  (org . t)
254  (eshell . t)
255  (calc . t)
256  (sed . t)
257  (awk . t)
258  (dot . t)
259  (js . t)
260  (C . t)
261  (python . t)
262  (lua . t)
263  (lilypond . t)))
264 ;;; IRC
265 (setq erc-format-nick-function 'erc-format-@nick)
266 
267 (defun start-erc ()
268  "Connect to IRC."
269  (interactive)
270  (erc-tls :server "irc.libera.chat" :port 6697
271  :client-certificate '("/mnt/y/data/private/krypt/libera.pem"))
272  (setq erc-autojoin-channels-alist '(("irc.libera.chat" "#emacs")
273  ("irc.libera.chat" "#linux")
274  ("irc.libera.chat" "#rust")
275  ("irc.libera.chat" "#btrfs")
276  ("irc.libera.chat" "#lisp")
277  ("irc.libera.chat" "#sbcl")
278  ("irc.oftc.net" "#llvm"))))
279 ;;; Tags
280 ;;;###autoload
281 (defun refresh-tags ()
282  "Refresh TAGS database in `user-emacs-directory'."
283  (interactive)
284  (let ((default-directory user-emacs-directory))
285  (async-shell-command
286  "etags ./*.el \\
287 ./lib/*.el \\
288 ~/comp/core/emacs/*.el \\
289 ~/comp/core/emacs/lib/*.el \\
290 -o TAGS")))
291 
292 (unless (string-equal "hyde" system-name)
293  (add-hook 'dired-mode-hook #'all-the-icons-dired-mode)
294  (add-hook 'ibuffer-mode-hook #'all-the-icons-ibuffer-mode))
295 
296 ;; strangerdanger
297 ;; (setq slime-enable-evaluate-in-emacs t)
298 
299 (defun org-word-count (beg end
300  &optional count-latex-macro-args?
301  count-footnotes?)
302  "Report the number of words in the Org mode buffer or selected region.
303 Ignores:
304 - comments
305 - tables
306 - source code blocks (#+BEGIN_SRC ... #+END_SRC, and inline blocks)
307 - hyperlinks (but does count words in hyperlink descriptions)
308 - tags, priorities, and TODO keywords in headers
309 - sections tagged as 'not for export'.
310 
311 The text of footnote definitions is ignored, unless the optional argument
312 COUNT-FOOTNOTES? is non-nil.
313 
314 If the optional argument COUNT-LATEX-MACRO-ARGS? is non-nil, the word count
315 includes LaTeX macro arguments (the material between {curly braces}).
316 Otherwise, and by default, every LaTeX macro counts as 1 word regardless
317 of its arguments."
318  (interactive "r")
319  (unless mark-active
320  (setf beg (point-min)
321  end (point-max)))
322  (let ((wc 0)
323  (latex-macro-regexp "\\\\[A-Za-z]+\\(\\[[^]]*\\]\\|\\){\\([^}]*\\)}"))
324  (save-excursion
325  (goto-char beg)
326  (while (< (point) end)
327  (cond
328  ;; Ignore comments.
329  ((or (org-in-commented-line) (org-at-table-p))
330  nil)
331  ;; Ignore hyperlinks. But if link has a description, count
332  ;; the words within the description.
333  ((looking-at org-bracket-link-analytic-regexp)
334  (when (match-string-no-properties 5)
335  (let ((desc (match-string-no-properties 5)))
336  (save-match-data
337  (cl-incf wc (length (remove "" (org-split-string
338  desc "\\W")))))))
339  (goto-char (match-end 0)))
340  ((looking-at org-any-link-re)
341  (goto-char (match-end 0)))
342  ;; Ignore source code blocks.
343  ((org-in-regexps-block-p "^#\\+BEGIN_SRC\\W" "^#\\+END_SRC\\W")
344  nil)
345  ;; Ignore inline source blocks, counting them as 1 word.
346  ((save-excursion
347  (backward-char)
348  (looking-at org-babel-inline-src-block-regexp))
349  (goto-char (match-end 0))
350  (setf wc (+ 2 wc)))
351  ;; Count latex macros as 1 word, ignoring their arguments.
352  ((save-excursion
353  (backward-char)
354  (looking-at latex-macro-regexp))
355  (goto-char (if count-latex-macro-args?
356  (match-beginning 2)
357  (match-end 0)))
358  (setf wc (+ 2 wc)))
359  ;; Ignore footnotes.
360  ((and (not count-footnotes?)
361  (or (org-footnote-at-definition-p)
362  (org-footnote-at-reference-p)))
363  nil)
364  (t
365  (let ((contexts (org-context)))
366  (cond
367  ;; Ignore tags and TODO keywords, etc.
368  ((or (assoc :todo-keyword contexts)
369  (assoc :priority contexts)
370  (assoc :keyword contexts)
371  (assoc :checkbox contexts))
372  nil)
373  ;; Ignore sections marked with tags that are
374  ;; excluded from export.
375  ((assoc :tags contexts)
376  (if (intersection (org-get-tags-at) org-export-exclude-tags
377  :test 'equal)
378  (org-forward-same-level 1)
379  nil))
380  (t
381  (cl-incf wc))))))
382  (re-search-forward "\\w+\\W*")))
383  (message (format "%d words in %s." wc
384  (if mark-active "region" "buffer")))))
385 
386 (defun org-check-misformatted-subtree ()
387  "Check misformatted entries in the current buffer."
388  (interactive)
389  (show-all)
390  (org-map-entries
391  (lambda ()
392  (when (and (move-beginning-of-line 2)
393  (not (looking-at org-heading-regexp)))
394  (if (or (and (org-get-scheduled-time (point))
395  (not (looking-at (concat "^.*" org-scheduled-regexp))))
396  (and (org-get-deadline-time (point))
397  (not (looking-at (concat "^.*" org-deadline-regexp)))))
398  (when (y-or-n-p "Fix this subtree? ")
399  (message "Call the function again when you're done fixing this subtree.")
400  (recursive-edit))
401  (message "All subtrees checked."))))))
402 
403 (defun org-sort-list-by-checkbox-type ()
404  "Sort list items according to Checkbox state."
405  (interactive)
406  (org-sort-list
407  nil ?f
408  (lambda ()
409  (if (looking-at org-list-full-item-re)
410  (cdr (assoc (match-string 3)
411  '(("[X]" . 1) ("[-]" . 2) ("[ ]" . 3) (nil . 4))))
412  4))))
413 
414 (defun org-time-string-to-seconds (s)
415  "Convert a string HH:MM:SS to a number of seconds."
416  (cond
417  ((and (stringp s)
418  (string-match "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)" s))
419  (let ((hour (string-to-number (match-string 1 s)))
420  (min (string-to-number (match-string 2 s)))
421  (sec (string-to-number (match-string 3 s))))
422  (+ (* hour 3600) (* min 60) sec)))
423  ((and (stringp s)
424  (string-match "\\([0-9]+\\):\\([0-9]+\\)" s))
425  (let ((min (string-to-number (match-string 1 s)))
426  (sec (string-to-number (match-string 2 s))))
427  (+ (* min 60) sec)))
428  ((stringp s) (string-to-number s))
429  (t s)))
430 
431 (defun org-time-seconds-to-string (secs)
432  "Convert a number of seconds to a time string."
433  (cond ((>= secs 3600) (format-seconds "%h:%.2m:%.2s" secs))
434  ((>= secs 60) (format-seconds "%m:%.2s" secs))
435  (t (format-seconds "%s" secs))))
436 
437 (defmacro with-time (time-output-p &rest exprs)
438  "Evaluate an org-table formula, converting all fields that look
439 like time data to integer seconds. If TIME-OUTPUT-P then return
440 the result as a time value."
441  (list
442  (if time-output-p 'org-time-seconds-to-string 'identity)
443  (cons 'progn
444  (mapcar
445  (lambda (expr)
446  `,(cons (car expr)
447  (mapcar
448  (lambda (el)
449  (if (listp el)
450  (list 'with-time nil el)
451  (org-time-string-to-seconds el)))
452  (cdr expr))))
453  `,@exprs))))
454 
455 (defun org-hex-strip-lead (str)
456  (if (and (> (length str) 2) (string= (substring str 0 2) "0x"))
457  (substring str 2) str))
458 
459 (defun org-hex-to-hex (int)
460  (format "0x%x" int))
461 
462 (defun org-hex-to-dec (str)
463  (cond
464  ((and (stringp str)
465  (string-match "\\([0-9a-f]+\\)" (setf str (org-hex-strip-lead str))))
466  (let ((out 0))
467  (mapc
468  (lambda (ch)
469  (setf out (+ (* out 16)
470  (if (and (>= ch 48) (<= ch 57)) (- ch 48) (- ch 87)))))
471  (coerce (match-string 1 str) 'list))
472  out))
473  ((stringp str) (string-to-number str))
474  (t str)))
475 
476 (defmacro with-hex (hex-output-p &rest exprs)
477  "Evaluate an org-table formula, converting all fields that look
478  like hexadecimal to decimal integers. If HEX-OUTPUT-P then
479  return the result as a hex value."
480  (list
481  (if hex-output-p 'org-hex-to-hex 'identity)
482  (cons 'progn
483  (mapcar
484  (lambda (expr)
485  `,(cons (car expr)
486  (mapcar (lambda (el)
487  (if (listp el)
488  (list 'with-hex nil el)
489  (org-hex-to-dec el)))
490  (cdr expr))))
491  `,@exprs))))
492 
493 (require 'mm-url) ; to include mm-url-decode-entities-string
494 
495 (defun org-insert-link-with-title ()
496  "Insert org link where default description is set to html title."
497  (interactive)
498  (let* ((url (read-string "URL: "))
499  (title (get-html-title-from-url url)))
500  (org-insert-link nil url title)))
501 
502 (defun get-html-title-from-url (url)
503  "Return content in <title> tag."
504  (let (x1 x2 (download-buffer (url-retrieve-synchronously url)))
505  (save-excursion
506  (set-buffer download-buffer)
507  (beginning-of-buffer)
508  (setq x1 (search-forward "<title>"))
509  (search-forward "</title>")
510  (setq x2 (search-backward "<"))
511  (mm-url-decode-entities-string (buffer-substring-no-properties x1 x2)))))
512 
513 (defun org-remove-empty-propert-drawers ()
514  "*Remove all empty property drawers in current file."
515  (interactive)
516  (unless (eq major-mode 'org-mode)
517  (error "You need to turn on Org mode for this function."))
518  (save-excursion
519  (goto-char (point-min))
520  (while (re-search-forward ":PROPERTIES:" nil t)
521  (save-excursion
522  (org-remove-empty-drawer-at "PROPERTIES" (match-beginning 0))))))
523 
524 (defun check-for-clock-out-note ()
525  (interactive)
526  (save-excursion
527  (org-back-to-heading)
528  (let ((tags (org-get-tags)))
529  (and tags (message "tags: %s " tags)
530  (when (member "clocknote" tags)
531  (org-add-note))))))
532 
533 (add-hook 'org-clock-out-hook 'check-for-clock-out-note)
534 
535 (defun org-list-files (dirs ext)
536  "Function to create list of org files in multiple subdirectories.
537 This can be called to generate a list of files for
538 org-agenda-files or org-refile-targets.
539 
540 DIRS is a list of directories.
541 
542 EXT is a list of the extensions of files to be included."
543  (let ((dirs (if (listp dirs)
544  dirs
545  (list dirs)))
546  (ext (if (listp ext)
547  ext
548  (list ext)))
549  files)
550  (mapc
551  (lambda (x)
552  (mapc
553  (lambda (y)
554  (setq files
555  (append files
556  (file-expand-wildcards
557  (concat (file-name-as-directory x) "*" y)))))
558  ext))
559  dirs)
560  (mapc
561  (lambda (x)
562  (when (or (string-match "/.#" x)
563  (string-match "#$" x))
564  (setq files (delete x files))))
565  files)
566  files))
567 
568 (defvar org-agenda-directories (list org-directory
569  ;; (join-paths user-lab-directory "org")
570  (join-paths company-source-directory "org/*")
571  (join-paths company-source-directory "org/*/*"))
572  "List of directories containing org files.")
573 (defvar org-agenda-extensions '(".org")
574  "List of extensions of agenda files")
575 
576 (defun org-set-agenda-files ()
577  (interactive)
578  (setq org-agenda-files
579  (cl-remove-if (lambda (x) (or
580  (string= "archive.org" (file-name-nondirectory x))
581  (string= "archive" (file-name-directory x))))
582  (org-list-files
583  org-agenda-directories
584  org-agenda-extensions))))
585 
586 (with-eval-after-load 'org
587  (org-set-agenda-files))
588 
589 ;;; Skel Config
590 (use-package skel
591  :requires skel
592  :load-path user-emacs-lib-directory
593  :custom
594  tempo-interactive t
595  auto-insert 'no-modify
596  auto-insert-query nil)
597 
598 (use-package skt
599  :requires (skel skt)
600  :load-path user-emacs-lib-directory
601  :custom
602  skt-enable-tempo-elements t
603  skt-delete-duplicate-marks t
604  :config
605  (defvar skt-default-version "0.1.0")
606  (keymap-set skt-minor-mode-map "b" #'tempo-backward-mark)
607  (keymap-set skt-minor-mode-map "f" #'tempo-forward-mark)
608  (keymap-set skt-minor-mode-map "SPC" #'tempo-complete-tag)
609  (keymap-set skt-minor-mode-map "t" #'skt-add-tag)
610 
611  (defvar skt-skeleton-path-function #'abbreviate-file-name
612  "Function to be called when expanding file-header skeletons. Useful to
613 rebind locally inside a project or module, where you want to delete some
614 prefix or replace it.")
615 
616  (defun skt-buffer-path (&optional function)
617  (let ((path (or buffer-file-name (format "%s.lisp" (gensym "scratch-")))))
618  (funcall (or function skt-skeleton-path-function) path)))
619 
620  (defun skt-skelfile-path ()
621  (if (string= (file-name-nondirectory buffer-file-name) "skelfile")
622  "skelfile"
623  (skt-buffer-path)))
624 
625  ;; functions
626  (skt-define-function capture (:abbrev "capture" :tag t) org-capture)
627  (skt-define-function agenda (:abbrev "agenda" :tag t) org-agenda)
628  (skt-define-function mjump (:abbrev "mjump" :tag t) bookmark-jump)
629  (skt-define-function bjump (:abbrev "bjump" :tag t) ibuffer-jump)
630  (skt-define-function rjump (:abbrev "rjump" :tag t)
631  (lambda () (jump-to-register (read-char "register: "))))
632  (skt-define-function pjump (:abbrev "pjump" :tag t) (lambda () (project-switch-project default-directory)))
633 
634  ;; templates
635  (skt-define-template readme (:mode org-mode :tag t)
636  "#+title: " (p "title: ") n
637  "#+description: " (p "description: ") n
638  "#+author: " user-full-name n
639  "#+email:" user-mail-address n
640  "#+setupfile: clean.theme" n
641  "#+export_file_name: index" n>
642  p n> n>
643  ":info:" n>
644  "+ version :: " skt-default-version n
645  ":end:" n>)
646 
647  (skt-define-template clean.theme (:mode org-mode :tag t)
648  "#+setupfile: " (join-paths company-cdn-url "org/clean.theme"))
649 
650  ;; TODO 2024-06-04:
651  ;; (skt-define-template defsystem (:mode lisp-mode :tag t :abbrev "defsystem"))
652  ;; (skt-define-template defpackage (:mode lisp-mode :tag t :abbrev "defpackage"))
653  ;; (skt-define-template defpkg (:mode lisp-mode :tag t :abbrev "defpkg"))
654 
655  (skt-define-template defmacro (:abbrev "(defmacro" :tag t :mode lisp-mode)
656  "(defmacro " (p "Name: ") " (" (p "Args: ") ")" > n> r ")")
657 
658  (skt-define-template defun (:abbrev "(defun" :tag t :mode lisp-mode)
659  "(defun " (p "Name: ") " (" (p "Args: ") ")" > n> r ")")
660 
661  (skt-define-template defvar (:abbrev "(defvar" :tag t :mode lisp-mode)
662  > "(defvar " > r ")")
663 
664  ;; skeletons
665  (skt-define-skeleton head (:abbrev "head" :mode lisp-mode)
666  "description: "
667  ";;; " (skt-buffer-path 'file-name-nondirectory) " --- " str \n \n ";; " _ \n \n ";;; Code:" \n >)
668 
669  (skt-define-skeleton head (:abbrev "head" :mode skel-mode)
670  "description: "
671  ";;; " (skt-skelfile-path) " --- " str " -*- mode: skel; -*-" \n _)
672 
673  (skt-define-skeleton head (:abbrev "head" :mode org-mode)
674  "title: "
675  "#+title: " str \n
676  "#+author: " (skeleton-read "author: ") \n
677  "#+description: " (skeleton-read "description: ") \n
678  "#+setupfile: clean.theme" \n > _)
679 
680  (skt-define-skeleton head (:abbrev "head" :mode rust-mode)
681  "description: "
682  "//! " (skt-buffer-path 'file-name-nondirectory) " --- " str \n \n "// " _ \n \n "//! Code: " \n >)
683 
684  (skt-define-skeleton system-head (:abbrev "system-head" :mode lisp-mode)
685  "system-name: "
686  ";;; " (skt-buffer-path) " --- "
687  '(setq v1 (file-name-base (skt-buffer-path))) (capitalize v1)
688  " Sytem Definitions" \n
689  > "(defsystem :" v1 \n
690  > ":depends-on (:std :log)" \n
691  > ":components ((:file \"pkg\")" _ "))")
692 
693  (skt-define-skeleton pkg-head (:abbrev "pkg-head" :mode lisp-mode)
694  "ignored"
695  ";;; " (skt-buffer-path 'file-name-nondirectory) " --- "
696  '(setq v1 (skeleton-read "name: ")) v1 " Package Definitions" \n
697  > "(defpkg :" v1 \n
698  > ":use (:std :log))" \n \n
699  > "(in-package :" v1 ")" \n >)
700 
701  (skt-define-skeleton crate-head (:abbrev "crate-head" :mode conf-toml-mode)
702  "ignored"
703  "### " (skt-buffer-path 'file-name-nondirectory) " --- "
704  '(setq v1 (skeleton-read "name: ")) v1 " Cargo Manifest" \n >
705  "[package]" \n
706  "name = \"" v1 "\"" \n
707  "version = \"" skt-default-version "\"" \n
708  "[dependencies]" \n >)
709 
710  (skt-define-skeleton local-vars
711  (:tag t :abbrev "local-vars"
712  :docstring "Insert a local variables section. Use current comment syntax if any.")
713  (completing-read "Mode: " obarray
714  (lambda (symbol)
715  (if (commandp symbol)
716  (string-match "-mode$" (symbol-name symbol))))
717  t)
718  '(save-excursion
719  (if (re-search-forward page-delimiter nil t)
720  (error "Not on last page")))
721  comment-start "Local Variables:" comment-end \n
722  comment-start "mode: " str
723  & -5 | '(kill-line 0) & -1 | comment-end \n
724  ( (completing-read (format "Variable, %s: " skeleton-subprompt)
725  obarray
726  (lambda (symbol)
727  (or (eq symbol 'eval)
728  (custom-variable-p symbol)))
729  t)
730  comment-start str ": "
731  (read-from-minibuffer "Expression: " nil read-expression-map nil
732  'read-expression-history) | _
733  comment-end \n)
734  resume:
735  comment-start "End:" comment-end \n)
736 
737  ;; autoinsert
738  (skt-register-auto-insert "skelfile" #'skt-template-skel-head)
739  (skt-register-auto-insert "readme.org" #'skt-template-org-readme)
740  (skt-register-auto-insert "Cargo.toml" #'skt-template-conf-toml-crate-head)
741  (skt-register-auto-insert "pkg.lisp" #'skt-template-lisp-pkg-head)
742  (skt-register-auto-insert ".*[.]asd" #'skt-template-lisp-system-head)
743  (skt-register-auto-insert ".*[.]lisp" #'skt-template-lisp-head)
744  (skt-register-auto-insert ".*[.].rs" #'skt-template-rust-head)
745  (auto-insert-mode t)
746  (keymap-set skel-minor-mode-map "C-<return>" 'company-tempo))
747 
748 ;;; glossary
749 ;; (with-eval-after-load 'org-glossary
750 ;; (setq org-glossary-collection-root (join-paths company-source-directory "org/meta/"))
751 ;; (cl-pushnew '("Terms" . glossary) org-glossary-headings)
752 ;; (cl-pushnew '("Acronyms" . acronym) org-glossary-headings))
753 
754 (provide 'ellis)
755 ;; ellis.el ends here