Compare commits

...

3 commits

Author SHA1 Message Date
Howard Abrams
4267673853 Publishing my literate initialization with one function 2024-08-10 21:59:26 -07:00
Howard Abrams
4e11a22457 Journaling cleanup 2024-08-10 21:59:03 -07:00
Howard Abrams
a9ce3c1d27 Fixed a "race condition" startup bug
I wanted to have an icon associated with the major mode hydra, but the
display system wasn't available at this time. So, now we can override it.
2024-08-10 21:58:05 -07:00
7 changed files with 149 additions and 119 deletions

View file

@ -116,8 +116,8 @@ The [[help:shell-command][shell-command]] function is useful, but having it spli
(thread-last command
shell-command-to-string
s-lines
(-map 's-trim)
(-remove 's-blank-str?)))
(seq-map 's-trim)
(seq-remove 's-blank-str?)))
#+end_src
And lets see the results:
@ -156,15 +156,19 @@ I actually run two instances of Emacs on some systems, where one instance has al
#+end_src
And now start the server with an appropriate tag name:
#+begin_src emacs-lisp
(if (not (ha-emacs-for-work?))
(setq server-name "personal")
(setq server-name "work")
(when (ha-running-on-macos?)
(set-exec-path-from-shell)))
(server-start)
#+begin_src emacs-lisp
(when (display-graphic-p)
(if (not (ha-emacs-for-work?))
(setq server-name "personal")
(setq server-name "work")
(when (ha-running-on-macos?)
(set-exec-path-from-shell)))
(server-start))
#+end_src
*Note:* When starting Emacs as a terminal program (only happens when I am attempting to evaluate code), we dont start the server.
* Load the Rest
The following /defines/ the rest of my org-mode literate files, that I load later with the =ha-hamacs-load= function:
#+begin_src emacs-lisp
@ -227,14 +231,17 @@ With this function, we can test/debug/reload any individual file, via:
"Load or reload an org-mode FILE containing literate
Emacs configuration code."
(interactive (list (completing-read "Org file: "
(ha-hamacs-files :all))))
;; TODO: Replace concat here:
(let ((full-file (file-name-concat hamacs-source-dir file)))
(ha-hamacs-files :all))))
(let ((full-file (expand-file-name file hamacs-source-dir)))
(when (file-exists-p full-file)
(ignore-errors
(org-babel-load-file full-file)))))
(message ">>> %s" full-file)
(if (called-interactively-p)
(org-babel-load-file full-file)
(ignore-errors (org-babel-load-file full-file))))))
#+end_src
Notice that when we call this function /non-interactively/ (e.g. from the Lisp function, =ha-hamacs-reload-all=), we suppress any errors. Obviously, I want to see the errors when calling interactively.
** Tangling the Hamacs
And this similar function, will /tangle/ one of my files. Notice that in order to increase the speed of the tangling process (and not wanting to pollute a project perspective), I use a /temporary buffer/ instead of =find-file=.
@ -272,8 +279,7 @@ And we can tangle /all/ the files:
"Tangle all my Org initialization/configuration files."
(interactive)
(dolist (file (ha-hamacs-files))
(unless (equal file "bootstrap.org")
(ha-hamacs-tangle file))))
(ha-hamacs-tangle file)))
#+end_src
** Edit my Files
Changing my Emacs configuration is as simple as editing an Org file containing the code, and evaluating that block or expression. Or even /re-loading/ the entire file as described above. Calling =find-file= (or more often [[file:ha-config.org::*Projects][project-find-file]]) is sufficient but quicker if I supply a /focused list/ of just the files in my project:

View file

@ -373,9 +373,7 @@ Since I seldom remember keybindings, or even function names, for major-modes, I
(string-replace "-" " ")
(string-replace " mode" "")
(s-titleize))))
(s-concat ; (s-repeat 5 " ")
(all-the-icons-icon-for-mode mode :v-adjust 0.05)
" " title " Commands")))))
(concat "ϻ " title " Commands")))))
#+end_src
For this feature, I may want to pull it out into its own file, so as to keep all of its features together... however, those feature often /depend/ of the functions they are calling. If so, we would have a series like this:

View file

