Minor fixes to work better with demonstrating hamacs

This commit is contained in:
Howard Abrams 2024-10-25 22:05:22 -07:00
parent d816725afc
commit 23efcd2a26
9 changed files with 232 additions and 120 deletions

View file

@ -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 "<f6>") 'ha-simple-demo)
(global-set-key (kbd "<f5>") '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 @@ Lets 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? Lets 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? Lets 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 @@ Lets 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 Lisps =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:

View file

@ -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,9 +309,9 @@ 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 |
|------+---------------------------------------------|
@ -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 <maildir>/.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))
@ -540,9 +542,12 @@ NO-DISPLAY is sent forward to `notmuch-search'."
(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
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)))
@ -550,9 +555,9 @@ search."
;; 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.
;; 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
@ -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:

View file

@ -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."

View file

@ -91,31 +91,39 @@ Im 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 Im not sure why I cant 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
#+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))
;; Note that evil-backward-word-end is on the `g e':
(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 dont 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]]

View file

@ -59,12 +59,12 @@ The =org-indent-indentation-per-level=, which defaults to =2= doesnt really w
:custom-face (org-indent ((t (:inherit fixed-pitch)))))
#+end_src
Finally, lets 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

View file

@ -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. Lets 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
Lets 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
Lets 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. =<<something-something>>= could /jump/ to the =#name= definition.
Since [[https://github.com/BurntSushi/ripgrep][ripgrep]] is pretty fast, Ill 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 lets 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
Lets 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
@ -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
Im 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]]:

View file

@ -1,6 +1,6 @@
# -*- mode: snippet -*-
# name: python-src-block
# key: #sp
# key: <sp
# --
#+BEGIN_SRC python
$0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB