changelog shortlog graph tags branches changeset files revisions annotate raw help

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

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