🚀 shom.dev

Corne LP

I fell down the split ergo mechanical keyboard rabbit hole thanks to a dear friend who was kind enough to loan me his [Gergoplex] (despite my incessant teasing about his hipster keyboard). The Gergoplex is on the deeper end of the rabbit-hole with only 36 keys and 12g switches but it demonstrated the value to me. I ended up getting a pre-built [Corne] and added the lightest switches I could find at the time: [Gateron MX 35g switches]. I've been pretty happy with the Corne (and it's 3x6 +3 layout) but I very much enjoyed the lower profile and light action of the Gergoplex and wanted to chase it...

So, I got a [Corne LP] kit but went with an acrylic case (the aluminum case looks really nice but it's quite rich) and got the 25g [Purpz] Choc switches.

Kit

It was fun to assemble the kit and the board looks great:

Board with no keycaps

I didn't have any Choc keycaps so I had to wait a bit for the [MK Ultra MBK Choc] keycaps. I'm very impressed with the keycaps and the homing keys feel great. I'm a big fan of the look and feel and quite happy with the low profile and light touch which I was looking for.

Corne LP with MK Ultra Chocs

The keyboard worked "out of the box" but I was able to flash my custom [QMK firmware] and was able to get up and going with my keymap. Now, maybe I'll look into making the kit [wireless]? It never ends.

Gergoplex

Corne

Gateron MX 35g switches

Corne LP

Purpz

MK Ultra MBK Choc

QMK firmware

wireless

OBS, virtual camera, guix

I've used OBS as a virtual camera input for various reasons (to compose scenes, to control field of view, etc.). I was setting it up on my desktop (Pop_Os! 20.04 with Guix as the package manager) today because Microsoft Teams recognizes my El Gato CamLink 4K but won't show any video. Since I had successfully used virtual camera before I tried setting it up, but ran into some issues.

OBS needs the `v4l2loopback' driver in order to enable the virtual camera functionality.

guix install obs-studio v4l2loopback-linux-module

Installing OBS and the loopback driver worked but even after a restart OBS would not show the virtual camera option. I decided to see if it was a package/path issue and tried using `apt' but even after restart that didn't work, turns out apt's version of OBS is too old.

apt install -y obs v4l2loopback-dkms

`NOTE' package names are different

Ultimately, I had to get OBS from guix and the loopback from apt. This mismatch makes me uneasy since it goes directly against a declarative config, so I'm documenting the discrepancy for when it bites me in the future.

Found Nemo!

First painting with the new paint set. Good paper (140 lbs) and paint make a big difference.

Nemo

Water color paint key/legend

I got a new water color paint set. Turns out I like painting enough and I was encouraged by a friend with a generous gift of brushes and a marine life water color book. The same friend also clued me in to making a paint key/legend. Well, first I made a poor design decision on how to structure the key and then failed to follow the design (further indicating poor design). I also had to reconcile my desire for perfection with lack of a ruler, lack of patience, and lack of necessity for the outcome to be perfect. So what I intended to be a relaxing afternoon activity turned out to be a bit frustrating. BUT, I'm glad I persevered and now I have this legend to guide me on what colors to pick when I paint. Now that it's done, it looks pretty to me, not surprising that I also love opera warming up cacophonous sound.

Paint key

Setting up Protonmail in Emacs

I've used [Protonmail] for several years and use the web interface for the most part and used Thunderbird on the desktop to keep offline copies of email. Since Protnmail takes care of the encryption it requires a [local bridge] to provide a standard interface like IMAP. Essentially, it is running an IMAP server on the local machine that any compatible client can connect to. Technically, the bridge can be made accessible on a local network so many clients from many machines can connect to it. I might eventually set this up when I have had a chance to get a better handle on vlans and access control.

Protonmail

local bridge

Installing packages

In order to use connect to the local IMAP bridge locally, I will be using `mbsync'. I'm using `guix' for package management, guix (and other package managers) refer to `mbsync' as `isync'. The `mu' package also includes `mu4e' (at least in version 1.6+ and it's not recommended to mix/match versions).

guix install isync mu

Configuring mbsync

`mbsync' expects a configuration in `~/.mbsyncrc' (does anyone know how to move this to `~/.config'? I'm disheartened by all the home directory clutter). Ideally one would GPG encrypt the password but since Proton Bridge generates it locally and it's is available as clear text to the local machine anyway, I didn't bother. Instead I just put the password from the ProtonBridge application into a text file (ensure no extra characters exist like space or return) and cat that into the `PassCmd `.

IMAPAccount proton
Host 127.0.0.1
User user@protonmail.com
PassCmd "cat ~/.protonBridgePass"
SSLType NONE
CertificateFile /etc/ssl/certs/ca-certificates.crt

IMAPStore proton-remote
Account proton

MaildirStore proton-local
Subfolders Verbatim
Path ~/mail/proton
Inbox ~/mail/proton/inbox

Channel proton
Far :proton-remote:
Near :proton-local:
Patterns *
Create Both
SyncState *

Running the sync command gave me an error that sent me on a goose chase:

mbsync -a

`Socket error: secure connect to 127.0.0.1 (127.0.0.1:1143): error:1408F10B:SSL routines:ssl3_get_record:wrong version number' The issue was the `SSLType NONE' is the proper config as shown above, I originally had it set to `IMAPS'. Once the sync starts it will take a long time depending upon how many emails you have.

Configuring mu4e

