diff --git a/README.org b/README.org index 260b42d..face674 100644 --- a/README.org +++ b/README.org @@ -18,8 +18,11 @@ This creates [[file:~/.emacs.d/init.el][~/.emacs.d/init.el]] that starts the pro - [[file:ha-org.org][ha-org.org]] :: configures the basics for org-mode formatted files. Specific features, however, come from their own files, however. - [[file:ha-org-word-processor.org][ha-org-word-processor.org]] :: attempts to make Org files /visually/ look like what one might see in a word processor, including turning off the colors for headers, and instead increasing their size. - [[file:ha-org-clipboard.org][ha-org-clipboard.org]] :: automatically converting HTML from a clipboard into Org-formatted content. + - [[file:ha-org-journaling.org][ha-org-journaling.org]] :: for writing journal entries and tasks. - [[file:ha-org-sprint.org][ha-org-sprint.org]] :: functions for working with the my Org-focused sprint files. - - [[file:ha-programming.org][ha-programming.org]] :: configuration for /all/ programming languages, or at least, the simple ones. + - [[file:ha-remoting.org][ha-remoting.org]] :: my interface to systems using SSH and Vterm. + - [[file:ha-feed-reader.org][ha-feed-reader.org]] :: configuration of elfeed as well as my RSS feeds. - [[file:ha-capturing-notes.org][ha-capturing-notes.org]] :: my engineering notebook. + - [[file:ha-programming.org][ha-programming.org]] :: configuration for /all/ programming languages, or at least, the simple ones. *Note:* Other functions and files come from essays written on [[http://www.howardism.org][my blog]]. To help with this, see [[file:support/final-initialize.el][support/final-initialize.el]] file. diff --git a/bootstrap.org b/bootstrap.org index 43f1957..8f9caae 100644 --- a/bootstrap.org +++ b/bootstrap.org @@ -112,7 +112,7 @@ The following loads the rest of my org-mode literate files. I add them as they a "ha-org.org" "ha-org-word-processor.org" "ha-org-clipboard.org" - ;; "org-journaling.org" + "ha-org-journaling.org" ;; "org-publishing.org" "ha-org-sprint.org" "ha-capturing-notes.org" diff --git a/ha-capturing-notes.org b/ha-capturing-notes.org index d1ffb00..531e9bf 100644 --- a/ha-capturing-notes.org +++ b/ha-capturing-notes.org @@ -18,7 +18,7 @@ A literate programming file for configuring org for capturing notes. ;; This file is not part of GNU Emacs. ;; ;; *NB:* Do not edit this file. Instead, edit the original literate file at: -;; /home/howard/other/hamacs/ha-capturing-notes.org +;; ~/other/hamacs/ha-capturing-notes.org ;; And tangle the file to recreate this one. ;; ;;; Code: diff --git a/ha-config.org b/ha-config.org index 9031e04..3e994ed 100644 --- a/ha-config.org +++ b/ha-config.org @@ -80,9 +80,44 @@ Using [[https://github.com/joaotavora/yasnippet][yasnippet]] to convert template #+BEGIN_SRC emacs-lisp (use-package yasnippet :config - (add-to-list 'yas-snippet-dirs "~/.emacs.d/snippets") + (add-to-list 'yas-snippet-dirs (expand-file-name "snippets" user-emacs-directory)) (yas-global-mode +1)) #+END_SRC +** Auto Insert Templates +The [[https://www.emacswiki.org/emacs/AutoInsertMode][auto-insert]] feature is a wee bit complicated. All I want is to associate a filename regular expression with a YASnippet template. I'm stealing some ideas from Henrik Lissner's [[https://github.com/hlissner/doom-emacs/blob/develop/modules/editor/file-templates/autoload.el][set-file-template!]] macro, but maybe simpler? +#+BEGIN_SRC emacs-lisp +(use-package autoinsert + :init + (setq auto-insert-directory (expand-file-name "templates" user-emacs-directory)) + ;; Don't want to be prompted before insertion: + (setq auto-insert-query nil) + + (add-hook 'find-file-hook 'auto-insert) + (auto-insert-mode t)) +#+END_SRC +However, auto insertion requires entering data for particular fields, and for that Yasnippet is better, so in this case, we combine them: +#+BEGIN_SRC emacs-lisp +(defun ha-autoinsert-yas-expand() + "Replace text in yasnippet template." + (yas-expand-snippet (buffer-string) (point-min) (point-max))) +#+END_SRC + +And since I'll be associating snippets with new files all over my configuration, let's make a helper function: +#+BEGIN_SRC emacs-lisp + (defun ha-auto-insert-file (filename-re snippet-name) + "Autofill file buffer matching FILENAME-RE regular expression. + The contents inserted from the YAS SNIPPET-NAME." + ;; The define-auto-insert takes a regular expression and an ACTION: + ;; ACTION may also be a vector containing several successive single + ;; actions as described above, e.g. ["header.insert" author-update]. + (define-auto-insert filename-re + (vector snippet-name 'ha-autoinsert-yas-expand))) +#+END_SRC + +As an example of its use, any Org files loaded in /this project/ should insert my config file: +#+BEGIN_SRC emacs-lisp + (ha-auto-insert-file (rx "hamacs/" (one-or-more any) ".org" eol) "hamacs-config") +#+END_SRC ** Request System The above code (and other stuff) needs the [[https://github.com/tkf/emacs-request][request]] package: #+BEGIN_SRC emacs-lisp diff --git a/ha-org-clipboard.org b/ha-org-clipboard.org index 9c89709..022aa3e 100644 --- a/ha-org-clipboard.org +++ b/ha-org-clipboard.org @@ -19,7 +19,7 @@ A literate programming file of functions for formatting the clipboard. ;; This file is not part of GNU Emacs. ;; ;; *NB:* Do not edit this file. Instead, edit the original literate file at: -;; /home/howard/other/hamacs/org-clipboard.org +;; ~/other/hamacs/org-clipboard.org ;; And tangle the file to recreate this one. ;; ;;; Code: diff --git a/ha-org-journaling.org b/ha-org-journaling.org new file mode 100644 index 0000000..2ba878a --- /dev/null +++ b/ha-org-journaling.org @@ -0,0 +1,201 @@ +#+TITLE: Org Journaling +#+AUTHOR: Howard X. Abrams +#+EMAIL: howard.abrams@gmail.com +#+DATE: 2020-09-24 +#+FILETAGS: :emacs: + +A literate programming configuration file for extending the Journaling capabilities. + +#+BEGIN_SRC emacs-lisp :exports none +;;; org-journaling.el --- A literate programming configuration file for extending the Journaling capabilities. -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2020 Howard X. Abrams +;; +;; Author: Howard X. Abrams +;; Maintainer: Howard X. Abrams +;; Created: September 24, 2020 +;; +;; This file is not part of GNU Emacs. +;; +;; *NB:* Do not edit this file. Instead, edit the original literate file at: +;; ~/other/hamacs/org-journaling.org +;; And tangle the file to recreate this one. +;; +;;; Code: +#+END_SRC +* Introduction +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 "TODO " + 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! + +And let's put a /leader key/ sequence for it (Doom-specific): + +#+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 + (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") +#+END_SRC + +This depends on the following [[file:~/.doom.d/snippets/org-journal-mode/__journal][snippet/template file]]: + +#+BEGIN_SRC snippet :tangle ~/other/hamacs/templates/journal +#+TITLE: Journal Entry- `(ha-journal-file-datestamp)` + +$0 + +#+END_SRC + +Note that when I create a new journal entry, I want a title that should insert a date to match the file's name, not necessarily the current date (see below). +* Journal Filename to Date +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))) + + (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))) +#+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))) + +(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) ""))))) +#+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")))) +#+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)))) +#+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+))) +#+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-))) +#+END_SRC +* Technical Artifacts :noexport: +Let's =provide= a name so we can =require= this file. + +#+BEGIN_SRC emacs-lisp :exports none +(provide 'ha-org-journaling) +;;; ha-org-journaling.el ends here +#+END_SRC + +Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~ + +#+DESCRIPTION: A literate programming configuration file for extending the Journaling capabilities. + +#+PROPERTY: header-args:sh :tangle no +#+PROPERTY: header-args:emacs-lisp :tangle yes +#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes + +#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil +#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil +#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js diff --git a/ha-org.org b/ha-org.org index 22a213d..6547baf 100644 --- a/ha-org.org +++ b/ha-org.org @@ -18,7 +18,7 @@ A literate programming file for configuring org-mode and those files. ;; This file is not part of GNU Emacs. ;; ;; *NB:* Do not edit this file. Instead, edit the original literate file at: -;; /home/howard/other/hamacs/ha-org.org +;; ~/other/hamacs/ha-org.org ;; And tangle the file to recreate this one. ;; ;;; Code: diff --git a/initialize b/initialize index e66ff27..f4b7ded 100755 --- a/initialize +++ b/initialize @@ -1,10 +1,18 @@ #!/usr/bin/env bash +# ---------------------------------------------------------------------- +# INITIALIZE the HAMACS SYSTEM +# ---------------------------------------------------------------------- HAMACS_DIR=$(cd "$(dirname "$0")"; pwd) HAMACS_DEST=$HOME/.emacs.hamacs # A symlink to ~/.emacs.d mkdir -p $HAMACS_DEST -mkdir -p $HAMACS_DEST/elisp + +for LINK in snippets templates elisp +do + rm -rf $HAMACS_DEST/$LINK + ln -s --force $HAMACS_DIR/$LINK $HAMACS_DEST +done cat > $HAMACS_DEST/init.el <> (buffer-file-name) + (file-name-base) + (s-split-words) + (--map (s-capitalize it)) + (s-join " "))`} +#+AUTHOR: `user-full-name` +#+EMAIL: `user-mail-address` +#+DATE: `(format-time-string "%Y-%m-%d")` +#+FILETAGS: :emacs: + +${2:A literate programming file configuring Emacs.} + +#+BEGIN_SRC emacs-lisp :exports none +;;; `(file-name-base (buffer-file-name)))`.el --- $2 -*- lexical-binding: t; -*- +;; +;; Copyright (C) `(format-time-string "%Y")` `user-full-name` +;; +;; Author: `user-full-name` +;; Maintainer: `user-full-name` <`user-mail-address`> +;; Created: `(format-time-string "%B %e, %Y")` +;; +;; This file is not part of GNU Emacs. +;; +;; *NB:* Do not edit this file. Instead, edit the original literate file at: +;; `(buffer-file-name)` +;; And tangle the file to recreate this one. +;; +;;; Code: +#+END_SRC + +* Introduction + +$0 + +* Technical Artifacts :noexport: + +Let's =provide= a name so we can =require= this file: + +#+BEGIN_SRC emacs-lisp :exports none +(provide '`(file-name-base (buffer-file-name)))`) +;;; `(file-name-base (buffer-file-name)))`.el ends here +#+END_SRC + +#+DESCRIPTION: $2 + +#+PROPERTY: header-args:sh :tangle no +#+PROPERTY: header-args:emacs-lisp :tangle yes +#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes + +#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil +#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil +#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js \ No newline at end of file diff --git a/templates/journal b/templates/journal new file mode 100644 index 0000000..a9c5379 --- /dev/null +++ b/templates/journal @@ -0,0 +1,7 @@ +# -*- mode: snippet -*- +# name: journal +# key: journal +# -- +#+TITLE: Journal Entry- `(ha-journal-file-datestamp)` + +$0