Compare commits
3 commits
b162327c7d
...
4267673853
Author | SHA1 | Date | |
---|---|---|---|
|
4267673853 | ||
|
4e11a22457 | ||
|
a9ce3c1d27 |
7 changed files with 149 additions and 119 deletions
|
@ -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 let’s 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 don’t 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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -37,10 +37,24 @@ Let's turn off the menu and other settings:
|
|||
#+end_src
|
||||
|
||||
And let’s 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#+TITLE: Journal Entry- `(ha-journal-file-datestamp)`
|
||||
#+title: Journal Entry- `(ha-journal-file-datestamp)`
|
||||
|
||||
$0
|
||||
|
|
Loading…
Reference in a new issue