@ -37,10 +37,24 @@ Let's turn off the menu and other settings:
#+end_src
And lets make this Emacs look more like a fancy IDE with [[https://github.com/domtronn/all-the-icons.el][all-the-icons]]:
#+begin_src emacs-lisp
(use-package all-the-icons
:if (display-graphic-p))
:if (display-graphic-p)
:config
(setq major-mode-hydra-title-generator
'(lambda (mode)
(let ((title (thread-last mode
(symbol-name)
(string-replace "-" " ")
(string-replace " mode" "")
(s-titleize))))
(s-concat ; (s-repeat 5 " ")
(all-the-icons-icon-for-mode mode :v-adjust 0.05)
" " title " Commands")))))
#+end_src
This also expands the [[file:ha-config.org::*Leader Sequences][Major Mode Hydra]] title sequence with a pretty icon.
* Mode Line
Let's install and load some of packages from the [[https://github.com/hlissner/doom-emacs][Doom Emacs]] project, like [[https://github.com/seagle0128/doom-modeline][doom-modeline]] and maybe the themes:
#+begin_src emacs-lisp

View file

@ -28,37 +28,29 @@ A literate programming configuration file for extending the Journaling capabilit
Using the [[https://github.com/bastibe/org-journal][org-journal]] project to easily create /daily/ journal entries:
#+begin_src emacs-lisp
(use-package org-journal
:init
(setq org-journal-dir "~/journal"
org-journal-date-format " "
org-journal-time-format ""
org-journal-file-type 'daily
org-journal-file-format "%Y%m%d")
:config
#+end_src
Notice that the rest of this file's contents is /contained/ in this =config= section!
(use-package org-journal
:after org
:config
(setq org-journal-dir "~/journal"
org-journal-date-format " "
org-journal-time-format ""
org-journal-file-type 'daily
org-journal-file-format "%Y%m%d")
And let's put a /leader key/ sequence for it (Doom-specific):
(ha-leader "f j" '("journal" . org-journal-new-entry))
#+begin_src emacs-lisp
(ha-leader "f j" '("journal" . org-journal-new-entry))
#+end_src
In normal Org file, I like large headers, but in my Journal, where each task is a header, I want them smaller:
#+begin_src emacs-lisp
(add-hook 'org-journal-mode-hook
;; In normal Org file, I like large headers, but in my Journal,
;; where each task is a header, I want them smaller:
(add-hook 'org-journal-mode-hook
(lambda ()
(set-face-attribute 'org-level-1 nil :height 1.2)
(set-face-attribute 'org-level-2 nil :height 1.1)
(set-face-attribute 'org-level-3 nil :height 1.0)))
#+end_src
But new files could use /my formatting/ (which is different than the options available in the project):
#+begin_src emacs-lisp
(ha-auto-insert-file (rx "journal/" (zero-or-more any) (= 8 digit)) "journal")
;; But new files could use /my formatting/ (which is different
;; than the options available in the project):
(ha-auto-insert-file (rx "journal/" (zero-or-more any) (= 8 digit)) "journal"))
#+end_src
This depends on the following [[file:~/.doom.d/snippets/org-journal-mode/__journal][snippet/template file]]:
@ -75,114 +67,110 @@ Note that when I create a new journal entry, I want a title that should insert a
Since the Journal's filename represents a date, I should be able to get the "date" associated with a file.
#+begin_src emacs-lisp
(defun ha-journal-file-date (&optional datename)
"Returns a Lisp date-timestamp based on the format of the current filename,
or DATENAME if given."
(unless datename
(setq datename (buffer-file-name)))
(defun ha-journal-file-date (&optional datename)
"Returns a Lisp date-timestamp based on the format of the current filename,
or DATENAME if given."
(unless datename
(setq datename (buffer-file-name)))
(let* ((datename-parser (rx (group (= 4 digit))
(group (= 2 digit))
(group (= 2 digit))))
(parsed-datename (string-match datename-parser datename))
(day (string-to-number (match-string 3 datename)))
(month (string-to-number (match-string 2 datename)))
(year(string-to-number (match-string 1 datename))))
(encode-time 0 0 0 day month year)))
(let* ((datename-parser (rx (group (= 4 digit))
(group (= 2 digit))
(group (= 2 digit))))
(parsed-datename (string-match datename-parser datename))
(day (string-to-number (match-string 3 datename)))
(month (string-to-number (match-string 2 datename)))
(year(string-to-number (match-string 1 datename))))
(encode-time 0 0 0 day month year)))
#+end_src
Using the "date" associated with a file, we can create our standard timestamp:
#+begin_src emacs-lisp
(defun ha-journal-file-datestamp (&optional datename)
"Return a string of the buffer's date (based on the file's name)."
(format-time-string "%e %b %Y (%A)" (ha-journal-file-date datename)))
(defun ha-journal-file-datestamp (&optional datename)
"Return a string of the buffer's date (based on the file's name)."
(format-time-string "%e %b %Y (%A)" (ha-journal-file-date datename)))
#+end_src
Close the =use-package= call:
#+begin_src emacs-lisp
)
#+end_src
* Journal Capture
Capturing a task (that when uncompleted, would then spillover to following days) could go to the daily journal entry. This requires a special function that opens today's journal, but specifies a non-nil prefix argument in order to inhibit inserting the heading, as =org-capture= will insert the heading.
#+begin_src emacs-lisp
(defun org-journal-find-location ()
(org-journal-new-entry t)
(org-narrow-to-subtree)
(goto-char (point-max)))
(defun org-journal-find-location ()
(org-journal-new-entry t)
(org-narrow-to-subtree)
(goto-char (point-max)))
(defvar org-capture-templates (list))
(add-to-list 'org-capture-templates
'("j" "Journal Task/Entry" plain
(function org-journal-find-location)
"* %?\n\n %i\n\n From: %a"
:empty-lines 1 :jump-to-captured t :immediate-finish t))
(defvar org-capture-templates (list))
(add-to-list 'org-capture-templates
'("j" "Journal Task/Entry" plain
(function org-journal-find-location)
"* %?\n\n %i\n\n From: %a"
:empty-lines 1 :jump-to-captured t :immediate-finish t))
#+end_src
* Next and Previous File
Sometimes it is obvious what is the /next file/ based on the one I'm currently reading. For instance, in my journal entries, the filename is a number that can be incremented. Same with presentation files...
#+begin_src emacs-lisp
(defun split-string-with-number (string)
"Returns a list of three components of the string, the first is
the text prior to any numbers, the second is the embedded number,
and the third is the rest of the text in the string."
(let* ((start (string-match "[0-9]+" string))
(end (string-match "[^0-9]+" string start)))
(if start
(list (substring string 0 start)
(substring string start end)
(if end (substring string end) "")))))
(defun split-string-with-number (string)
"Returns a list of three components of the string, the first is
the text prior to any numbers, the second is the embedded number,
and the third is the rest of the text in the string."
(let* ((start (string-match "[0-9]+" string))
(end (string-match "[^0-9]+" string start)))
(if start
(list (substring string 0 start)
(substring string start end)
(if end (substring string end) "")))))
#+end_src
Which means that the following defines this function:
#+begin_src emacs-lisp :tangle no
(ert-deftest split-string-with-number-test ()
(should (equal (split-string-with-number "abc42xyz") '("abc" "42" "xyz")))
(should (equal (split-string-with-number "42xyz") '("" "42" "xyz")))
(should (equal (split-string-with-number "abc42") '("abc" "42" "")))
(should (equal (split-string-with-number "20140424") '("" "20140424" "")))
(should (null (split-string-with-number "abcxyz"))))
(ert-deftest split-string-default-separatorsg-with-number-test ()
(should (equal (split-string-with-number "abc42xyz") '("abc" "42" "xyz")))
(should (equal (split-string-with-number "42xyz") '("" "42" "xyz")))
(should (equal (split-string-with-number "abc42") '("abc" "42" "")))
(should (equal (split-string-with-number "20140424") '("" "20140424" "")))
(should (null (split-string-with-number "abcxyz"))))
#+end_src
Given this splitter function, we create a function that takes some sort of operator and return a new filename based on the conversion that happens:
#+begin_src emacs-lisp
(defun find-file-number-change (f)
(let* ((filename (buffer-file-name))
(parts (split-string-with-number
(file-name-base filename)))
(new-name (number-to-string
(funcall f (string-to-number (nth 1 parts))))))
(concat (file-name-directory filename)
(nth 0 parts)
new-name
(nth 2 parts))))
(defun find-file-number-change (f)
(let* ((filename (buffer-file-name))
(parts (split-string-with-number
(file-name-base filename)))
(new-name (number-to-string
(funcall f (string-to-number (nth 1 parts))))))
(concat (file-name-directory filename)
(nth 0 parts)
new-name
(nth 2 parts))))
#+end_src
And this allows us to create two simple functions that can load the "next" and "previous" files:
#+begin_src emacs-lisp
(defun find-file-increment ()
"Takes the current buffer, and loads the file that is 'one
more' than the file contained in the current buffer. This
requires that the current file contain a number that can be
incremented."
(interactive)
(find-file (find-file-number-change '1+)))
(defun find-file-increment ()
"Takes the current buffer, and loads the file that is 'one
more' than the file contained in the current buffer. This
requires that the current file contain a number that can be
incremented."
(interactive)
(find-file (find-file-number-change '1+)))
#+end_src
#+begin_src emacs-lisp
(defun find-file-decrement ()
"Takes the current buffer, and loads the file that is 'one
less' than the file contained in the current buffer. This
requires that the current file contain a number that can be
decremented."
(interactive)
(find-file (find-file-number-change '1-)))
(defun find-file-decrement ()
"Takes the current buffer, and loads the file that is 'one
less' than the file contained in the current buffer. This
requires that the current file contain a number that can be
decremented."
(interactive)
(find-file (find-file-number-change '1-)))
#+end_src
* Technical Artifacts :noexport:
* Technical Artifacts :noexport:
Let's =provide= a name so we can =require= this file.
#+begin_src emacs-lisp :exports none

View file

@ -30,9 +30,11 @@ While the Emacs community have a plethora of options for generating a static web
While the following packages come with Emacs, they aren't necessarily loaded:
#+begin_src emacs-lisp :results silent
(require 'ox-html)
(require 'ox-rss)
(require 'ox-publish)
(use-package org
:config
(require 'ox-html)
(require 'ox-rss)
(require 'ox-publish))
#+end_src
Render my code with my font colors:
@ -41,6 +43,13 @@ Render my code with my font colors:
(use-package htmlize)
#+end_src
Also, we need Jack, and his HTML prowess:
#+begin_src emacs-lisp
(use-package jack
:straight (:host github :repo "tonyaldon/jack")
:commands (jack-html))
#+end_src
Variable settings:
#+begin_src emacs-lisp
(setq org-publish-project-alist nil ; filled in below
@ -330,6 +339,20 @@ Using =rsync= to keep published files in sync with my website:
(message)
(async-shell-command))))
#+end_src
** Workflows for Hamacs
A single function to publish and sync my literate initialization of Emacs.
The idea is that pushing a Git commit to this project, triggers a Forgejo Workflow, that /exports/ the literate text as HTML to [[https://www.howardabrams.com/hamacs][my website]].
#+begin_src emacs-lisp
(defun hamacs-publishing-workflow ()
"Render and push a new web version of my Emacs initialization."
(interactive)
(org-publish-project "hamacs")
(org-publish-project "hamacs-static")
(ha-sync-site "hamacs"))
#+end_src
* Keybindings
Make it easy to publish all projects or single project:
#+begin_src emacs-lisp

View file

@ -1198,7 +1198,8 @@ Support for [[https://docutils.sourceforge.io/rst.html][reStructuredText]] is [[
#+begin_src emacs-lisp
(use-package rst
:config
(set-face-attribute 'rst-literal nil :font ha-fixed-font))
(when (and (display-graphic-p) (boundp 'ha-fixed-font))
(set-face-attribute 'rst-literal nil :font ha-fixed-font)))
#+end_src
** Docker
Edit =Dockerfiles= with the [[https://github.com/spotify/dockerfile-mode][dockerfile-mode]] project:

View file

@ -1,3 +1,3 @@
#+TITLE: Journal Entry- `(ha-journal-file-datestamp)`
#+title: Journal Entry- `(ha-journal-file-datestamp)`
$0