Configure the `mu4e-maildir ` location to wherever you want to store the mail directory (remember mail in this folder is stored in clear-text). The `mu4e-****-folder ` variables need to include the sub-directory in the relative path, in my case `proton'.

(use-package mu4e
  :straight nil
  :defer 20 ; Wait until 20 seconds after startup
  :config

  (setq mu4e-change-filenames-when-moving t ; avoid sync conflicts
	mu4e-update-interval (* 10 60) ; check mail 10 minutes
	mu4e-compose-format-flowed t ; re-flow mail so it's not hard wrapped
	mu4e-get-mail-command "mbsync -a"
	mu4e-maildir "~/mail/proton")

  (setq mu4e-drafts-folder "/proton/Drafts"
	mu4e-sent-folder   "/proton/Sent"
	mu4e-refile-folder "/proton/All Mail"
	mu4e-trash-folder  "/proton/Trash")

  (setq mu4e-maildir-shortcuts
	'(("/proton/inbox"     . ?i)
	  ("/proton/Sent"      . ?s)
	  ("/proton/Trash"     . ?t)
	  ("/proton/Drafts"    . ?d)
	  ("/proton/All Mail"  . ?a)))

  (setq message-send-mail-function 'smtpmail-send-it
	auth-sources '("~/.authinfo") ;need to use gpg version but only local smtp stored for now
	smtpmail-smtp-server "127.0.0.1"
	smtpmail-smtp-service 1025
	smtpmail-stream-type  'ssl))

I'm also configuring `smtpmail ` in the config section of `mu4e' just to keep mail config together, `smtpmail ` is part of Emacs core. I'm adding SMTP authentication info to the un-encrypted `.authinfo ` for the same reason as `.mbsyncrc' explanation above.

machine 127.0.0.1 login user@protonmail.com password ProtonBridgeGeneratedPassword port 1025

Using org-mode to compose HTML emails

At this stage plain-text email will work just fine, in order to send email with formatting I'm using `org-msg' which lets you compose with org markup and sends it out as HTML (including in-lining images, tables, etc.)

(use-package org-msg
  :straight t
  :after mu4e
  :config
  (setq mail-user-agent 'mu4e-user-agent)
  (require 'org-msg)
  (setq org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil \\n:t"
	org-msg-startup "hidestars indent inlineimages"
	org-msg-default-alternatives '((new		. (text html))
				       (reply-to-html	. (text html))
				       (reply-to-text	. (text)))
	org-msg-convert-citation t)
  (org-msg-mode))

References

Here are a list of references I used to get everything setup and configured:

https://systemcrafters.net/emacs-mail/

http://cachestocaches.com/2017/3/complete-guide-email-emacs-using-mu-and-/

https://jherrlin.github.io/posts/emacs-mu4e/

"Inverse literate" config via org-transclusion

I am very intrigued by the whole concept of literate programming. There is a lot of opinions and lots of valid points for and against comments, but ultimately it's always a good idea to understand intent. I wanted to create a literate config but did not want slow down startup with tangling.

I came across an interesting package today called [org-transclusion] by @nobiot. The package is very interesting, being able to bring in arbitrary lines of text from multiple documents into a single document (while those documents remain the source of truth) is quite powerful. The package also allows extracting sections based on tags (string match) which makes it a good contender to make an "inverse literate" configuration which I've been curious about ever since David Wilson did a [System Crafters live stream].

So I decided to give it a shot and got started with my custom configuration. I added some text comments to divide the configuration into sections:

;directory_begin
(setq user-emacs-directory "~/.emacs/.custom/")
;directory_end

Then I'm able to include it in an org file:

This line live in my org file, but the content below lives in my init.el file:
#+transclude: [[./init.el::;directory_begin]] :lines 2- :src emacs-lisp :end "directory_end"

Where `org-transclusion' looks for a file `./init.el' and searching for the begin string `;directory_begin ` and includes everything until it encounters the end string `;directory_end ` (both strings are arbitrary, I just picked that convention) but doesn't include the actual line containing "directory_end" as specified by the `:line 2- ` parameter. All of that would produce:

This line live in my org file, but the content below lives in my init.el file:
(setq user-emacs-directory "~/.emacs/.custom/")

And in the future if I added anything in `init.el' between the `;directory_begin ` and `;directory_end ` comment lines, then it would get included in the org file.

Here's what all of this looks like [in my actual configuration repo] (I haven't finished writing up all the sections yet, but plan to soonâ„¢.

Overall, this has worked pretty well. The file `config.org' in my repo contains the "source" and `org-transclusion' directives and is rendered out to `README.md' (markdown is better supported for auto-rendering by more forges currently). I'll eventually automate this process, likely through a git-hook. However, the rendered output is never guaranteed to include all of my config, just the sections that have been manually commented, `init.el' and includes will remain the source of truth.

org-transclusion

System Crafters live stream

in my actual configuration repo

Doom Emacs config (deprecated)

I was asked about my Doom config by [someone on fosstodon] but it's not a clean repo where I'm not confident that I didn't accidentally commit private information in the past, so I wasn't sure how to share. But this is a good time to put a pin in the config and capture a snapshot here, for reference.

This is quite messy and mixes idioms at random as I learned more about configuration. I also used this config to transition over to my custom config so I disabled some Doom functionality as I went down that path, in short, I was using a lot more packages in `init.el' that the current state below.

someone on fosstodon

init.el

(doom! :input
       ;;chinese
       ;;japanese

       :completion
       company           ; the ultimate code completion backend
       ;;helm              ; the *other* search engine for love and life
       ;;ido               ; the other *other* search engine...
       ;;ivy               ; a search engine for love and life

       :ui
       ;;deft              ; notational velocity for Emacs
       doom              ; what makes DOOM look the way it does
       doom-dashboard    ; a nifty splash screen for Emacs
       doom-quit         ; DOOM quit-message prompts when you quit Emacs
       ;;fill-column       ; a `fill-column' indicator
       hl-todo           ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
       ;;hydra
       indent-guides     ; highlighted indent columns
       modeline          ; snazzy, Atom-inspired modeline, plus API
       nav-flash         ; blink the current line after jumping
       ;;neotree           ; a project drawer, like NERDTree for vim
       ;;ophints           ; highlight the region an operation acts on
       (popup +defaults)   ; tame sudden yet inevitable temporary windows
       ;;pretty-code       ; ligatures or substitute text with pretty symbols
       ;tabs              ; an tab bar for Emacs
       ;;treemacs          ; a project drawer, like neotree but cooler
       unicode           ; extended unicode support for various languages
       vc-gutter         ; vcs diff in the fringe
       ;;vi-tilde-fringe   ; fringe tildes to mark beyond EOB
       ;;window-select     ; visually switch windows
       ;;workspaces        ; tab emulation, persistence & separate workspaces
       ;;zen               ; distraction-free coding or writing

       :editor
       (evil +everywhere); come to the dark side, we have cookies
       ;file-templates    ; auto-snippets for empty files
       fold              ; (nigh) universal code folding
       ;;(format +onsave)  ; automated prettiness
       ;;god               ; run Emacs commands without modifier keys
       ;;lispy             ; vim for lisp, for people who don't like vim
       ;;multiple-cursors  ; editing in many places at once
       ;;objed             ; text object editing for the innocent
       ;;parinfer          ; turn lisp into python, sort of
       ;;rotate-text       ; cycle region at point between text candidates
       snippets          ; my elves. They type so I don't have to
       ;;word-wrap         ; soft wrapping with language-aware indent

       :emacs
       (dired +icons)    ; making dired pretty [functional]
       electric          ; smarter, keyword-based electric-indent
       ;;ibuffer         ; interactive buffer management
       undo              ; persistent, smarter undo for your inevitable mistakes
       ;;vc              ; version-control and Emacs, sitting in a tree

       :term
       ;;eshell            ; the elisp shell that works everywhere
       ;;shell             ; simple shell REPL for Emacs
       ;;term              ; basic terminal emulator for Emacs
       vterm             ; the best terminal emulation in Emacs

       :checkers
       syntax              ; tasing you for every semicolon you forget
       spell             ; tasing you for misspelling mispelling
       ;;grammar           ; tasing grammar mistake every you make

       :tools
       ;;ansible
       ;;debugger          ; FIXME stepping through code, to help you add bugs
       ;;direnv
       ;;docker
       ;;editorconfig      ; let someone else argue about tabs vs spaces
       ;;ein               ; tame Jupyter notebooks with emacs
       (eval +overlay)     ; run code, run (also, repls)
       ;;gist              ; interacting with github gists
       lookup              ; navigate your code and its documentation
       lsp
       ;;macos             ; MacOS-specific commands
       (magit +forge)      ; a git porcelain for Emacs
       ;;make              ; run make tasks from Emacs
       ;;pass              ; password manager for nerds
       ;;pdf               ; pdf enhancements
       ;;prodigy           ; FIXME managing external services & code builders
       ;;rgb               ; creating color strings
       ;;terraform         ; infrastructure as code
       ;;tmux              ; an API for interacting with tmux
       ;;upload            ; map local to remote projects via ssh/ftp

       :lang
       ;;agda              ; types of types of types of types...
       ;;assembly          ; assembly for fun or debugging
       ;;cc                ; C/C++/Obj-C madness
       ;;clojure           ; java with a lisp
       ;;common-lisp       ; if you've seen one lisp, you've seen them all
       ;;coq               ; proofs-as-programs
       ;;crystal           ; ruby at the speed of c
       ;;csharp            ; unity, .NET, and mono shenanigans
       data              ; config/data formats
       ;;(dart +flutter)   ; paint ui and not much else
       ;;elixir            ; erlang done right
       ;;elm               ; care for a cup of TEA?
       emacs-lisp        ; drown in parentheses
       ;;erlang            ; an elegant language for a more civilized age
       ;;ess               ; emacs speaks statistics
       ;;faust             ; dsp, but you get to keep your soul
       ;;fsharp           ; ML stands for Microsoft's Language
       ;;fstar             ; (dependent) types and (monadic) effects and Z3
       ;;(go +lsp)         ; the hipster dialect
       ;;(haskell +dante)  ; a language that's lazier than I am
       ;;hy                ; readability of scheme w/ speed of python
       ;;idris             ;
       ;;(java +meghanada) ; the poster child for carpal tunnel syndrome
       ;;javascript        ; all(hope(abandon(ye(who(enter(here))))))
       ;;julia             ; a better, faster MATLAB
       ;;kotlin            ; a better, slicker Java(Script)
       ;;latex             ; writing papers in Emacs has never been so fun
       ;;lean
       ;;factor
       ;;ledger            ; an accounting system in Emacs
       ;;lua               ; one-based indices? one-based indices
       markdown          ; writing docs for people to ignore
       ;;nim               ; python + lisp at the speed of c
       ;;nix               ; I hereby declare "nix geht mehr!"
       ;;ocaml             ; an objective camel
       org ;;(org +roam)              ; organize your plain life in plain text
       ;;perl              ; write code no one else can comprehend
       ;;php               ; perl's insecure younger brother
       ;;plantuml          ; diagrams for confusing people more
       ;;purescript        ; javascript, but functional
       ;;python            ; beautiful is better than ugly
       ;;qt                ; the 'cutest' gui framework ever
       ;;racket            ; a DSL for DSLs
       ;;rest              ; Emacs as a REST client
       ;;rst               ; ReST in peace
       ;;(ruby +rails)     ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
       rust              ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
       ;;scala             ; java, but good
       ;;scheme            ; a fully conniving family of lisps
       (sh +lsp +fish)     ; she sells {ba,z,fi}sh shells on the C xor
       ;;sml
       ;;solidity          ; do you need a blockchain? No.
       ;;swift             ; who asked for emoji variables?
       ;;terra             ; Earth and Moon in alignment for performance.
       ;;web               ; the tubes

       :email
       ;;(mu4e +gmail)
       ;;notmuch
       ;;(wanderlust +gmail)

       :app
       ;;calendar
       ;;irc               ; how neckbeards socialize
       ;;(rss +org)        ; emacs as an RSS reader
       ;;twitter           ; twitter client https://twitter.com/vnought
       everywhere

       :config
       ;;literate
       (default +bindings +smartparens))

packages.el

;; Useful for position M-x (execute-extended-command) window on screen
(package! ivy-posframe)

;; Simpleclip allows access to system clipboard in a reasonable manner
(package! simpleclip)

;; Use org-journal with org-roam to follow Roam Research workflow
(package! org-journal)

;; Use org-roam-server to visualize org-roam links
(package! org-roam-server)

;; single dired buffer and icons
(package! all-the-icons-dired)
(package! dired-single)

(package! fish-completion
  :recipe (:host gitlab :repo "ambrevar/emacs-fish-completion"))

(package! emacas-0x0
  :recipe (:host gitlab :repo "willvaughn/emacs-0x0"))

(package! org-present)
(package! org-appear)

(package! ox-gemtext
  :recipe (:host nil :repo "https://codeberg.org/woozong/ox-gemtext"))

(package! gemini-mode)
(package! org-preview-html)

(package! ox-hugo)
(package! yaml-mode)
(package! ox-gemini)

(package! org-books)

(package! deadgrep)

(package! vertico)
(package! orderless)
(package! marginalia)
(package! embark)

(package! ace-window)

(package! org-bars
  :recipe (:host github :repo "tonyaldon/org-bars"))

(package! consult)

(package! vertico-posframe)

config.el

(setq doom-theme 'doom-one)

(setq doom-font (font-spec :family "JetBrains Mono" :size 14)
      doom-big-font (font-spec :family "JetBrains Mono" :size 32))

(setq display-line-numbers-type t)

;; CUA type customizations and conveniences=====================================
;; Simpleclip to access system clipboard
(require 'simpleclip)
(setq simpleclip-mode 1)

(map! :gin "C-S-x" #'simpleclip-cut ;Was: C-x chord
      :gin "C-S-c" #'simpleclip-copy ;Was: C-x chord
      :gin "C-S-v" #'clipboard-yank ;freezing on Ubuntu: 'simpleclip-paste ;Was: C-x chord
      :gin "C-z" #'undo ; Was: enable Emacs state
      :gin "C-S-z" #'redo ;Was: C-x chor
      ;; :gin "C-<tab>" #'switch-to-next-buffer ;Was: aya-create snippet
      ;; :gin "C-S-<tab>" #'previous-multiframe-window ;Was: C-x chord
      :gin "C-w" #'kill-buffer ;Was: evil-window-map
      :gin "C-a" #'mark-whole-buffer ;Was: doom/backward-to-bol-or-indent
      )

;; Escape smart-parens after done typing inside
(map! :i "M-;" #'sp-up-sexp) ;Was: comment-dwim

;; Save. Was: isearch-forward
(map! "C-s" #'save-buffer)
;; Save as. Was: nil
(map! "C-S-s" #'write-file)

;; Ctrl shift P like sublime for commands
(map! "C-S-p" #'execute-extended-command)

;; Popup which-key fast
(after! which-key
  (setq which-key-idle-delay 0.1))

;; Org mode related=============================================================
(setq org-directory "~/org/")
(setq org-agenda-files '("~/org/todo.org"))

;; Org files that are refile targets
(setq org-refile-targets (quote (("notes.org" :maxlevel . 1)
				 ("projects.org" :level . 1)
				 ("doomNotes.org" :level . 1)
				 )))

;; Allow text selection by holding down shift key
(setq org-support-shift-select t)

;; Mark when task was completed
(setq org-log-done 'time)

;; Toggle narrow/widen subtree. Was: append-next-kill
(map! "C-M-w" #'org-toggle-narrow-to-subtree)

;; Render modified text only not modifier characters
(setq org-pretty-entities-include-sub-superscripts t)

;; Show images in the org buffers
(setq org-startup-with-inline-images t)

;; Org-roam
(setq org-roam-mode 0)
(setq org-roam-directory "~/org/roam/")
(setq org-roam-buffer "Org-roam Sidebar")
(setq org-roam-buffer-width 0.15)
;;(setq org-roam-buffer-no-delete-other-windows t)
(setq org-roam-link-title-format "∞%s")

;; Org-journal roam integration
;; From @ianjones on doom emacs discord: https://www.ianjones.us/blog/2020-05-05-doom-emacs/#fleeting-notes
(use-package org-journal
      :custom
      (org-journal-dir "~/org/roam/journal/")
      (org-journal-date-prefix "#+TITLE: ")
      (org-journal-file-format "%Y-%m-%d.org")
      (org-journal-date-format "%A, %B %d %Y"))
(setq org-journal-enable-agenda-integration t)
(map! "C-c C-5" #'org-journal-search) ;;was overriding org schedule

(setq org-roam-dailies-capture-templates
      '(("d" "daily" plain #'org-roam-capture--get-point ""
	 :immediate-finish t
	 :file-name "%<journal/%Y-%m-%d>"
	 :head "#+TITLE: %<%Y %B %d, %A>\nTAGS: [[file:dailies.org][∞Dailies]]\n\n*")))

(setq org-roam-capture-templates '(
				   ("d" "default"
				    plain
				    #'org-roam-capture--get-point "%?"
				    :file-name "%<%Y%m%d>-${slug}"
				    :head "#+TITLE: ${title}\n"
				    :unnarrowed t)
				   ("p" "personal"
				    plain
				    #'org-roam-capture--get-point "%?"
				    :file-name "personal/%<%Y%m%d>-${slug}"
				    :head "#+TITLE: ${title}\n"
				    :unnarrowed t)))
;; org-roam-server=====================================
(if (eq system-type 'gnu/linux)
    (use-package org-roam-server
      :ensure t
      :config
      (setq org-roam-server-host "127.0.0.1"
	    org-roam-server-port 8008
	    org-roam-server-authenticate nil
	    org-roam-server-export-inline-images t
	    org-roam-server-serve-files nil
	    org-roam-server-served-file-extensions '("pdf" "mp4" "ogv")
	    org-roam-server-network-poll t
	    org-roam-server-network-arrows nil
	    org-roam-server-network-label-truncate t
	    org-roam-server-network-label-truncate-length 60
	    org-roam-server-network-label-wrap-length 20))
  )
;; Posframe customization to position popup=====================================
(require 'ivy-posframe)
;; display at `ivy-posframe-style'
(setq ivy-posframe-display-functions-alist
      '((t . ivy-posframe-display)))
(setq ivy-posframe-display-functions-alist
      '((t . ivy-posframe-display-at-frame-center)))
(ivy-posframe-mode t)

;; Use aspell for spell-checking================================================
(setq-default ispell-program-name "aspell")

;; Speed up frame by loading heavy things when daemon starts
(when (daemonp)
  (require 'org)
  (require 'org-roam)
  (require 'ispell)
  (ispell-start-process))

;; dired config from system builder's emacs from scratch #1
(use-package dired
    :ensure nil
    :commands (dired dired-jump)
    :bind (("C-x C-j" . dired-jump))
    :custom ((dired-listing-switches "-agho --group-directories-first"))
    :config
    (evil-collection-define-key 'normal 'dired-mode-map
      "h" 'dired-single-up-directory
      "l" 'dired-single-buffer))

(use-package dired-single
  :ensure t
  :init
  (require 'dired-single))

(use-package all-the-icons-dired
    :hook (dired-mode . all-the-icons-dired-mode))

;; Magit forge configuration==================================================
(setq auth-sources '("~/.authinfo"))

;; eshell configuration ======================================================
(when (and (executable-find "fish")
	   (require 'fish-completion nil t))
  (global-fish-completion-mode))

;; vterm configuration========================================================
(use-package vterm
  :commands vterm
  :config
  (setq term-prompt-regexp "^[^#$%>\n]*[#$%>] *")
  (setq vterm-shell "fish")
  (setq vterm-max-scrollback 10000))

;; org-present configuration from https://github.com/daviwil/dotfiles=========
(defun dw/org-present-prepare-slide ()
  (org-overview)
  (org-show-entry)
  ;(org-show-children)
  )

(defun dw/org-present-hook ()
  (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch)
				     (header-line (:height 4.5) variable-pitch)
				     (org-document-title (:height 1.75) org-document-title)
				     (org-code (:height 1.55) org-code)
				     (org-verbatim (:height 1.55) org-verbatim)
				     (org-block (:height 1.25) org-block)
				     (org-block-begin-line (:height 0.7) org-block)))
  (setq header-line-format " ")
  (org-appear-mode -1)
  (org-display-inline-images)
  (display-line-numbers-mode)
  (dw/org-present-prepare-slide))

(defun dw/org-present-quit-hook ()
  (setq-local face-remapping-alist '((default variable-pitch default)))
  (setq header-line-format nil)
  (org-present-small)
  (org-remove-inline-images)
  (org-appear-mode 1)
  (display-line-numbers-mode))

(defun dw/org-present-prev ()
  (interactive)
  (org-present-prev)
  (dw/org-present-prepare-slide))

(defun dw/org-present-next ()
  (interactive)
  (org-present-next)
  (dw/org-present-prepare-slide))

(use-package org-present
  :after simple
  :after org
  :bind (:map org-present-mode-keymap
	 ("C-j" . dw/org-present-next)
	 ("C-k" . dw/org-present-prev))
  :hook ((org-present-mode . dw/org-present-hook)
	 (org-present-mode-quit . dw/org-present-quit-hook)))

;; Gemini=====================================================================
(require 'ox-gemtext)
(add-hook 'find-file-hook
	  (lambda ()
	    (when (string= (file-name-extension buffer-file-name) "gmi")
	      (gemini-mode +1))))
;; ox-hugo====================================================================
(require 'ox-hugo)
(require 'ox-gemini)

;; Org capture template for Hugo posts
;; https://ox-hugo.scripter.co/doc/org-capture-setup/
(with-eval-after-load 'org-capture
  (defun org-hugo-new-subtree-post-capture-template ()
    "Returns `org-capture' template string for new Hugo post.
See `org-capture-templates' for more information."
    (let* ((title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title
	   (fname (concat (format-time-string "%Y%m%d_") (org-hugo-slug title))))
      (mapconcat #'identity
		 `(
		   ,(concat "\n* DRAFT " title)
		   ":PROPERTIES:"
		   ,(concat ":EXPORT_FILE_NAME: " fname)
		   ":EXPORT_HUGO_MENU:\n:END:"
		   "%?\n")          ;Place the cursor here finally
		 "\n")))

  (add-to-list 'org-capture-templates
	       '("h"                ;`org-capture' binding + h
		 "Hugo post"
		 entry
		 ;; It is assumed that below file is present in `org-directory'
		 ;; and that it has a "Blog Ideas" heading. It can even be a
		 ;; symlink pointing to the actual location of all-posts.org!
		 (file+olp "~/dev/shom.dev/content.org" "Content")
		 (function org-hugo-new-subtree-post-capture-template)
		 :prepend t)))

;; Embark config==============================================================
(use-package embark
  :ensure t
  :bind
  (("C-;" . embark-act)
   ("C-M-;" . embark-dwim)
   ("C-h B" . embark-bindings))

  :init
  (setq prefix-help-command #'embark-prefix-help-command))


;; Org-books==================================================================
(setq org-books-file "~/org/roam/personal/books.org")

;; Vertico ===================================================================
;; Enable vertico
(use-package vertico
  :ensure t
  :init
  (vertico-mode)

  ;; Optionally enable cycling for `vertico-next', `vertico-previous',
  ;; `vertico-next-group' and `vertico-previous-group'.
  (setq vertico-cycle t))

;; Optionally use the `orderless' completion style. See
;; `+orderless-dispatch' in the Consult wiki for an advanced Orderless style
;; dispatcher. Additionally enable `partial-completion' for file path
;; expansion. `partial-completion' is important for wildcard support.
;; Multiple files can be opened at once with `find-file' if you enter a
;; wildcard. You may also give the `initials' completion style a try.
(use-package orderless
  :ensure t
  :custom (completion-styles '(orderless)))
(orderless-define-completion-style orderless+initialism
  (orderless-matching-styles '(orderless-initialism
			       orderless-literal
			       orderless-regexp)))
(setq completion-category-overrides
      '((command (styles orderless+initialism))
	(symbol (styles orderless+initialism))
	(variable (styles orderless+initialism))))

;; Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist
  :init
  (savehist-mode))

(use-package marginalia
  :after vertico
  :ensure t
  :custom
  (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
  :init
  (marginalia-mode))

(use-package consult
  :after vertico)
(map! :gin "C-<tab>" #'consult-buffer
      :gin "C-f" #'consult-ripgrep
      :given "C-i" #'consult-imenu)

;; Window and decoration =====================================================
(set-fringe-mode '(15 . 10))

(use-package ace-window
  :ensure t
  :init
  (global-set-key (kbd "M-q") 'ace-window)
  (setq aw-dispatch-always t)
  (custom-set-faces!
    '(aw-leading-char-face
      :foreground "white" :background "red"
      :weight bold :height 2.5 :box (:line-width 10 :color "red"))))


;; Org-bars configuration ====================================================
(use-package org-bars
  :after org
  :ensure t
  :init
 (defun org-no-ellipsis-in-headlines ()
 "Remove use of ellipsis in headlines.
See `buffer-invisibility-spec'."
  (remove-from-invisibility-spec '(outline . t))
  (add-to-invisibility-spec 'outline))
 (add-hook 'org-mode-hook #'org-bars-mode)
 (add-hook 'org-mode-hook 'org-no-ellipsis-in-headlines))

;; ===========================================================================
(after! tramp
  (setq tramp-inline-compress-start-size 1000)
  (setq tramp-copy-size-limit 10000)
  (setq tramp-verbose 1)
  (setq tramp-default-method "scp")
  (setq tramp-use-ssh-controlmaster-options t)
  (setq tramp-verbose 1))

;; ===========================================================================
(use-package vertico-posframe
  :after vertico
  :ensure t
  :init
  (vertico-posframe-mode 1))

Highland Chewie

I picked up a water color kit for $2 with a brush and eight colors to try something new. I followed along with a [tutorial] to paint a highland cow and my painting wasn't that great, but it was fun. Afterwards it felt a little like Chewbacca, so l added a bandolier. Here's +Highland Chewie+ Chewvaca:

Chewvaca

tutorial

Emacs which-key prefix labels

I've been using `evil-mode' for my Emacs configuration and [evil-leader] makes the key-mapping very straight-forward with the `set-key'. I wanted a few functions to be grouped together. `SPC' is bound as a leader key and there are a few frequent functions bound to single keys, the rest are grouped under other leaders.

However, the secondary leaders show up as `x → +prefix' and it would nice to give the grouping a name. A lot of suggestions make use of the [General.el] but at this time I didn't need anything beyond giving the grouping a name. I was not immediately able to find a way to create an empty keymap to put commands under (I did not know that's what I needed to do), like this: `"e" '("eval" . (keymap)) `

(evil-leader/set-key
"." 'find-file
"," 'consult-buffer
"'" 'execute-extended-command

"e" '("eval" . (keymap))
"eb" '("buffer" . eval-buffer)
"er" '("region" . eval-region)

"g" '("magit" . (keymap))
"gc" '("commit" . magit-commit)
"gf" '("fetch" . magit-fetch)
"gg" '("status" . magit-status)

"q" '("quit" . (keymap))
"qb" '("buffer" . kill-this-buffer)
"qq" '("save&quit" . save-buffers-kill-terminal)

"h" '("help" . (keymap))
"hf" '("function" . describe-function)
"hk" '("key" . describe-key)
"hv" '("variable" . describe-variable)

"w" '("window" . (keymap))
"wd" '("delete" . delete-window)
"wo" '("delete other" . delete-other-windows)
"ww" '("ace-window" . aw-show-dispatch-help))

evil-leader

General.el

Emacs custom configuration

I crafted a custom configuration for Emacs and have been using it for the past few weeks. This is something I didn't really see myself doing when I started using Emacs, it seemed "very advanced". This was my journey from a noob to a different kind of noob!

Doom

I started my Emacs journey with [Doom] and was learning things along the way. This was a great way to get started by borrowing configuration snippets and blindly copying and pasting, which got me up and running quickly. I did find the vastness of Doom intimidating and knew that I wasn't using all the functionality and wasn't really discovering it given the jam packed key-maps.

Doom

Vanilla Chocolate Swirl

Around the time when I was understanding how to copy paste configs more, there was some community discussion around making Emacs more inviting to new users. As a new user, I felt qualified to collect my thoughts. In an attempt to help new user on-boarding, I even created a [literate config] that others found useful enough to contribute to. I understood things a lot better through that exercise and felt comfortable enough to try packages by myself.

literate config

Back to Doom

Actually, I never left Doom while doing the above exercise. I did not want to invest the time necessary to learn to make my own config. Also, having all the keybindings already setup and showing up nicely in `which-key ` was great. This is also before `native-comp' was merged into Emacs 28 master branch so I was having issues with compatibility. The final push was that using Doom with all its modules was not performant on a Windows machine that I don't manage but have to use.

Custom Config

[During this time], I kept disabling more and more Doom modules and replacing some of them with other options. There seems to be a lot of excitement about light-weight packages like `vertico', `consult', etc. that are more single task focused which I started integrating. I started using `orderless', `embark' and `ace-window' as well and with those, I felt I had enough to use a custom config and be productive. I'm using [Chemacs2] to have both my Doom config and my [custom config] installed but have been exclusively using the config.

I'll make a few short posts with some of the things I learned in this process with some code snippets as examples.

During this time

Chemacs2

custom config

Sony A7c initial customization

I have been using the Sony A7ii for a long while. It was my first full-frame and mirrorless camera. The A7ii is a great camera and in a lot of ways I have been very spoiled by it. However, when the A7iii came out with fairly significant improvements I resisted the urge to upgrade and decided to wait for the A7iv.

The A7iv was released last week and in many regards is a "perfect" camera. It has made a lot of improvements in an already excellent line-up and is perhaps justifiably is also priced 25% more than it's predecessor. However, most of the advancements were made in the video department (save for the new 33MP sensor) and that is not the feature set I use. Also, given the shortage of electronic parts it is unclear when pre-orders would get into the hands of users. Ultimately, after waiting for an agonizing 3.5 years after the release of the A7iii, I decided not to buy the A7iv.

Instead, I opted for the A7c which was released in 2020 and is essentially an A7iii in a smaller body. It loses the dual SD cards, 2 custom buttons, and a joystick but gains a fully articulating LCD monitor, compactness, and a range-finder look and feel. I decided to get it with the compact (but quite excellent) 28-60 f/4-5.6 kit lens and make this is my "only" camera for both landscape and underwater photography (with a Seafrog case I intend to get).

All of this preface to get to my main point. I have customized a lot of functions of the A7ii that I no longer remember the "how" or the "why" behind those changes. Here are the main changes I made and replicated on the A7c before the first shoot.

Image from first shoot:

Lake McDonald

Back-button auto-focus

Decoupling auto-focus from the shutter action allows me to focus on a subject and wait for the right moment to click the shutter without worrying about refocusing/losing focus. This is accomplished in two pieces, first the shutter and auto-focus is decoupled and then the auto-focus function is then remapped to a button on the back of the camera.

Decouple auto-focus from shutter

The current Sony terminology for decoupling auto-focus from shutter is `AF w/ shutter'. In the A7C it is found in `Menu - Camera 1 - AF2 ` (Page 5).

It is also a good idea to turn off `Pre-AF Off' which moves the focus point based on the scene changes even before auto-focus is actuated (to improve speed).

`NOTE: ` Shutter half-press is not customizable on the A7c (unlike A7ii)

Remap auto-focus to another button

I'm choosing to use the default `AF-On' button on the back of the camera for now. But it can be customized to any of the other buttons in `Menu - Camera 2 - Custom Operation1 - Custom Key ` (Page 9).

DRO/Auto HDR

The LCD panel on the camera shows the JPEG preview of the image regardless of whether you're shooting RAW. The Dynamic Range Optimization (DRO) boosts the shadows and that's what shows up in the LCD, which in turn means that the RAW is underexposed. The `DRO/Auto HDR' setting can be turned off in `Menu - Camera 1 - Color/WB/Img.Processing1 ` (Page 11).

This [video from Nick Page] describes the issue and suggests this fix.

video from Nick Page

Long Exposure NR

By default the camera attempts to do Noise Reduction (NR) when doing long-exposure. While this does create a lower noise image it comes at the expense of "timing out" for the same length of time the original exposure was. This makes sense since the camera takes a "dark" image with the shutter closed as a noise reference and subtracts it from the original exposure to remove that noise. However, this is a major hindrance for doing multiple longer exposure shots especially as the light is fading. Turning the `Long Exposure NR' feature off is necessary for those scenarios. The option is found in `Menu - Camera 1 - Quality/Image Size2 ` (Page 2).

`NOTE: ` There's a related setting for `High ISO NR'.

`NOTE: ` If attempting proper astrophotography then multiple dark frames are needed anyway for proper post processing.I'll

These are the main features that would have "bit" me if I didn't change them before trying to use the camera. If there are others, I will note them here after they bite me.

org-bars view for outlining/folding

I came across this new [org-bars] package that shows folding indicators and lines to indicate the groupings. In the [reddit] discussion I also discovered that there's another package [org-visual-outline] but it actually requires configuring two packages so I didn't try it.

However, based on the discussion in the comments it seems that `org-bars ` supports narrowing of the buffer (and it works great) which visual-outline does not. I discovered a visual bug and filed a [report], so hopefully it's an easy fix but it's not a breaking issue.

Here's the configuration I'm using based on the recommendations in the documentation.

;; Org-bars configuration ====================================================
(use-package org-bars
  :after org
  :ensure t
  :custom
 (defun org-no-ellipsis-in-headlines ()
 "Remove use of ellipsis in headlines.
See `buffer-invisibility-spec'."
  (remove-from-invisibility-spec '(outline . t))
  (add-to-invisibility-spec 'outline))
 (add-hook 'org-mode-hook #'org-bars-mode)
 (add-hook 'org-mode-hook 'org-no-ellipsis-in-headlines))

Here's a screenshot of my Hugo content buffer showing `org-bars `:

Org-Bars

org-bars

reddit

org-visual-outline

report

Wine and CrossOver to use Lightroom on Linux

I have been using [Darktable] and transitioning away from Adobe's Lightroom. However, I have almost a decade of edits and experience with Lightroom so doing a cold-turkey switch is proving to be challenging. So I decided to investigate if I could "natively" run Lightroom (without a VM) so I decided to give `wine' a try.

I use `guix' as a package manager on Pop!_OS and guix has `wine' but it did a while to build and install. I needed to download a Lightroom Classic executable but like a lot of software it's an installer that does the downloading and installing. However, Adobe won't allow you to download a Windows installer on Linux, so I had to use [User-Agent Switcher] on Firefox to Windows to even get the installer... this is part of the frustration of software you lease.

`wine' will ask to install mono installer, which is does by itself and then the same thing with Gecko installer. Overall a pretty smooth process but the Adobe installer failed miserably with a less than helpful error.

Crash Annotation GraphicsCriticalError: |[0][GFX1]: Potential driver version mismatch ignored due to missing DLLs 0.0.0.0 and 0.0.0.0 (t=18.9854
) [GFX1]: Potential driver version mismatch ignored due to missing DLLs 0.0.0.0 and 0.0.0.0

At this point I didn't have high hopes for avoiding the Windows VM route but wanted to give a quick try to [CrossOver]. I tried one of their supported applications (Notepad++) and that worked great. They also support "unlisted application" but pointing the Adobe installer led to a lot of nothing, the logs were not very helpful either. At this point I decided to abandon this path and go the VM route to make progress on my actual photo editing goals. However, Steam's [Proton] could be a option to investigate in the future. Are there any other good solutions?

Darktable

User-Agent Switcher

CrossOver

Proton

Fully automated deployment

Up until the last commit, the site was being written in Org Mode, exported using ox-hugo, and Hugo was invoked manually to generate the html all locally. The generated `public' folder was what was being pushed to SourceHut for the deployment. This will be first post which will only commit the actual content in org format only and the full CI/CD will happen on SourceHut.

Using org-publish

I'll be following along with the System Crafters' [Publishing Website with Org Mode] to take full advantage of `org-publish ` and configure multiple outputs (WWW and Gemini). As of the now the following configuration is invoking the correct export function through org-publish but ox-hugo isn't finding the Hugo sub-trees.

(message "\n==== Exporting Hugo markdown ====")
(setq org-publish-project-alist
      (list
       (list "org-site:main"
	     :recursive nil
	     :base-directory "./"
	     :publishing-function '(org-hugo-export-wim-to-md :all-subtrees nil :visible-only nil)
	     :publishing-directory "./public"
	     ;; :with-author nil           ;; Don't include author name
	     ;; :with-creator t            ;; Include Emacs and Org versions in footer
	     ;; :with-toc t                ;; Include a table of contents
	     ;; :section-numbers nil       ;; Don't include section numbers
	     :time-stamp-file nil)))    ;; Don't include time stamp in file

;; Generate the site output
(org-publish-all t)

(message "\n==== Export complete ====")

`RESULTS'

Publishing file /home/shom/dev/shom.dev/content.org using `org-hugo-export-wim-to-md'
[ox-hugo] No valid Hugo post subtrees were found

Publishing Website with Org Mode

Using hugo-export directly

In order to check sanity and solve the issue, I exported directly with `org-hugo-export-wim-to-md ` which is straightforward since I've opted for a single org-content file and it worked as expected. So this is the configuration that is currently building the site:

(message "\n==== Exporting Hugo markdown ====")
(with-current-buffer (find-file "./content.org")
  (org-hugo-export-wim-to-md :all-subtrees nil :visible-only nil))

(message "\n==== Export complete ====")

I would like to get the `org-publish ` route sorted out so I can publish to the Hugo site and the Gemini capsule with a single commit.