diff --git a/ha-config.org b/ha-config.org index 7c6b306..cd76b4c 100644 --- a/ha-config.org +++ b/ha-config.org @@ -422,14 +422,14 @@ The following defines my use of the Emacs completion system. I’ve decided my / I don’t find the Emacs completion system obvious, with different interfaces, some distinct, some connected. As ~TAB~ is often overloaded. Emacs can have a cascade of functions. Here’s the summary as I understand (as well as the overriding keybindings I use): - #+BEGIN_EXAMPLE - ╭─▷ indent-for-tab-command ╭───────╮ - │ ╷ ╭──┤ M-TAB │ ╭─────╮ - │ ╰─▶ completion-at-point ◁──╯ ╰───────╯ │ M-/ │ - ╭──┴──╮ (completion-at-point-functions) ╰──┬──╯ - │ TAB │ ╷ │ - ╰─────╯ ╰─▶ hippie and dabbrev ◁──────────────╯ - #+END_EXAMPLE +#+BEGIN_EXAMPLE + ╭─▷ indent-for-tab-command ╭───────╮ + │ ╷ ╭──┤ M-TAB │ ╭─────╮ + │ ╰─▶ completion-at-point ◁──╯ ╰───────╯ │ M-/ │ + ╭──┴──╮ (completion-at-point-functions) ╰──┬──╯ + │ TAB │ ╷ │ + ╰─────╯ ╰─▶ hippie and dabbrev ◁──────────────╯ +#+END_EXAMPLE In =org-mode=, ~TAB~ calls [[help:org-cycle][org-cycle]], which is even more overload and context-specific. In the context of typing text, calls the binding for ~TAB~, which is the [[help:indent-for-tab-command][indent-for-tab-command]]. If the line is /indented/, it then completes the word: diff --git a/ha-demos.org b/ha-demos.org index 0ac7dea..93cda64 100644 --- a/ha-demos.org +++ b/ha-demos.org @@ -2,7 +2,7 @@ #+author: Howard X. Abrams #+date: 2024-10-18 #+filetags: emacs hamacs -#+lastmod: [2024-10-19 Sat] +#+lastmod: [2024-10-24 Thu] A literate programming file for creating and running demonstrations @@ -114,8 +114,8 @@ Instead of executing a sequence of demonstration steps, demonstrations key on #+BEGIN_SRC emacs-lisp :tangle no (define-ha-demo ha-simple-demo - (:head "New Demonstration" :i 0) (message "Howdy") - (:head "New Demonstration" :i 1) (message "Hi there")) + (:heading "New Demonstration" :i 0) (message "Howdy") + (:heading "New Demonstration" :i 1) (message "Hi there")) (global-set-key (kbd "") 'ha-simple-demo) (global-set-key (kbd "") 'org-present-next) @@ -136,7 +136,7 @@ To make the contents of the expression easier to write, the =define-ha-demo= as (define-demo demo1 (:buffer \"demonstrations.py\") (message \"In a buffer\") (:mode 'dired-mode) (message \"In a dired\") - (:head \"Raven Civilizations\" (message \"In an org file\"))) + (:heading \"Raven Civilizations\" (message \"In an org file\"))) Calling `(demo1)' displays a message based on position of the point in a particular buffer or place in a heading in an Org file. @@ -151,7 +151,7 @@ To make the contents of the expression easier to write, the =define-ha-demo= as (interactive) (let ((state (list :buffer (buffer-name) :mode major-mode - :head (when (eq major-mode 'org-mode) + :heading (when (eq major-mode 'org-mode) (org-get-heading))))) (cond ,@(seq-map (lambda (tf-pair) @@ -214,7 +214,7 @@ Let’s test: '(:a 1 :i 5) '((:a 1) (:b 2) (:c 3)))))) #+END_SRC -But can I check if I have triggered a state once before? Let’s keep track of the /states/ that have returned true before, in a hash table where the key is the /state/ (a list of =:buffer=, =:mode=, =:head=, etc.) and the /value/ is the number of times triggered at that state: +But can I check if I have triggered a state once before? Let’s keep track of the /states/ that have returned true before, in a hash table where the key is the /state/ (a list of =:buffer=, =:mode=, =:heading=, etc.) and the /value/ is the number of times triggered at that state: #+BEGIN_SRC emacs-lisp (defvar ha-demo-prev-state (make-hash-table :test 'equal) @@ -239,6 +239,91 @@ Let’s create a function that could accept a list of /triggering keys/, and the (not (seq-difference triggers state))) #+END_SRC +* Demonstration Support +What sort of functions will I often be doing? + +** Display File +Displaying a File with: + - On the side or covering the entire frame + - Larger font size + - Modeline or no modeline + - Going to a particular text or line + - Moving the cursor to the top or middle of the buffer window + +All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters? + +#+BEGIN_SRC emacs-lisp + (cl-defun ha-demo-show-file (filename &key position size modeline + line heading shift commands) + "Show a file, FILENAME, in a buffer based on keyed parameters. + POSITION can be 'full 'right or 'below and positions the window. + SIZE is an integer for the font size based on the default size. + MODELINE is shown if non-line, default is to hide it. + LINE is either a line number or a regular expression to match. + SHIFT is the number of lines above the point to show, in case + the LINE shouldn't be at the top of the window. + + COMMANDS is a lambda expression that can contain any other + instructions to happen to the buffer display." + (unless position + (setq position :right)) + + ;; Step 1: Create a window + (pcase position + ('full ) + ('right (progn (split-window-horizontally) (other-window 1))) + ('below (progn (split-window-vertically) (other-window 1)))) + ;; We could do :left and :top by not doing the other window bit... + + ;; Step 2: Load the file + (find-file filename) + (goto-char (point-min)) + + ;; Step 3: Increase the font size + (when size + (text-scale-set size)) + + (when line + (if (integerp line) + (goto-line line) + (re-search-forward line nil t))) + + (when heading + (re-search-forward (rx bol (one-or-more "*") (one-or-more space) + (literal heading)) + nil t)) + + ;; If SHIFT is positive integer, left that many line above point, + ;; otherwise don't do anything to leave it in the middle. + ;; If SHIFT is null, move it to the top of the buffer window: + (if shift + (when (integerp shift) + (recenter-top-bottom shift)) + (recenter-top-bottom 0)) + + (unless modeline + (setq-local mode-line-format nil)) + + (when commands (funcall commands)) + ) + + (funcall (lambda () (message "Hello"))) +#+END_SRC + +Let try it all together: + +#+BEGIN_SRC emacs-lisp :tangle no + (ha-demo-show-file "ha-config.org" :position 'right :size 1 :modeline nil :line 418 :shift 4) +#+END_SRC + +Or: + +#+BEGIN_SRC emacs-lisp :tangle no + (ha-demo-show-file "ha-config.org" :modeline t + :heading "Text Expanders" + :commands (lambda () (jinx-mode -1))) +#+END_SRC + * Technical Artifacts :noexport: Let's =provide= a name so we can =require= this file: diff --git a/ha-email.org b/ha-email.org index 43f6a73..99d2ec3 100644 --- a/ha-email.org +++ b/ha-email.org @@ -64,6 +64,11 @@ To use these, we set the =:noweb yes= (to pull in the /name/ of the code block) smtpmail-smtp-server "smtp.gmail.com" smtpmail-smtp-service 587) #+end_src +* Sending Mail +#+BEGIN_SRC emacs-lisp +(require 'smtpmail) +#+END_SRC + * Installation and Basic Configuration To begin, we need the code. On Ubuntu, this is: #+begin_src shell :tangle no @@ -304,17 +309,17 @@ The following option is supported here: exclude_tags=deleted;spam; #+end_src *** Maildir compatibility configuration -The following option is supported here: +This section support the following option: - - =synchronize_flags= :: Valid values are true and false. If true, then the following maildir flags (in message filenames) will be synchronized with the corresponding notmuch tags: +- =synchronize_flags= :: Valid values are true and false. If true, then notmuch synchronizing the following maildir flags (in message filenames) with the corresponding notmuch tags: - | Flag | Tag | - |------+---------------------------------------------| - | D | draft | - | F | flagged | - | P | passed | - | R | replied | - | S | unread (added when 'S' flag is not present) | + | Flag | Tag | + |------+---------------------------------------------| + | D | draft | + | F | flagged | + | P | passed | + | R | replied | + | S | unread (added when 'S' flag is not present) | The =notmuch new= command will notice flag changes in filenames and update tags, while the =notmuch tag= and =notmuch restore= commands will notice tag changes and update flags in filenames. @@ -325,7 +330,7 @@ The =notmuch new= command will notice flag changes in filenames and update tags, That should complete the Notmuch configuration. ** =pre-new= -Then we need a shell script called when beginning a retrieval, =pre-new= that simply calls =mbsync= to download all the messages: +We call this shell script when beginning a retrieval, =pre-new= that calls =mbsync= to download all the messages: #+begin_src shell :tangle ~/.mail/.notmuch/hooks/pre-new :shebang "#!/bin/bash" # More info about hooks: https://notmuchmail.org/manpages/notmuch-hooks-5/ @@ -344,11 +349,9 @@ And a =post-new= hook based on a filtering scheme that mimics the Hey.com workfl # Based On: https://gist.githubusercontent.com/frozencemetery/5042526/raw/57195ba748e336de80c27519fe66e428e5003ab8/post-new # Note: We now tangle this file from ~/src/hamacs/ha-email.org # -# Install this by moving this file to /.notmuch/hooks/post-new -# NOTE: you need to define your maildir in the vardiable nm_maildir (just a few lines below in this script) -# Also create empty files for: -# 1. thefeed.db (things you want to read every once in a while) -# 2. spam.db (things you never want to see) +# Create empty files for: +# 1. thefeed.db (mail you want to read every once in a while) +# 2. spam.db (mail you never want to see) # 3. screened.db (your inbox) # 4. ledger.db (papertrail) # in the hooks folder. @@ -422,8 +425,6 @@ do done timer_end "Screened" -# Projects... - timer_start "Old-Projects" notmuch tag +old-project 'subject:/.*howardabrams\/node-mocks-http/' notmuch tag +old-project 'subject:/.*Pigmice2733/' @@ -434,12 +435,12 @@ notmuch tag +screened 'subject:[Web]' echo "Completing not-much 'post-new' script" #+end_src * Hey -I originally took the following configuration from [[https://youtu.be/wuSPssykPtE][Vedang Manerikar's video]], along with [[https://gist.github.com/vedang/26a94c459c46e45bc3a9ec935457c80f][the code]]. The ideas brought out were to mimic the hey.com email workflow, and while not bad, I thought that maybe I could improve upon it slowly over time. +I originally took the following configuration from [[https://youtu.be/wuSPssykPtE][Vedang Manerikar's video]], along with [[https://gist.github.com/vedang/26a94c459c46e45bc3a9ec935457c80f][the code]]. The ideas brought out were to mimic the hey.com email workflow, and while not bad, I thought I could improve it over time. -To allow me to keep Vedang's and my code side-by-side in the same Emacs variable state, I have renamed the prefix to =hey-=, however, if you are looking to steal my code, you may want to revisit the source. +To allow me to keep Vedang's and my code side-by-side in the same Emacs variable state, I have renamed the prefix to =hey-=, buf, if you are looking to steal my code, you may want to revisit the original source. ** Default Searches -A list of pre-defined searches act like "Folder buttons" at the top to quickly see files that match those /buckets/: +A list of pre-defined searches act like "Folder buttons" at the top to see files that match those /buckets/: #+begin_src emacs-lisp (use-package notmuch @@ -451,6 +452,7 @@ A list of pre-defined searches act like "Folder buttons" at the top to quickly s (:name "Previously Seen" :query "tag:screened AND NOT tag:unread" :key "I") + (:name "Sent" :query "tag:sent") (:name "Unscreened" :query "tag:inbox AND tag:unread AND NOT tag:screened AND NOT date:..14d AND NOT tag:thefeed AND NOT tag:/ledger/ AND NOT tag:old-project" :key "s") @@ -479,7 +481,7 @@ A list of pre-defined searches act like "Folder buttons" at the top to quickly s #+end_src ** Helper Functions -With good bucket definitions, we should be able to scan the mail quickly and deal with the entire lot of them: +With good bucket definitions, we should be able to scan the mail and deal with the entire lot: #+begin_src emacs-lisp (defun hey-notmuch-archive-all () @@ -495,7 +497,7 @@ With good bucket definitions, we should be able to scan the mail quickly and dea (hey-notmuch-archive-all)) (defun hey-notmuch-search-delete-and-archive-thread () - "Archive the currently selected thread. Add the deleted tag as well." + "Archive the selected thread. Add the deleted tag as well." (interactive) (notmuch-search-add-tag '("+deleted")) (notmuch-search-archive-thread)) @@ -526,38 +528,41 @@ A key point in organizing emails with the Hey model, is looking at the "from" ad And we can create a filter, /search/ and tagging based on this "from" function: #+begin_src emacs-lisp -(defun hey-notmuch-filter-by-from () - "Filter the current search view to show all emails sent from the sender of the current thread." - (interactive) - (notmuch-search-filter (concat "from:" (hey-notmuch-search-find-from)))) + (defun hey-notmuch-filter-by-from () + "Filter the current search view to show all emails sent from the sender of the current thread." + (interactive) + (notmuch-search-filter (concat "from:" (hey-notmuch-search-find-from)))) -(defun hey-notmuch-search-by-from (&optional no-display) - "Show all emails sent from the sender of the current thread. -NO-DISPLAY is sent forward to `notmuch-search'." - (interactive) - (notmuch-search (concat "from:" (hey-notmuch-search-find-from)) - notmuch-search-oldest-first nil nil no-display)) + (defun hey-notmuch-search-by-from (&optional no-display) + "Show all emails sent from the sender of the current thread. + NO-DISPLAY is sent forward to `notmuch-search'." + (interactive) + (notmuch-search (concat "from:" (hey-notmuch-search-find-from)) + notmuch-search-oldest-first nil nil no-display)) -(defun hey-notmuch-tag-by-from (tag-changes &optional beg end refresh) - "Apply TAG-CHANGES to all emails from the sender of the current thread. -BEG and END provide the region, but are ignored. They are defined -since `notmuch-search-interactive-tag-changes' returns them. If -REFRESH is true, refresh the buffer from which we started the -search." - (interactive (notmuch-search-interactive-tag-changes)) - (let ((this-buf (current-buffer))) - (hey-notmuch-search-by-from t) - ;; This is a dirty hack since I can't find a way to run a - ;; temporary hook on `notmuch-search' completion. So instead of - ;; waiting on the search to complete in the background and then - ;; making tag-changes on it, I will just sleep for a short amount - ;; of time. This is generally good enough and works, but is not - ;; guaranteed to work every time. I'm fine with this. - (sleep-for 0.5) - (notmuch-search-tag-all tag-changes) - (when refresh - (set-buffer this-buf) - (notmuch-refresh-this-buffer)))) + (defun hey-notmuch-tag-by-from (tag-changes &optional beg end refresh) + "Apply TAG-CHANGES to all emails from the sender of the current thread. + + While defined (since `notmuch-search-interactive-tag-changes' + returns them), this function ignores BEG and END (for the + region). + + If REFRESH is true, refresh the buffer from which we started the + search." + (interactive (notmuch-search-interactive-tag-changes)) + (let ((this-buf (current-buffer))) + (hey-notmuch-search-by-from t) + ;; This is a dirty hack since I can't find a way to run a + ;; temporary hook on `notmuch-search' completion. So instead of + ;; waiting on the search to complete in the background and then + ;; making tag-changes on it, I sleep for a short amount of time. + ;; This is generally good enough and works, but is not guaranteed + ;; to work every time. I'm fine with this. + (sleep-for 0.5) + (notmuch-search-tag-all tag-changes) + (when refresh + (set-buffer this-buf) + (notmuch-refresh-this-buffer)))) #+end_src ** Moving Mail to Buckets @@ -573,8 +578,8 @@ We based the Hey buckets on notmuch databases, we combine the =hey-notmuch-add-a "For the email at point, move the sender of that email to the feed. This means: 1. All new email should go to the feed and skip the inbox altogether. -2. All existing email should be updated with the tag =thefeed=. -3. All existing email should be removed from the inbox." +2. All existing email updated with the tag `thefeed'. +3. All existing email removed from the inbox." (interactive) (hey-notmuch-add-addr-to-db (hey-notmuch-search-find-from) (format "%s/thefeed.db" notmuch-hooks-dir)) @@ -584,8 +589,8 @@ This means: "For the email at point, move the sender of that email to the papertrail. This means: 1. All new email should go to the papertrail and skip the inbox altogether. -2. All existing email should be updated with the tag =ledger/TAG-NAME=. -3. All existing email should be removed from the inbox." +2. All existing email updated with the tag `ledger/TAG-NAME'. +3. All existing email removed from the inbox." (interactive "sTag Name: ") (hey-notmuch-add-addr-to-db (format "%s %s" tag-name @@ -597,8 +602,8 @@ This means: (defun hey-notmuch-move-sender-to-screened () "For the email at point, move the sender of that email to Screened Emails. This means: -1. All new email should be tagged =screened= and show up in the inbox. -2. All existing email should be updated to add the tag =screened=." +1. All new email tagged `screened' and show up in the inbox. +2. All existing email updated to add the tag `screened'." (interactive) (hey-notmuch-add-addr-to-db (hey-notmuch-search-find-from) (format "%s/screened.db" notmuch-hooks-dir)) @@ -759,3 +764,7 @@ Let's =provide= a name so we can =require= this file: #+options: num:nil toc:t todo:nil tasks:nil tags:nil date:nil #+options: skip:nil author:nil email:nil creator:nil timestamp:nil #+infojs_opt: view:nil toc:t ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js + +# Local Variables: +# jinx-local-words: "notmuch" +# End: diff --git a/ha-eshell.org b/ha-eshell.org index c21951a..efda46e 100644 --- a/ha-eshell.org +++ b/ha-eshell.org @@ -73,12 +73,14 @@ If any program wants to pause the output through the =$PAGER= variable, well, we #+end_src ** Argument Completion Shell completion uses the flexible =pcomplete= mechanism internally, which allows you to program the completions per shell command. To know more, check out this [[https://www.masteringemacs.org/article/pcomplete-context-sensitive-completion-emacs][blog post]], about how to configure =pcomplete= for git commands. The [[https://github.com/JonWaltman/pcmpl-args.el][pcmpl-args]] package extends =pcomplete= with completion support for more commands, like the Fish and other modern shells. I love how a package can gives benefits without requiring learning anything. + #+begin_src emacs-lisp (use-package pcmpl-args) #+end_src Note that this will work with =shell-command= as well. ** Better Command Line History On [[http://www.reddit.com/r/emacs/comments/1zkj2d/advanced_usage_of_eshell/][this discussion]] a little gem for using IDO to search back through the history, instead of =M-R= to prompt for the history. + #+begin_src emacs-lisp (defun eshell-insert-history () "Displays the eshell history to select and insert back into your eshell." diff --git a/ha-evil.org b/ha-evil.org index 49b0bc1..91108f4 100644 --- a/ha-evil.org +++ b/ha-evil.org @@ -91,31 +91,39 @@ I’m not a long term VI user, and I generally like /easy keys/, e.g. ~w~, have #+begin_src emacs-lisp (use-package evil - :config - (require 'evil-commands) - (evil-define-key '(normal visual motion operator) 'global + :config (require 'evil-commands) + (evil-define-key + '(normal visual motion operator) 'global "w" 'evil-forward-WORD-begin "W" 'evil-forward-word-begin "e" 'evil-forward-WORD-end - "E" 'evil-forward-word-end + "E" 'evil-forward-word-end) +#+END_SRC - ;; This may be an absolute heresy to most VI users, - ;; but I'm Evil and really, I use M-x and SPC instead. - ;; Besides, I don't know any : colon commands... - ":" 'evil-repeat-find-char-reverse) +The ~b~ key bindings seems to need their own call, and I’m not sure why I can’t include it in the ~w~ and ~e~ bindings. - ;; The `b' key seems to need its own configuration setting: - (evil-define-key '(normal visual motion operator) 'global - "b" 'evil-backward-WORD-begin) - (evil-define-key '(normal visual motion operator) 'global - "B" 'evil-backward-word-begin)) - ;; Note that evil-backward-word-end is on the `g e': +#+BEGIN_SRC emacs-lisp + (evil-define-key + '(normal visual motion operator) 'global + "b" 'evil-backward-WORD-begin) + (evil-define-key + '(normal visual motion operator) 'global + "B" 'evil-backward-word-begin) #+end_src In other words, with the above settings in place, ~w~ and ~e~ should jump from front to back of the entire line, but ~W~ and ~E~ should stop as /subword/: - =word-subword-subword= - =word_subword_subword= +Note I don’t bind =evil-backward-word-end= with a single key, but bind it to ~g e~ below. + +While an absolute heresy to most VI users, I'm Evil and use ~M-x~ and ~SPC~ instead of ~:~ for running commands. I bind the ~:~ as a reverse of the ~;~ which continues the search from ~f~ and ~t~: +#+BEGIN_SRC emacs-lisp + (evil-define-key + '(normal visual motion operator) 'global + ":" 'evil-repeat-find-char-reverse)) +#+END_SRC + This clever hack from [[https://manueluberti.eu//emacs/2022/10/16/back-last-edit/][Manuel Uberti]] got me finding these useful bindings: - ~g ;~ :: [[help:goto-last-change][goto-last-change]] - ~g ,~ :: [[help:goto-last-change-reverse][goto-last-change-reverse]] diff --git a/ha-org-word-processor.org b/ha-org-word-processor.org index f19772e..9604f34 100644 --- a/ha-org-word-processor.org +++ b/ha-org-word-processor.org @@ -59,12 +59,12 @@ The =org-indent-indentation-per-level=, which defaults to =2= doesn’t really w :custom-face (org-indent ((t (:inherit fixed-pitch))))) #+end_src -Finally, let’s add frame borders and window dividers: +The following adds frame borders and window dividers to give space between window buffers. Do I need this when my Org files indent the text? Dunno, but it makes the view more pleasant. #+begin_src emacs-lisp (modify-all-frames-parameters - '((right-divider-width . 20) - (internal-border-width . 20))) + '((right-divider-width . 2) + (internal-border-width . 10))) (dolist (face '(window-divider window-divider-first-pixel @@ -385,7 +385,7 @@ However, I'm just going to have to write a function to clean this. (replace-match (match-string 1) nil :no-error))) #+end_src Now that is some complicated regular expressions. -* Technical Artifacts :noexport: +* Technical Artifacts :noexport: Note, according to [[https://www.reddit.com/r/emacs/comments/vahsao/orgmode_use_capitalized_property_keywords_or/][this discussion]] (and especially [[https://scripter.co/org-keywords-lower-case/][this essay]]), I’m switching over to lower-case version of org properties. Using this helper function: Let's provide a name so we can =require= this file: diff --git a/ha-org.org b/ha-org.org index 29decd9..90db979 100644 --- a/ha-org.org +++ b/ha-org.org @@ -283,7 +283,15 @@ Came up with a great way to search a project for Org-specific files, and wrote [ (ha-leader "f o" '("load org" . org-find-file))) #+end_src -Now that my paragraphs in an org file are on a single line, I could use =rg= (or some other =grep= program), but being able to use an /indexed search system/, like [[https://ss64.com/osx/mdfind.html][mdfind]] on Macos, or [[https://www.lesbonscomptes.com/recoll/][recoll]] on Linux, gives better results than line-oriented search systems. Let’s create operating-system functions the command line for searching: +Now that my paragraphs in an org file are on a single line, I could use =rg= (or some other =grep= program), but being able to use an /indexed search system/, like [[https://ss64.com/osx/mdfind.html][mdfind]] on Macos, or [[https://www.lesbonscomptes.com/recoll/][recoll]] on Linux, gives better results than line-oriented search systems. + +While =mdfind= is builtin to MacOS, we need to install =recoll=: + +#+BEGIN_SRC sh + sudo apt install -y recoll +#+END_SRC + +Let’s create operating-system functions the command line for searching: #+begin_src emacs-lisp (defun ha-search-notes--macos (phrase path) @@ -322,9 +330,12 @@ This function calls the above-mentioned operating-system-specific functions, but #+end_src Let’s see it in action: #+begin_src emacs-lisp :tangle no :results replace - (ha-search-notes--files "openstack grafana" '("~/Notes")) + (ha-search-notes--files "bread" '("~/personal")) #+end_src +#+RESULTS: +: ':3:common/rclinit.cpp:391::Recoll 1.36.1 + Xapian 1.4.22 [/home/howard/.recoll]' + Returns this string: #+begin_example "'/Users/howard.abrams/Notes/Sprint-2022-25.org' '/Users/howard.abrams/Notes/Sprint-2022-03.org' '/Users/howard.abrams/Notes/Sprint-2020-45.org' '/Users/howard.abrams/Notes/Sprint-2022-09.org' '/Users/howard.abrams/Notes/Sprint-2022-05.org' '/Users/howard.abrams/Notes/Sprint-2022-01.org' '/Users/howard.abrams/Notes/Sprint-2022-19.org'" @@ -384,14 +395,6 @@ And turn on ALL the languages: (plantuml . t))) #+end_src -The [[https://github.com/isamert/corg.el][corg project]] does completing feature for all the block header values. To do this, type ~M-Tab~ (not just regular ~Tab~). - -#+begin_src emacs-lisp :results list :hlines yes - (use-package corg - :straight (:host github :repo "isamert/corg.el") - :hook (org-mode . 'corg-setup)) -#+end_src - *** Searching Literate Files A noweb definition, e.g. =<>= could /jump/ to the =#name= definition. Since [[https://github.com/BurntSushi/ripgrep][ripgrep]] is pretty fast, I’ll call it instead of attempting to build a [[https://stackoverflow.com/questions/41933837/understanding-the-ctags-file-format][CTAGS]] table. Oooh, the =rg= takes a =—json= option, which makes it easier to parse. @@ -470,7 +473,21 @@ And let’s try this: #+end_src *** Graphviz -The [[https://graphviz.org/][graphviz project]] can be written in org blocks, and then rendered as an image: +Using the [[https://graphviz.org/][graphviz project]], create charts with /textual instructions/ (code), and then rendered as an image. First setup Graphviz configuration using [[https://github.com/ppareit/graphviz-dot-mode][graphviz-dot-mode]]: + +#+begin_src emacs-lisp + (use-package graphviz-dot-mode + :mode "\\.dot\\'" + :init + (setq tab-width 4 + graphviz-dot-indent-width 2 + graphviz-dot-auto-indent-on-newline t + graphviz-dot-auto-indent-on-braces t + graphviz-dot-auto-indent-on-semi t)) +#+end_src + +Next, add it to org-babel: + #+name: ob-graphviz #+begin_src emacs-lisp :tangle no (add-to-list 'org-src-lang-modes '("dot" . "graphviz-dot")) @@ -547,7 +564,7 @@ Here is a sequence diagram example to show how is looks/works: #+attr_org: :width 800px [[file:ha-org-plantuml-example.png]] *** Pikchr -No, not Pikachu, but close. The [[https://pikchr.org/home/doc/trunk/homepage.md][Pikchr project]] is similar to Graphviz and Plantuml, but makes the boxes more positional and really allows one to place things more precisely. Yet another steep learning curve. +No, not Pikachu, but close. Unlike Graphviz and Plantuml, the [[https://pikchr.org/home/doc/trunk/homepage.md][Pikchr project]] makes boxes more positional and allows one to place the parts more precisely. Yet another steep learning curve. Not sure if anyone has made a /package/, so we need to download and build locally: #+begin_src sh :dir ~/bin @@ -556,17 +573,18 @@ Not sure if anyone has made a /package/, so we need to download and build locall gcc -DPIKCHR_SHELL -o ~/bin/pikchr ~/bin/pikchr.c -lm # to build the pikchr command-line tool #+end_src -Of course, since we are dealing with Emacs, any good idea will be assimilated. Johann Klähn created [[https://github.com/kljohann/pikchr-mode][pikchr-mode]]: +Of course, since we are dealing with Emacs, where we assimilate any good idea. Johann Klähn created [[https://github.com/kljohann/pikchr-mode][pikchr-mode]]: #+begin_src emacs-lisp (use-package pikchr-mode :straight (:local-repo "~/src/pikchr-mode") + ;; :straight (:host github :repo "kljohann/pikchr-mode") :custom (pikchr-executable "~/bin/pikchr")) #+end_src Let’s see this in action: -#+begin_src pikchr :file ha-org-pikchr-01.svg :results file :exports both +#+begin_src pikchr :file ha-org-pikchr-01.png :results file :exports both bgcolor = 0x1d2021 fgcolor = 0xeeeeee line; box "Hello," "World!"; arrow @@ -592,7 +610,7 @@ At work, I’ve been integrating [[https://mermaidjs.github.io/][Mermaid]] into Assuming we have installed the [[https://github.com/mermaid-js/mermaid-cli][Mermaid CLI]]: #+BEGIN_SRC sh -npm install -g @mermaid-js/mermaid-cli + npm install -g @mermaid-js/mermaid-cli #+END_SRC We edit the code with [[https://github.com/abrochard/mermaid-mode][mermaid-mode]]: @@ -600,7 +618,9 @@ We edit the code with [[https://github.com/abrochard/mermaid-mode][mermaid-mode] #+BEGIN_SRC emacs-lisp (use-package mermaid-mode :config - (setq mermaid-mmdc-location "/opt/homebrew/bin/mmdc")) + (setq mermaid-mmdc-location (if (file-exists-p "/opt/homebrew") + "/opt/homebrew/bin/mmdc" + "/usr/local/bin/mmdc"))) #+END_SRC We can make Mermaid diagrams in Emacs Org files using [[https://github.com/arnm/ob-mermaid][ob-mermaid]]: @@ -608,7 +628,7 @@ We can make Mermaid diagrams in Emacs Org files using [[https://github.com/arnm/ #+BEGIN_SRC emacs-lisp (use-package ob-mermaid :config - (setq ob-mermaid-cli-path "/opt/homebrew/bin/mmdc")) + (setq ob-mermaid-cli-path mermaid-mmdc-location)) #+END_SRC #+BEGIN_SRC mermaid :file ha-org-mermaid.png :theme dark :background-color transparent @@ -752,18 +772,6 @@ I have a special version of tweaked [[file:elisp/ox-confluence.el][Confluence ex "o E" '("to confluence" . ox-export-to-confluence))) #+end_src -And Graphviz configuration using [[https://github.com/ppareit/graphviz-dot-mode][graphviz-dot-mode]]: -#+begin_src emacs-lisp - (use-package graphviz-dot-mode - :mode "\\.dot\\'" - :init - (setq tab-width 4 - graphviz-dot-indent-width 2 - graphviz-dot-auto-indent-on-newline t - graphviz-dot-auto-indent-on-braces t - graphviz-dot-auto-indent-on-semi t)) -#+end_src - *** HTML Style I’m not afraid of HTML, but I like the idea of doing my HTML work in a Lisp-like way using the [[https://github.com/tonyaldon/jack][jack-html project]]: diff --git a/snippets/org-mode/python-src-block b/snippets/org-mode/python-src-block index 5c9ae24..2c94ac4 100644 --- a/snippets/org-mode/python-src-block +++ b/snippets/org-mode/python-src-block @@ -1,6 +1,6 @@ # -*- mode: snippet -*- # name: python-src-block -# key: #sp +# key: