diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el
index 35e1accc..70a8d444 100644
--- a/emacs/.emacs.d/init.el
+++ b/emacs/.emacs.d/init.el
@@ -381,7 +381,9 @@ DEFINITIONS is a sequence of string and command pairs."
(defmacro prot-emacs-abbrev (table &rest definitions)
"Expand abbrev DEFINITIONS for the given TABLE.
DEFINITIONS is a sequence of string pairs mapping the
-abbreviation to its expansion."
+abbreviation to its expansion.
+
+Also see `prot-emacs-abbrev-function'."
(declare (indent 1))
(unless (zerop (% (length definitions) 2))
(error "Uneven number of key+command pairs"))
@@ -394,6 +396,24 @@ abbreviation to its expansion."
`(define-abbrev table ,abbrev ,expansion)))
(seq-split definitions 2))))
+(defmacro prot-emacs-abbrev-function (table &rest definitions)
+ "Expand abbrev DEFINITIONS for the given TABLE.
+DEFINITIONS is a sequence of string and function symbol pairs
+mapping the abbreviation to its expansion.
+
+Also see `prot-emacs-abbrev'."
+ (declare (indent 1))
+ (unless (zerop (% (length definitions) 2))
+ (error "Uneven number of key+command pairs"))
+ `(when-let (((abbrev-table-p ,table))
+ (table ,table))
+ ,@(mapcar
+ (lambda (pair)
+ (when-let ((abbrev (car pair))
+ (expansion (cadr pair)))
+ `(define-abbrev table ,abbrev "" ,expansion)))
+ (seq-split definitions 2))))
+
(defun prot-emacs-return-loaded-packages ()
"Return a list of all loaded packages.
Here packages include both `prot-emacs-loaded-packages' and
@@ -413,7 +433,7 @@ that is expanded with the `prot-emacs-package' macro."
(defconst prot-emacs-font-lock-keywords
'(("(\\(prot-emacs-package\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?"
(2 font-lock-constant-face nil t))
- ("(\\(prot-emacs-\\(keybind\\|abbrev\\)\\)\\_>[ \t']*\\(\\(\\sw\\|\\s_\\)+\\)?"
+ ("(\\(prot-emacs-\\(keybind\\|abbrev\\|abbrev-function\\)\\)\\_>[ \t']*\\(\\(\\sw\\|\\s_\\)+\\)?"
(3 font-lock-variable-name-face nil t))
("(\\(prot-emacs-comment\\)\\_>[ \t']*"
(1 font-lock-preprocessor-face nil t))))
diff --git a/emacs/.emacs.d/prot-emacs-modules/prot-emacs-completion.el b/emacs/.emacs.d/prot-emacs-modules/prot-emacs-completion.el
index e677f27f..4e51621b 100644
--- a/emacs/.emacs.d/prot-emacs-modules/prot-emacs-completion.el
+++ b/emacs/.emacs.d/prot-emacs-modules/prot-emacs-completion.el
@@ -166,23 +166,49 @@
"texmacs" "TeXmacs"
"typescript" "TypeScript"
"visavis" "vis-à-vis"
- "youtube" "YouTube")
+ "youtube" "YouTube"
+ ":up" "🙃"
+ ":uni" "🦄"
+ ":laugh" "🤣"
+ ":smile" "😀"
+ ":sun" "☀️")
+
+ ;; Allow abbrevs with a prefix colon or underscore. I demonstrated
+ ;; this here: .
+ (abbrev-table-put text-mode-abbrev-table :regexp "\\(?:^\\|[\t\s]+\\)\\(?1:[:_].*\\|.*\\)")
(with-eval-after-load 'message
(prot-emacs-abbrev message-mode-abbrev-table
"bestregards" "Best regards,\nProtesilaos (or simply \"Prot\")"
"allthebest" "All the best,\nProtesilaos (or simply \"Prot\")"
+ "niceday" "Have a nice day,\nProtesilaos (or simply \"Prot\")"
"abest" "All the best,\nProt"
"bregards" "Best regards,\nProt"
+ "nday" "Have a nice day,\nProt"
"nosrht" "P.S. I am phasing out SourceHut:
.
Development continues on GitHub with GitLab as a mirror."))
+ ;; Unlike the above, the `prot-emacs-abbrev-function' macro does not
+ ;; expand a static text, but calls a function which dynamically
+ ;; expands into the requisite form.
+ (require 'prot-abbrev)
+ (prot-emacs-abbrev-function global-abbrev-table
+ "metime" #'prot-abbrev-current-time
+ "medate" #'prot-abbrev-current-date
+ "mejitsi" #'prot-abbrev-jitsi-link)
+
;; message-mode derives from text-mode, so we don't need a separate
;; hook for it.
(dolist (hook '(text-mode-hook prog-mode-hook git-commit-mode-hook))
(add-hook hook #'abbrev-mode))
+ ;; Because the *scratch* buffer is produced before we load this, we
+ ;; have to explicitly activate the mode there.
+ (when-let ((scratch (get-buffer "*scratch*")))
+ (with-current-buffer scratch
+ (abbrev-mode 1)))
+
;; By default, abbrev asks for confirmation on whether to use
;; `abbrev-file-name' to save abbrevations. I do not need that, nor
;; do I want it.
diff --git a/emacs/.emacs.d/prot-emacs.org b/emacs/.emacs.d/prot-emacs.org
index 6d319ff1..40045fe0 100644
--- a/emacs/.emacs.d/prot-emacs.org
+++ b/emacs/.emacs.d/prot-emacs.org
@@ -1345,7 +1345,9 @@ abbreviations. Though it is good to practice some programming.
(defmacro prot-emacs-abbrev (table &rest definitions)
"Expand abbrev DEFINITIONS for the given TABLE.
DEFINITIONS is a sequence of string pairs mapping the
-abbreviation to its expansion."
+abbreviation to its expansion.
+
+Also see `prot-emacs-abbrev-function'."
(declare (indent 1))
(unless (zerop (% (length definitions) 2))
(error "Uneven number of key+command pairs"))
@@ -1357,6 +1359,24 @@ abbreviation to its expansion."
(expansion (cadr pair)))
`(define-abbrev table ,abbrev ,expansion)))
(seq-split definitions 2))))
+
+(defmacro prot-emacs-abbrev-function (table &rest definitions)
+ "Expand abbrev DEFINITIONS for the given TABLE.
+DEFINITIONS is a sequence of string and function symbol pairs
+mapping the abbreviation to its expansion.
+
+Also see `prot-emacs-abbrev'."
+ (declare (indent 1))
+ (unless (zerop (% (length definitions) 2))
+ (error "Uneven number of key+command pairs"))
+ `(when-let (((abbrev-table-p ,table))
+ (table ,table))
+ ,@(mapcar
+ (lambda (pair)
+ (when-let ((abbrev (car pair))
+ (expansion (cadr pair)))
+ `(define-abbrev table ,abbrev "" ,expansion)))
+ (seq-split definitions 2))))
#+end_src
** The =init.el= to find which packages have been loaded
@@ -1402,7 +1422,7 @@ specifies how they should be colourised.
(defconst prot-emacs-font-lock-keywords
'(("(\\(prot-emacs-package\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?"
(2 font-lock-constant-face nil t))
- ("(\\(prot-emacs-\\(keybind\\|abbrev\\)\\)\\_>[ \t']*\\(\\(\\sw\\|\\s_\\)+\\)?"
+ ("(\\(prot-emacs-\\(keybind\\|abbrev\\|abbrev-function\\)\\)\\_>[ \t']*\\(\\(\\sw\\|\\s_\\)+\\)?"
(3 font-lock-variable-name-face nil t))
("(\\(prot-emacs-comment\\)\\_>[ \t']*"
(1 font-lock-preprocessor-face nil t))))
@@ -4080,23 +4100,49 @@ templates to have a real need for it---but it works).
"texmacs" "TeXmacs"
"typescript" "TypeScript"
"visavis" "vis-à-vis"
- "youtube" "YouTube")
+ "youtube" "YouTube"
+ ":up" "🙃"
+ ":uni" "🦄"
+ ":laugh" "🤣"
+ ":smile" "😀"
+ ":sun" "☀️")
+
+ ;; Allow abbrevs with a prefix colon or underscore. I demonstrated
+ ;; this here: .
+ (abbrev-table-put text-mode-abbrev-table :regexp "\\(?:^\\|[\t\s]+\\)\\(?1:[:_].*\\|.*\\)")
(with-eval-after-load 'message
(prot-emacs-abbrev message-mode-abbrev-table
"bestregards" "Best regards,\nProtesilaos (or simply \"Prot\")"
"allthebest" "All the best,\nProtesilaos (or simply \"Prot\")"
+ "niceday" "Have a nice day,\nProtesilaos (or simply \"Prot\")"
"abest" "All the best,\nProt"
"bregards" "Best regards,\nProt"
+ "nday" "Have a nice day,\nProt"
"nosrht" "P.S. I am phasing out SourceHut:
.
Development continues on GitHub with GitLab as a mirror."))
+ ;; Unlike the above, the `prot-emacs-abbrev-function' macro does not
+ ;; expand a static text, but calls a function which dynamically
+ ;; expands into the requisite form.
+ (require 'prot-abbrev)
+ (prot-emacs-abbrev-function global-abbrev-table
+ "metime" #'prot-abbrev-current-time
+ "medate" #'prot-abbrev-current-date
+ "mejitsi" #'prot-abbrev-jitsi-link)
+
;; message-mode derives from text-mode, so we don't need a separate
;; hook for it.
(dolist (hook '(text-mode-hook prog-mode-hook git-commit-mode-hook))
(add-hook hook #'abbrev-mode))
+ ;; Because the *scratch* buffer is produced before we load this, we
+ ;; have to explicitly activate the mode there.
+ (when-let ((scratch (get-buffer "*scratch*")))
+ (with-current-buffer scratch
+ (abbrev-mode 1)))
+
;; By default, abbrev asks for confirmation on whether to use
;; `abbrev-file-name' to save abbrevations. I do not need that, nor
;; do I want it.
@@ -10063,6 +10109,77 @@ Please bear in mind that the code I write here is not necessarily as
high quality as what I put in my public packages, meaning that I do
not test it as much and do not try to make it perfect.
+** The =prot-abbrev.el= library
+:PROPERTIES:
+:CUSTOM_ID: h:ddb9c32c-2114-4347-9f76-5160e590b5dc
+:END:
+
+#+begin_src emacs-lisp :tangle "prot-lisp/prot-abbrev.el" :mkdirp yes
+;;; prot-abbrev.el --- Functions for use with abbrev-mode -*- lexical-binding: t -*-
+
+;; Copyright (C) 2024 Protesilaos Stavrou
+
+;; Author: Protesilaos Stavrou
+;; URL: https://protesilaos.com/emacs/dotemacs
+;; Version: 0.1.0
+;; Package-Requires: ((emacs "30.1"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program 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.
+;;
+;; This program 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 this program. If not, see .
+
+;;; Commentary:
+;;
+;; Functions for use with `abbrev-mode'.
+;;
+;; Remember that every piece of Elisp that I write is for my own
+;; educational and recreational purposes. I am not a programmer and I
+;; do not recommend that you copy any of this if you are not certain of
+;; what it does.
+
+;;; Code:
+
+(defgroup prot-abbrev ()
+ "Functions for use with `abbrev-mode'."
+ :group 'editing)
+
+(defcustom prot-abbrev-time-specifier "%R"
+ "Time specifier for `format-time-string'."
+ :type 'string
+ :group 'prot-abbrev)
+
+(defcustom prot-abbrev-date-specifier "%F"
+ "Date specifier for `format-time-string'."
+ :type 'string
+ :group 'prot-abbrev)
+
+(defun prot-abbrev-current-time ()
+ "Insert the current time per `prot-abbrev-time-specifier'."
+ (insert (format-time-string prot-abbrev-time-specifier)))
+
+(defun prot-abbrev-current-date ()
+ "Insert the current date per `prot-abbrev-date-specifier'."
+ (insert (format-time-string prot-abbrev-date-specifier)))
+
+(defun prot-abbrev-jitsi-link ()
+ "Insert a Jitsi link."
+ (insert (concat "https://meet.jit.si/" (format-time-string "%Y%M%dT%H%M%S"))))
+
+(provide 'prot-abbrev)
+;;; prot-abbrev.el ends here
+#+end_src
+
** The =prot-coach.el= library
:PROPERTIES:
:CUSTOM_ID: h:dbdfc774-c389-403f-95e7-17fa62c53d84
diff --git a/emacs/.emacs.d/prot-lisp/prot-abbrev.el b/emacs/.emacs.d/prot-lisp/prot-abbrev.el
new file mode 100644
index 00000000..af8e5102
--- /dev/null
+++ b/emacs/.emacs.d/prot-lisp/prot-abbrev.el
@@ -0,0 +1,63 @@
+;;; prot-abbrev.el --- Functions for use with abbrev-mode -*- lexical-binding: t -*-
+
+;; Copyright (C) 2024 Protesilaos Stavrou
+
+;; Author: Protesilaos Stavrou
+;; URL: https://protesilaos.com/emacs/dotemacs
+;; Version: 0.1.0
+;; Package-Requires: ((emacs "30.1"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program 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.
+;;
+;; This program 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 this program. If not, see .
+
+;;; Commentary:
+;;
+;; Functions for use with `abbrev-mode'.
+;;
+;; Remember that every piece of Elisp that I write is for my own
+;; educational and recreational purposes. I am not a programmer and I
+;; do not recommend that you copy any of this if you are not certain of
+;; what it does.
+
+;;; Code:
+
+(defgroup prot-abbrev ()
+ "Functions for use with `abbrev-mode'."
+ :group 'editing)
+
+(defcustom prot-abbrev-time-specifier "%R"
+ "Time specifier for `format-time-string'."
+ :type 'string
+ :group 'prot-abbrev)
+
+(defcustom prot-abbrev-date-specifier "%F"
+ "Date specifier for `format-time-string'."
+ :type 'string
+ :group 'prot-abbrev)
+
+(defun prot-abbrev-current-time ()
+ "Insert the current time per `prot-abbrev-time-specifier'."
+ (insert (format-time-string prot-abbrev-time-specifier)))
+
+(defun prot-abbrev-current-date ()
+ "Insert the current date per `prot-abbrev-date-specifier'."
+ (insert (format-time-string prot-abbrev-date-specifier)))
+
+(defun prot-abbrev-jitsi-link ()
+ "Insert a Jitsi link."
+ (insert (concat "https://meet.jit.si/" (format-time-string "%Y%M%dT%H%M%S"))))
+
+(provide 'prot-abbrev)
+;;; prot-abbrev.el ends here