changelog shortlog graph tags branches changeset files revisions annotate raw help

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

changeset 47: 02dec5169a1e
parent: b9e2f76128bb
child: f3c32ffdbbef
author: Richard Westhaver <ellis@rwest.io>
date: Wed, 19 Jun 2024 15:32:46 -0400
permissions: -rw-r--r--
description: emacs updates
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 (keymap-set user-map "t" #'org-todo)
234 
235 ;; populate org-babel
236 (org-babel-do-load-languages
237  ;; TODO 2021-10-24: bqn, apl, k
238  'org-babel-load-languages '((shell . t)
239  (emacs-lisp . t)
240  (lisp . t)
241  (org . t)
242  (eshell . t)
243  (calc . t)
244  (sed . t)
245  (awk . t)
246  (dot . t)
247  (js . t)
248  (C . t)
249  (python . t)
250  (lua . t)
251  (lilypond . t)))
252 ;;; IRC
253 (setq erc-format-nick-function 'erc-format-@nick)
254 
255 (defun start-erc ()
256  "Connect to IRC."
257  (interactive)
258  (erc-tls :server "irc.libera.chat" :port 6697
259  :client-certificate '("/mnt/y/data/private/krypt/libera.pem"))
260  (setq erc-autojoin-channels-alist '(("irc.libera.chat" "#emacs")
261  ("irc.libera.chat" "#linux")
262  ("irc.libera.chat" "#rust")
263  ("irc.libera.chat" "#btrfs")
264  ("irc.libera.chat" "#lisp")
265  ("irc.libera.chat" "#sbcl")
266  ("irc.oftc.net" "#llvm"))))
267 ;;; Tags
268 ;;;###autoload
269 (defun refresh-tags ()
270  "Refresh TAGS database in `user-emacs-directory'."
271  (interactive)
272  (let ((default-directory user-emacs-directory))
273  (async-shell-command
274  "etags ./*.el \\
275 ./lib/*.el \\
276 ~/comp/core/emacs/*.el \\
277 ~/comp/core/emacs/lib/*.el \\
278 -o TAGS")))
279 
280 (unless (string-equal "hyde" system-name)
281  (add-hook 'dired-mode-hook #'all-the-icons-dired-mode)
282  (add-hook 'ibuffer-mode-hook #'all-the-icons-ibuffer-mode))
283 
284 ;; strangerdanger
285 ;; (setq slime-enable-evaluate-in-emacs t)
286 
287 (defun org-word-count (beg end
288  &optional count-latex-macro-args?
289  count-footnotes?)
290  "Report the number of words in the Org mode buffer or selected region.
291 Ignores:
292 - comments
293 - tables
294 - source code blocks (#+BEGIN_SRC ... #+END_SRC, and inline blocks)
295 - hyperlinks (but does count words in hyperlink descriptions)
296 - tags, priorities, and TODO keywords in headers
297 - sections tagged as 'not for export'.
298 
299 The text of footnote definitions is ignored, unless the optional argument
300 COUNT-FOOTNOTES? is non-nil.
301 
302 If the optional argument COUNT-LATEX-MACRO-ARGS? is non-nil, the word count
303 includes LaTeX macro arguments (the material between {curly braces}).
304 Otherwise, and by default, every LaTeX macro counts as 1 word regardless
305 of its arguments."
306  (interactive "r")
307  (unless mark-active
308  (setf beg (point-min)
309  end (point-max)))
310  (let ((wc 0)
311  (latex-macro-regexp "\\\\[A-Za-z]+\\(\\[[^]]*\\]\\|\\){\\([^}]*\\)}"))
312  (save-excursion
313  (goto-char beg)
314  (while (< (point) end)
315  (cond
316  ;; Ignore comments.
317  ((or (org-in-commented-line) (org-at-table-p))
318  nil)
319  ;; Ignore hyperlinks. But if link has a description, count
320  ;; the words within the description.
321  ((looking-at org-bracket-link-analytic-regexp)
322  (when (match-string-no-properties 5)
323  (let ((desc (match-string-no-properties 5)))
324  (save-match-data
325  (cl-incf wc (length (remove "" (org-split-string
326  desc "\\W")))))))
327  (goto-char (match-end 0)))
328  ((looking-at org-any-link-re)
329  (goto-char (match-end 0)))
330  ;; Ignore source code blocks.
331  ((org-in-regexps-block-p "^#\\+BEGIN_SRC\\W" "^#\\+END_SRC\\W")
332  nil)
333  ;; Ignore inline source blocks, counting them as 1 word.
334  ((save-excursion
335  (backward-char)
336  (looking-at org-babel-inline-src-block-regexp))
337  (goto-char (match-end 0))
338  (setf wc (+ 2 wc)))
339  ;; Count latex macros as 1 word, ignoring their arguments.
340  ((save-excursion
341  (backward-char)
342  (looking-at latex-macro-regexp))
343  (goto-char (if count-latex-macro-args?
344  (match-beginning 2)
345  (match-end 0)))
346  (setf wc (+ 2 wc)))
347  ;; Ignore footnotes.
348  ((and (not count-footnotes?)
349  (or (org-footnote-at-definition-p)
350  (org-footnote-at-reference-p)))
351  nil)
352  (t
353  (let ((contexts (org-context)))
354  (cond
355  ;; Ignore tags and TODO keywords, etc.
356  ((or (assoc :todo-keyword contexts)
357  (assoc :priority contexts)
358  (assoc :keyword contexts)
359  (assoc :checkbox contexts))
360  nil)
361  ;; Ignore sections marked with tags that are
362  ;; excluded from export.
363  ((assoc :tags contexts)
364  (if (intersection (org-get-tags-at) org-export-exclude-tags
365  :test 'equal)
366  (org-forward-same-level 1)
367  nil))
368  (t
369  (cl-incf wc))))))
370  (re-search-forward "\\w+\\W*")))
371  (message (format "%d words in %s." wc
372  (if mark-active "region" "buffer")))))
373 
374 (defun org-check-misformatted-subtree ()
375  "Check misformatted entries in the current buffer."
376  (interactive)
377  (show-all)
378  (org-map-entries
379  (lambda ()
380  (when (and (move-beginning-of-line 2)
381  (not (looking-at org-heading-regexp)))
382  (if (or (and (org-get-scheduled-time (point))
383  (not (looking-at (concat "^.*" org-scheduled-regexp))))
384  (and (org-get-deadline-time (point))
385  (not (looking-at (concat "^.*" org-deadline-regexp)))))
386  (when (y-or-n-p "Fix this subtree? ")
387  (message "Call the function again when you're done fixing this subtree.")
388  (recursive-edit))
389  (message "All subtrees checked."))))))
390 
391 (defun org-sort-list-by-checkbox-type ()
392  "Sort list items according to Checkbox state."
393  (interactive)
394  (org-sort-list
395  nil ?f
396  (lambda ()
397  (if (looking-at org-list-full-item-re)
398  (cdr (assoc (match-string 3)
399  '(("[X]" . 1) ("[-]" . 2) ("[ ]" . 3) (nil . 4))))
400  4))))
401 
402 (defun org-time-string-to-seconds (s)
403  "Convert a string HH:MM:SS to a number of seconds."
404  (cond
405  ((and (stringp s)
406  (string-match "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)" s))
407  (let ((hour (string-to-number (match-string 1 s)))
408  (min (string-to-number (match-string 2 s)))
409  (sec (string-to-number (match-string 3 s))))
410  (+ (* hour 3600) (* min 60) sec)))
411  ((and (stringp s)
412  (string-match "\\([0-9]+\\):\\([0-9]+\\)" s))
413  (let ((min (string-to-number (match-string 1 s)))
414  (sec (string-to-number (match-string 2 s))))
415  (+ (* min 60) sec)))
416  ((stringp s) (string-to-number s))
417  (t s)))
418 
419 (defun org-time-seconds-to-string (secs)
420  "Convert a number of seconds to a time string."
421  (cond ((>= secs 3600) (format-seconds "%h:%.2m:%.2s" secs))
422  ((>= secs 60) (format-seconds "%m:%.2s" secs))
423  (t (format-seconds "%s" secs))))
424 
425 (defmacro with-time (time-output-p &rest exprs)
426  "Evaluate an org-table formula, converting all fields that look
427 like time data to integer seconds. If TIME-OUTPUT-P then return
428 the result as a time value."
429  (list
430  (if time-output-p 'org-time-seconds-to-string 'identity)
431  (cons 'progn
432  (mapcar
433  (lambda (expr)
434  `,(cons (car expr)
435  (mapcar
436  (lambda (el)
437  (if (listp el)
438  (list 'with-time nil el)
439  (org-time-string-to-seconds el)))
440  (cdr expr))))
441  `,@exprs))))
442 
443 (defun org-hex-strip-lead (str)
444  (if (and (> (length str) 2) (string= (substring str 0 2) "0x"))
445  (substring str 2) str))
446 
447 (defun org-hex-to-hex (int)
448  (format "0x%x" int))
449 
450 (defun org-hex-to-dec (str)
451  (cond
452  ((and (stringp str)
453  (string-match "\\([0-9a-f]+\\)" (setf str (org-hex-strip-lead str))))
454  (let ((out 0))
455  (mapc
456  (lambda (ch)
457  (setf out (+ (* out 16)
458  (if (and (>= ch 48) (<= ch 57)) (- ch 48) (- ch 87)))))
459  (coerce (match-string 1 str) 'list))
460  out))
461  ((stringp str) (string-to-number str))
462  (t str)))
463 
464 (defmacro with-hex (hex-output-p &rest exprs)
465  "Evaluate an org-table formula, converting all fields that look
466  like hexadecimal to decimal integers. If HEX-OUTPUT-P then
467  return the result as a hex value."
468  (list
469  (if hex-output-p 'org-hex-to-hex 'identity)
470  (cons 'progn
471  (mapcar
472  (lambda (expr)
473  `,(cons (car expr)
474  (mapcar (lambda (el)
475  (if (listp el)
476  (list 'with-hex nil el)
477  (org-hex-to-dec el)))
478  (cdr expr))))
479  `,@exprs))))
480 
481 (require 'mm-url) ; to include mm-url-decode-entities-string
482 
483 (defun org-insert-link-with-title ()
484  "Insert org link where default description is set to html title."
485  (interactive)
486  (let* ((url (read-string "URL: "))
487  (title (get-html-title-from-url url)))
488  (org-insert-link nil url title)))
489 
490 (defun get-html-title-from-url (url)
491  "Return content in <title> tag."
492  (let (x1 x2 (download-buffer (url-retrieve-synchronously url)))
493  (save-excursion
494  (set-buffer download-buffer)
495  (beginning-of-buffer)
496  (setq x1 (search-forward "<title>"))
497  (search-forward "</title>")
498  (setq x2 (search-backward "<"))
499  (mm-url-decode-entities-string (buffer-substring-no-properties x1 x2)))))
500 
501 (defun org-remove-empty-propert-drawers ()
502  "*Remove all empty property drawers in current file."
503  (interactive)
504  (unless (eq major-mode 'org-mode)
505  (error "You need to turn on Org mode for this function."))
506  (save-excursion
507  (goto-char (point-min))
508  (while (re-search-forward ":PROPERTIES:" nil t)
509  (save-excursion
510  (org-remove-empty-drawer-at "PROPERTIES" (match-beginning 0))))))
511 
512 (defun check-for-clock-out-note ()
513  (interactive)
514  (save-excursion
515  (org-back-to-heading)
516  (let ((tags (org-get-tags)))
517  (and tags (message "tags: %s " tags)
518  (when (member "clocknote" tags)
519  (org-add-note))))))
520 
521 (add-hook 'org-clock-out-hook 'check-for-clock-out-note)
522 
523 (defun org-list-files (dirs ext)
524  "Function to create list of org files in multiple subdirectories.
525 This can be called to generate a list of files for
526 org-agenda-files or org-refile-targets.
527 
528 DIRS is a list of directories.
529 
530 EXT is a list of the extensions of files to be included."
531  (let ((dirs (if (listp dirs)
532  dirs
533  (list dirs)))
534  (ext (if (listp ext)
535  ext
536  (list ext)))
537  files)
538  (mapc
539  (lambda (x)
540  (mapc
541  (lambda (y)
542  (setq files
543  (append files
544  (file-expand-wildcards
545  (concat (file-name-as-directory x) "*" y)))))
546  ext))
547  dirs)
548  (mapc
549  (lambda (x)
550  (when (or (string-match "/.#" x)
551  (string-match "#$" x))
552  (setq files (delete x files))))
553  files)
554  files))
555 
556 (defvar org-agenda-directories (list org-directory user-lab-directory)
557  "List of directories containing org files.")
558 (defvar org-agenda-extensions '(".org")
559  "List of extensions of agenda files")
560 
561 (defun org-set-agenda-files ()
562  (interactive)
563  (setq org-agenda-files (org-list-files
564  org-agenda-directories
565  org-agenda-extensions)))
566 
567 (add-hook 'after-init-hook 'org-set-agenda-files)
568 
569 ;;; Skel Config
570 (use-package skel
571  :requires skel
572  :load-path user-emacs-lib-directory
573  :custom
574  tempo-interactive t
575  auto-insert 'no-modify
576  auto-insert-query nil)
577 
578 (use-package skt
579  :requires (skel skt)
580  :load-path user-emacs-lib-directory
581  :custom
582  skt-enable-tempo-elements t
583  skt-delete-duplicate-marks t
584  :config
585  (defvar skt-default-version "0.1.0")
586  (keymap-set skt-minor-mode-map "b" #'tempo-backward-mark)
587  (keymap-set skt-minor-mode-map "f" #'tempo-forward-mark)
588  (keymap-set skt-minor-mode-map "SPC" #'tempo-complete-tag)
589  (keymap-set skt-minor-mode-map "t" #'skt-add-tag)
590 
591  (defvar skt-skeleton-path-function #'abbreviate-file-name
592  "Function to be called when expanding file-header skeletons. Useful to
593 rebind locally inside a project or module, where you want to delete some
594 prefix or replace it.")
595 
596  (defun skt-buffer-path (&optional function)
597  (let ((path (or buffer-file-name (format "%s.lisp" (gensym "scratch-")))))
598  (funcall (or function skt-skeleton-path-function) path)))
599 
600  (defun skt-skelfile-path ()
601  (if (string= (file-name-nondirectory buffer-file-name) "skelfile")
602  "skelfile"
603  (skt-buffer-path)))
604 
605  ;; functions
606  (skt-define-function capture (:abbrev "capture" :tag t) org-capture)
607  (skt-define-function agenda (:abbrev "agenda" :tag t) org-agenda)
608  (skt-define-function mjump (:abbrev "mjump" :tag t) bookmark-jump)
609  (skt-define-function bjump (:abbrev "bjump" :tag t) ibuffer-jump)
610  (skt-define-function rjump (:abbrev "rjump" :tag t)
611  (lambda () (jump-to-register (read-char "register: "))))
612  (skt-define-function pjump (:abbrev "pjump" :tag t) (lambda () (project-switch-project default-directory)))
613 
614  ;; templates
615  (skt-define-template readme (:mode org-mode :tag t)
616  "#+title: " (p "title: ") n
617  "#+description: " (p "description: ") n
618  "#+author: " user-full-name n
619  "#+email:" user-mail-address n
620  "#+setupfile: clean.theme" n
621  "#+export_file_name: index" n>
622  p n> n>
623  ":info:" n>
624  "+ version :: " skt-default-version n
625  ":end:" n>)
626 
627  (skt-define-template clean.theme (:mode org-mode :tag t)
628  "#+setupfile: " (join-paths company-cdn-url "org/clean.theme"))
629 
630  ;; TODO 2024-06-04:
631  ;; (skt-define-template defsystem (:mode lisp-mode :tag t :abbrev "defsystem"))
632  ;; (skt-define-template defpackage (:mode lisp-mode :tag t :abbrev "defpackage"))
633  ;; (skt-define-template defpkg (:mode lisp-mode :tag t :abbrev "defpkg"))
634 
635  (skt-define-template defmacro (:abbrev "(defmacro" :tag t :mode lisp-mode)
636  "(defmacro " (p "Name: ") " (" (p "Args: ") ")" > n> r ")")
637 
638  (skt-define-template defun (:abbrev "(defun" :tag t :mode lisp-mode)
639  "(defun " (p "Name: ") " (" (p "Args: ") ")" > n> r ")")
640 
641  (skt-define-template defvar (:abbrev "(defvar" :tag t :mode lisp-mode)
642  > "(defvar " > r ")")
643 
644  ;; skeletons
645  (skt-define-skeleton head (:abbrev "head" :mode lisp-mode)
646  "description: "
647  ";;; " (skt-buffer-path 'file-name-nondirectory) " --- " str \n \n ";; " _ \n \n ";;; Code:" \n >)
648 
649  (skt-define-skeleton head (:abbrev "head" :mode skel-mode)
650  "description: "
651  ";;; " (skt-skelfile-path) " --- " str " -*- mode: skel; -*-" \n _)
652 
653  (skt-define-skeleton head (:abbrev "head" :mode org-mode)
654  "title: "
655  "#+title: " str \n
656  "#+author: " (skeleton-read "author: ") \n
657  "#+description: " (skeleton-read "description: ") \n
658  "#+setupfile: clean.theme" \n > _)
659 
660  (skt-define-skeleton head (:abbrev "head" :mode rust-mode)
661  "description: "
662  "//! " (skt-buffer-path 'file-name-nondirectory) " --- " str \n \n "// " _ \n \n "//! Code: " \n >)
663 
664  (skt-define-skeleton system-head (:abbrev "system-head" :mode lisp-mode)
665  "system-name: "
666  ";;; " (skt-buffer-path) " --- "
667  '(setq v1 (file-name-base (skt-buffer-path))) (capitalize v1)
668  " Sytem Definitions" \n
669  > "(defsystem :" v1 \n
670  > ":depends-on (:std :log)" \n
671  > ":components ((:file \"pkg\")" _ "))")
672 
673  (skt-define-skeleton pkg-head (:abbrev "pkg-head" :mode lisp-mode)
674  "ignored"
675  ";;; " (skt-buffer-path 'file-name-nondirectory) " --- "
676  '(setq v1 (skeleton-read "name: ")) v1 " Package Definitions" \n
677  > "(defpkg :" v1 \n
678  > ":use (:std :log))" \n \n
679  > "(in-package :" v1 ")" \n >)
680 
681  (skt-define-skeleton crate-head (:abbrev "crate-head" :mode conf-toml-mode)
682  "ignored"
683  "### " (skt-buffer-path 'file-name-nondirectory) " --- "
684  '(setq v1 (skeleton-read "name: ")) v1 " Cargo Manifest" \n >
685  "[package]" \n
686  "name = \"" v1 "\"" \n
687  "version = \"" skt-default-version "\"" \n
688  "[dependencies]" \n >)
689 
690  (skt-define-skeleton local-vars
691  (:tag t :abbrev "local-vars"
692  :docstring "Insert a local variables section. Use current comment syntax if any.")
693  (completing-read "Mode: " obarray
694  (lambda (symbol)
695  (if (commandp symbol)
696  (string-match "-mode$" (symbol-name symbol))))
697  t)
698  '(save-excursion
699  (if (re-search-forward page-delimiter nil t)
700  (error "Not on last page")))
701  comment-start "Local Variables:" comment-end \n
702  comment-start "mode: " str
703  & -5 | '(kill-line 0) & -1 | comment-end \n
704  ( (completing-read (format "Variable, %s: " skeleton-subprompt)
705  obarray
706  (lambda (symbol)
707  (or (eq symbol 'eval)
708  (custom-variable-p symbol)))
709  t)
710  comment-start str ": "
711  (read-from-minibuffer "Expression: " nil read-expression-map nil
712  'read-expression-history) | _
713  comment-end \n)
714  resume:
715  comment-start "End:" comment-end \n)
716 
717  ;; autoinsert
718  (skt-register-auto-insert "skelfile" #'skt-template-skel-head)
719  (skt-register-auto-insert "readme.org" #'skt-template-org-readme)
720  (skt-register-auto-insert "Cargo.toml" #'skt-template-conf-toml-crate-head)
721  (skt-register-auto-insert "pkg.lisp" #'skt-template-lisp-pkg-head)
722  (skt-register-auto-insert ".*[.]asd" #'skt-template-lisp-system-head)
723  (skt-register-auto-insert ".*[.]lisp" #'skt-template-lisp-head)
724  (skt-register-auto-insert ".*[.].rs" #'skt-template-rust-head)
725  (auto-insert-mode t)
726  (keymap-set skel-minor-mode-map "C-<return>" 'company-tempo))
727 
728 (provide 'ellis)
729 ;;; ellis.el ends here