Skip to content

jackson15j/dot_emacs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

My Literate Emacs Config

Dot Emacs

My main .emacs file.

NOTE: For built-in packages, check out the emacs manual via: C-h r!

Ansible:

Install via ansible with the following command, which will prompt for sudo password (pacman package installation) due to the -K or --ask-become-pass flag:

  • cd ansible/
  • ansible-playbook main.yml -K

You can add -i hosts if you want to run against remote hosts instead of locally.

NOTE: Hard-coded to ArchLinux and my own needs.

Hooks:

To unset a key binding: ~M-x global-unset-key~y

To remove all hooks from a mode during testing, evaulate: (setq <mode-hook> nil). As per: https://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html

Core:

compliation

(use-package compile
  :ensure t
  :custom
  (compilation-ask-about-save nil "Auto save before compiling.")
  (compilation-scroll-output t "Scroll output and don't stop on errors.")
  )

Debugging Emacs:

(setq debug-on-error t)
(use-package bug-hunter
  :ensure t
  :defer t)

To start Esup, run M-x esup, and watch the magic happen.

By default, Esup will profile user-init-file. To profile a custom file, call esup with a prefix argument. That is, C-u M-x esup.

(use-package esup
  :ensure t
  :defer t
  :defer
  :config
  ;; Work around a bug where esup tries to step into the byte-compiled
  ;; version of `cl-lib', and fails horribly.
  ;; See; https://github.com/jschaf/esup/issues/85
  (setq esup-depth 0)
  )

dired:

(use-package dired
  :custom
  (dired-async-mode t)
  (dired-listing-switches "-alFh")
  (dired-dwim-target t)  ;; Guess target for operations.
  )

Dired decompress and rename workflow:

  • Decompress archive(s):
    • Z decompress to a folder named after archive.
    • ! <RETURN> to decompress to current folder.
  • Rename files/folders:
    • C-xC-q (M-x dired-toggle-read-only) buffer editing.
    • C-cC-c commit changes to disk.

doc-view-mode:

PDF support (install dependencies):

(use-package doc-view
  :ensure-system-package ((gs . ghostscript))
  )

Eglot (Github: joaotavora/eglot) is the built-in, streamlined LSP (Language Server Protocol) client for emacs, to talk to LSP Servers with. it is the alternative to the external,feature-rich package: lsp-mode.

NOTE: Currently transitioning over to eglot from: lsp-mode, as part of trying to slim down config and use more built-ins.

(use-package eglot
  ;; TODO: Raise bug about how this `:after` call breaks `eglot` automatically
  ;; running.
  ;; :after (company-mode)
  :hook (
         (eglot-mode . global-company-mode)
         ;; NOTE: `prog-mode` covers too many non-lsp modes. Tired of constant
         ;; errors, so going back to explicitly enabling eglot on each mode!
         ;; (prog-mode . eglot-ensure)
         )
  :ensure t)

Breadcrumb is a mode that fell out of the wish for eglot Users to have the same breadcrumb as seen in lsp-ui. See: Github: joaotavora/eglot - Breadcrumb feature (can eglot support headerline like lsp-mode does?) #988.

This is external to eglot, but placing here just because of the link.

(use-package breadcrumb
  :vc (:url "https://github.com/joaotavora/breadcrumb"
       :rev :newest)
  :ensure t
  :config
  (breadcrumb-mode)
  )

eww:

(use-package eww
  :bind (("<f4>" . eww))
  ;; FIXME: eww is okay, but for things like google account redirects, we need
  ;; a real browser.
  :config
  (setq eww-bookmarks-directory "~/org/personal/")
  ;; (progn
  ;;   (setq
  ;;    browse-url-browser-function (quote eww-browse-url)
  ;;    )
  ;;   )
  )

'(browse-url-browser-function (quote browse-url-default-browser))  ; Use system default browser instead of eww.
;; bound this to Darwin only.
;; (cond
;;  ((string-equal system-type "darwin")
;;   (setq browse-url-browser-function  (quote browse-url-default-browser))));;'browse-url-generic
;;         browse-url-generic-program "/Applications/Opera.app/Contents/MacOS/Opera")))

Fontify code in eww buffer:

(use-package language-detection
  ; https://github.com/andreasjansson/language-detection.el
  :ensure t
  :defer t
  )

(require 'cl-lib)

(defun eww-tag-pre (dom)
  "See: https://github.com/andreasjansson/language-detection.el.
DOM - web dom."
  (let ((shr-folding-mode 'none)
        (shr-current-font 'default))
    (shr-ensure-newline)
    (insert (eww-fontify-pre dom))
    (shr-ensure-newline)))

(defun eww-fontify-pre (dom)
  "See: https://github.com/andreasjansson/language-detection.el.
DOM - web dom."
  (with-temp-buffer
    (shr-generic dom)
    (let ((mode (eww-buffer-auto-detect-mode)))
      (when mode
        (eww-fontify-buffer mode)))
    (buffer-string)))

(defun eww-fontify-buffer (mode)
  "See: https://github.com/andreasjansson/language-detection.el.
MODE - ??"
  (delay-mode-hooks (funcall mode))
  (font-lock-default-function mode)
  (font-lock-default-fontify-region (point-min)
                                    (point-max)
                                    nil))

(defun eww-buffer-auto-detect-mode ()
  "See: https://github.com/andreasjansson/language-detection.el."
  (let* ((map '((ada ada-mode)
                (awk awk-mode)
                (c c-mode)
                (cpp c++-mode)
                (clojure clojure-mode lisp-mode)
                ; (csharp csharp-mode java-mode)
                (css css-mode)
                (dart dart-mode)
                (delphi delphi-mode)
                (emacslisp emacs-lisp-mode)
                (erlang erlang-mode)
                (fortran fortran-mode)
                (fsharp fsharp-mode)
                (go go-mode)
                (groovy groovy-mode)
                (haskell haskell-mode)
                (html html-mode)
                (java java-mode)
                (javascript javascript-mode)
                (json json-mode javascript-mode)
                (latex latex-mode)
                (lisp lisp-mode)
                (lua lua-mode)
                (matlab matlab-mode octave-mode)
                (objc objc-mode c-mode)
                (perl perl-mode)
                (php php-mode)
                (prolog prolog-mode)
                (python python-mode)
                (r r-mode)
                (ruby ruby-mode)
                (rust rust-mode)
                (scala scala-mode)
                (shell shell-script-mode)
                (smalltalk smalltalk-mode)
                (sql sql-mode)
                (swift swift-mode)
                (visualbasic visual-basic-mode)
                (xml sgml-mode)))
         (language (language-detection-string
                    (buffer-substring-no-properties (point-min) (point-max))))
         (modes (cdr (assoc language map)))
         (mode (cl-loop for mode in modes
                        when (fboundp mode)
                        return mode)))
    (message (format "%s" language))
    (when (fboundp mode)
      mode)))

(setq shr-external-rendering-functions
      '((pre . eww-tag-pre)))

flymake:

FIXME: flymake: temp disable due to noise from legacy init mode: (error "Can’t find a suitable init function").

Doesn’t appear when flymake is started by eglot in a mode that has an lsp.

(use-package flymake
  :bind (:map flymake-mode-map
         ("C-c e" . flymake-show-buffer-diagnostics)
         ("C-c p" . flymake-show-project-diagnostics)
         ("C-c j" . flymake-goto-next-error)
      )
;;  :hook (
;;         (prog-mode . flymake-mode)
;;         (text-mode . flymake-mode)
;;         )
  :config
  (progn
   (set-face-attribute 'flymake-error nil :background "DarkRed")
   (set-face-attribute 'flymake-warning nil :background "DarkBlue")
   (set-face-attribute 'flymake-note nil :background "DarkGreen")
   )
  )

General

  • Don’t prompt to kill processes on exit.
    (setq confirm-kill-processes nil)
    (setq-default tab-width 4)
        
  • Global defaults:
    (setq-default tab-width 4)
        
  • Fuzzy completions (just like ido with fuzzy matching set + smex) and Save history in minibuffers.
    (fido-mode t)
    (savehist-mode t)
    (setq savehist-additional-variables '(search-ring regexp-search-ring))
        
  • Bookmarks:
    (setq bookmark-default-file "~/org/personal/bookmarks")
        
  • Highlights:
    (global-hl-line-mode 1)  ;; horizontal highlighted line on cursor.
    ;; http://www.emacswiki.org/emacs/EmacsNiftyTricks
    ;; http://emacs-fu.blogspot.com/2008/12/highlighting-todo-fixme-and-friends.html
    (defun my_highlighted_words ()
      "Highlight specific words in the buffer."
     (interactive)
      (font-lock-add-keywords nil
       '(("\\<\\(Note\\|NOTE\\|FIXME\\|Todo\\|TODO\\|BUG\\|Bug\\):" 1 '(:foreground "red" :weight bold) t))))
        

backups:

;; backup files - https://www.emacswiki.org/emacs/BackupDirectory
(setq
   backup-by-copying t      ; don't clobber symlinks
   backup-directory-alist
    '(("." . "~/.emacs.d/.backups/"))    ; don't litter my fs tree
   delete-old-versions t
   kept-new-versions 6
   kept-old-versions 2
   version-control t)       ; use versioned backups
(make-directory "~/.emacs.d/.backups/" t)
;; https://emacs.stackexchange.com/questions/17210/how-to-place-all-auto-save-files-in-a-directory
(setq auto-save-file-name-transforms
      `(
        ("\\`/[^/]*:\\([^/]*/\\)*\\([^/]*\\)\\'" "/tmp/\\2" t)
        (".*" "~/.emacs.d/.auto-saves/" t)
        )
      )
(make-directory "~/.emacs.d/.auto-saves/" t)
;; Don't save lock files by files - https://www.emacswiki.org/emacs/LockFiles.
(setq create-lockfiles nil)

Desktop:

Auto save all open files in current session and reload on startup.

(use-package desktop
  :ensure t
  :defer t
  :init (desktop-save-mode)
  :config
  (progn
    ;; Don't autosave desktops, it's too expensive.  Desktops aren't
    ;; that precious, and Emacs will save the desktop on exit anyway.
    (setq
     desktop-restore-eager 0
     desktop-load-locked-desktop t
     desktop-auto-save-timeout nil
     desktop-path '("~/")
     desktop-dirname "~/")
    (dolist (mode '(magit-mode git-commit-mode))
      (add-to-list 'desktop-modes-not-to-save mode))))

display-line-numbers:

Use the C-based line numbers instead of the slower lisp (`linum`). https://www.emacswiki.org/emacs/LineNumbers#h5o-1

(use-package display-line-numbers
  :hook (
         (conf-mode . 'display-line-numbers)
         (prog-mode . 'display-line-numbers)
         (text-mode . 'display-line-numbers)
         (org-mode . (lambda () (display-line-numbers-mode -1)))
         )
  :custom-face
   (line-number ((t (:inherit (shadow default) :background "grey10"))))
  )

Hash (#) on Macs:

Allow `Alt+3` on a Mac to be `#`:

(global-set-key (kbd "M-3") '(lambda () (interactive) (insert "#")))
(define-key isearch-mode-map (kbd "M-3") '(lambda () (interactive) (isearch-process-search-char ?\#)))

which-key:

which-key integration, to show keyboard shortcuts.

(use-package which-key
  :ensure t
  :config
  (which-key-mode))

Highlight white-space (eg. tabs) in the buffer.

(use-package whitespace
  :ensure t
  :config
  (global-whitespace-mode)
  (setq whitespace-style (quote (face trailing tabs)))
  )

Load extra dot files:

Load extra dot files (if they exist).

(make-directory "~/org/emacs" t)
(use-package cus-edit
  :custom (custom-file "~/org/emacs/custom_set_variables.el" "Moved custom-set-variables to it's own file")
  )

(let () (dolist (dot_emacs '("~/org/emacs/custom_set_variables.el"
                             "~/org/emacs/private_dot_emacs.el"
                             "~/org/emacs/unstable_config_dot_emacs.el"
                             "~/org/emacs/work_specific_dot_emacs.el"))
          "Loading my extra emacs dot files if they exist."
          (when (file-exists-p dot_emacs)
            (message (concat "Loading external dot file: " dot_emacs))
            (load-file dot_emacs))))

mode-line:

The gutter bar at the bottom of the emacs window/frame.

(setq column-number-mode t)

Highlight active mode-line:

See:

(set-face-attribute 'mode-line-active nil
                    :foreground "black" :background "goldenrod" :box '(:line-width 1 :color "black"))

smart mode line wraps up a lot of nice tweaks in one package.

NOTE: Trialling the stock mode-line for a bit to see if I can live without smart-mode-line.

(use-package smart-mode-line
  ;; :ensure t
  :disabled t
  :defer t
  :init
  (setq
   sml/no-confirm-load-theme t
   sml/theme 'dark
   sml/mode-width `full
   )
  (sml/setup)
  (column-number-mode t)
  )

Native Compilation:

Don’t load outdated byte code.

(setq load-prefer-newer t)

SO: How do I byte compile everything?

;; (byte-recompile-directory (expand-file-name "~/.emacs.d") 0)

Log but don’t pop up Warnings buffer for all native compilation warnings.

(setq native-comp-async-report-warnings-errors 'silent)

Project management:

I’ve used projectile for years, but giving project a go. Only ever used:

CommandsProjectileProject
Fuzzy search for filesC-c p fC-x p f
Grep projectC-c gC-x p g
Switch buffers in projectC-x p b
Switch ProjectC-c p pC-c p p

Going to try project for a bit and see how it goes.

project (built-in):

(use-package project
  :ensure t)
Historical notes:

Been getting more annoyed at not using daemon mode on my main box and connecting with emacsclients. Due to work, I use quite a few git-worktree’s of the same repo. The problem would be accidentally cross editing files across the different worktree’s (Hence not using daemon mode, and instead just running up multiple emacs --debug-init sessions for each worktree.

Let’s have a go at banishing this behaviour:

  • Projectile: Allows for project focus (git repo), whilst also doing fuzzy file searching across the entire project (Nice!)
  • Perspective: Allows for workspaces that when switched to, return the buffers to their original state. Also focuses down the ido buffer to the open buffers in that workspace (Nice!)
  • persp-projectile: Combines Projectile and Perspective so that switching projects gives you the Perspective buffer change behaviour (Much nicer than Projectile’s insistence that you want to always open a new file but also keep old buffers hanging around).

NOTE: Projectile state is not saved in desktop-save. NOTE: Perspective mode with IDO only show’s files in project, so have to use ibuffer to get full list.

(use-package projectile
  :disabled
  ;; :ensure t
  ;; :defer t
  :bind ("C-c p" . 'projectile-command-map)
  :init
  (progn
    (projectile-mode)
    (recentf-mode)  ; enables projectile-recentf mode for recent files.
    ; https://github.com/bbatsov/projectile/issues/1183
    ; Projectile now scrapes all files to discover project type for modeline.
    ; This is calculated on every cursor movement, so lags emacs like crazy.
    ; Below is the workaround to disable this until it is fixed.
    (setq projectile-mode-line
         '(:eval (format " Projectile[%s]"
                        (projectile-project-name))))
    )
  )

Server:

(use-package server
  :ensure t
  :after (exec-path-from-shell)
  :config
  ;; https://wiki.archlinux.org/title/Emacs#Multiplexing_emacs_and_emacsclient
  (unless (server-running-p)
    (server-start))
  )

Environment Variables:

See: Github: purcell/exec-path-from-shell & Yi Tang: Managing Emacs Server as Systemd Service for notes on using the environment variables:

Environment Variables

The customised shell configuration in .bashrc are loaded when opening an interactive shell session. So the Emacs server managed by systemd would not have the environment variables, alias, functions or whatever defined in .bashrc.

This stackoverflow post provides the rationale and how to tweak the unit file so systemd would load .bashrc.

This problem can solved a lot easier on the Emacs side, by using exec-path-from-shell package. It will ensure the environment variables inside Emacs are the same as in the user’s interactive shell.

Simply put the following in your .emacs would do the trick.

(exec-path-from-shell-initialize)

(use-package exec-path-from-shell
  :ensure t
  :config
  (exec-path-from-shell-initialize)
  )

Spell Checking:

dictionary:

Lookup dictionary definitions.

See: https://emacsredux.com/blog/2023/04/11/looking-up-words-in-a-dictionary/, for details as well as installing the dictionary service as an alternative to: dict.org.

  • M-x dictionary-search look up word definition.
  • M-x dictionary-lookup-definition to do a lookup at point.
(use-package dictionary
  :ensure t
  :defer t
  :config (setq dictionary-server "dict.org")
  )

flyspell:

See: EmacsWiki: FlySpell Performance about disabling flyspell-issue-message-flag to greatly speed up flyspell-buffer.

(use-package flyspell
  :ensure t
  :hook (
         (prog-mode . flyspell-prog-mode)
         (text-mode . flyspell-mode)
         )
  :config (setq flyspell-issue-message-flag nil)
  )

Highlight all spelling mistakes in a buffer in one go.

M-x flyspell-buffer

ispell (via aspell):

ispell is the built in spell checker, but aspell is better (multiple dictionaries). See: http://www.emacswiki.org/emacs/InteractiveSpell#toc6

(use-package ispell
  :ensure-system-package (aspell)
  :custom
  (ispell-list-command "list")
  (ispell-personal-dictionary "~/org/ispell_personal_dict")
  (ispell-program-name "aspell")
  (ispell-silently-savep t)  ;; No confirmation on saving to personal dictionary.
  )

Add word to personal dictionary:

Either:

  • M-$ i.
  • C-c $ and then click Save word in GUI drop-down.

Set local ispell dictionary to Welsh in Welsh files.

Steps:

  • Pull welsh dictionary from; https://ftp.gnu.org/gnu/aspell/dict/cy/.
  • Un-tar, build and install dictionary: ./configure && make && sudo make install.
  • Set file local variable to set the Welsh dictionary: M-x add-file-local-variable <ret>ispell-local-dictionary<ret>"cy"<ret>.
  • Revert buffer and verify spellings: M-x flyspell-buffer.

tab-bar:

The tab-bar package creates tabs like a browser. Each tab can maintain it’s layout. Seems to hook into desktop-save to restore on restarts.

 (use-package tab-bar
	:ensure t
	:defer t
	:after (hydra)
	:bind ("C-x t" . 'hydra-tab-bar/body)
	:config
	;; https://github.com/abo-abo/hydra/wiki/Emacs-27-tab-bar-mode
	;; https://github.com/abo-abo/hydra/wiki/Binding-Styles
	(defhydra hydra-tab-bar (:color amaranth)
			  "Tab Bar Operations"
			  ("t" tab-new "Create a new tab" :column "Creation")
			  ("c" tab-new "Create a new tab")
			  ("d" dired-other-tab "Open Dired in another tab")
			  ("f" find-file-other-tab "Find file in another tab")
			  ("0" tab-close "Close current tab")
			  ("k" tab-close "Close current tab")
			  ("m" tab-move "Move current tab" :column "Management")
			  ("r" tab-rename "Rename Tab")
			  ("n" tab-bar-select-tab-by-name "Select tab by name" :column "Navigation")
			  ("s" tab-bar-select-tab-by-name "Select tab by name")
			  ("j" tab-previous "Previous Tab")
			  ("l" tab-next "Next Tab")
			  (";" tab-next "Next Tab")
			  ("q" nil "Exit" :exit t)
			  )
	)

Treesit:

Treesit uses the tree-sitter grammars to provide faces/fontifying/structures to text by an AST instead of a regex (ie. fast, accurate, works during editing).

Automatically install tree-sitter grammars.

(use-package treesit-auto
  :ensure t
  :demand t
  :config
  (setq
   treesit-auto-install t
   )
  (global-treesit-auto-mode)
  )

Various Tweaks:

(global-auto-revert-mode t)
(put 'downcase-region 'disabled nil)  ; allow downcase-region without the disabled feature warning.
(put 'upcase-region 'disabled nil)  ; allow upcase-region without the disabled feature warning.
(setq calendar-week-start-day 1)
(menu-bar-mode -1)  ;; Disable Menu Bar
(tool-bar-mode -1)  ;; Disable tool Bar
(fset 'yes-or-no-p 'y-or-n-p)  ;; yes/no -> y/n
(load-theme 'wombat t)
; (display-time)  ;; Time in modeline. Un-comment to enable.
(display-battery-mode t)  ;; Battery in modeline. Un-comment to enable.
(setq large-file-warning-threshold (* 40 1024 1024))  ;; large files shouting from 40MB's

;; http://pragmaticemacs.com/emacs/dired-human-readable-sizes-and-sort-by-size/
(setq dired-listing-switches "-alh")

Builtin method of moving between windows with (default) Shift+<arrow>. See: PragmaticEmacs: Whizz between windows with windmove.

(use-package windmove
  :ensure t
  :config (windmove-default-keybindings)
  )

Custom Functions:

go to column:

(defun go-to-column (column)
  "GoTo column.
Was getting annoyed seeing errors that point to a COLUMN number;
so grabbed this code:
- http://emacsredux.com/blog/2013/07/09/go-to-column/"
  (interactive "nColumn: ")
  (move-to-column column t))
(global-set-key (kbd "M-g M-c") 'go-to-column)

prog-mode defaults:

(defun my-programming-defaults-config ()
  "All of my programming defaults  in one place."
  (interactive)
  (whitespace-mode)  ;; highlights whitespace.
  (my_highlighted_words)  ;; highlights specific words in red & bold.
  (display-fill-column-indicator-mode)  ;; adds fill column indicator.
  ;; (auto-fill-mode nil)  ;; disables auto fill at column.
  (setq indent-tabs-mode nil)  ;; spaces instead of tabs
  (setq tab-width 4)  ;; 4 spaces per tab key press.

  ;; TODO: raise a bug on which-function-mode breaking in python when opening a
  ;; triple double-qoute (`"""`) docstring in a function and then emacs
  ;; freezes. Replicated on work files with: `emacs -q`, but failed to
  ;; replicate so far on a quickly mocked up file in /tmp/.
  ;;
  ;; (which-function-mode)  ;; Display current function in mode line. (http://emacsredux.com/blog/2014/04/05/which-function-mode/)
  (my_highlighted_words)  ;; highlight specific words
  (show-paren-mode 1)  ;; highlight matching brackets
  (setq tags-revert-without-query t)
  )
(add-hook 'prog-mode-hook 'my-programming-defaults-config)
;; Don't line-wrap in html files.
;; https://stackoverflow.com/questions/9294437/emacs-disable-wordwrapping-in-html-mode
(add-hook 'html-mode-hook (lambda () (auto-fill-mode -1)))

revert all buffers:

(defun revert-all-buffers ()
  "Refreshes all open buffers from their respective files."
  (interactive)
  (dolist (buf (buffer-list))
    (with-current-buffer buf
      (when (and (buffer-file-name) (file-exists-p (buffer-file-name)) (not (buffer-modified-p)))
        (revert-buffer t t t) )))
  (message "Refreshed open files.") )

scratch-mode defaults:

(defun my-scratch-mode-config ()
  "Disabling config for *scratch* buffer."
  (interactive)
  (display-fill-column-indicator-mode -1)
  (auto-fill-mode -1)
  )
(add-hook 'lisp-interaction-mode-hook 'my-scratch-mode-config)

show non-ascii in occur buffer:

Here’s a simple defun to show non-ascii characters of current buffer in an Occur buffer http://www.emacswiki.org/emacs/FindingNonAsciiCharacters

(defun occur-non-ascii ()
  "Find any non-ascii characters in the current buffer."
  (interactive)
  (occur "[^[:ascii:]]"))

text-mode defaults:

(defun my-text-mode-config ()
  "All of my `text-mode` config in one place."
  (interactive)
  (whitespace-mode)  ;; highlights whitespace.
  (my_highlighted_words)  ;; highlights specific words in red & bold.
  (display-fill-column-indicator-mode)  ;; adds fill column indicator.
  (auto-fill-mode)  ;; wraps at auto fill column.
  (my_highlighted_words)  ;; highlight specific words
  (setq indent-tabs-mode nil)  ;; spaces instead of tabs
  )

(add-hook 'text-mode-hook 'my-text-mode-config)  ;; singular text-mode-hook
(add-hook 'conf-mode-hook 'my-text-mode-config)  ;; *.conf
(defun comment-or-uncomment-region-or-line ()
  "Un/Comments the region or the current line if there's no active region."
  (interactive)
  (let (beg end)
    (if (region-active-p)
        (setq beg (region-beginning) end (region-end))
      (setq beg (line-beginning-position) end (line-end-position)))
    (comment-or-uncomment-region beg end)))
(global-set-key (kbd "C-c '") 'comment-or-uncomment-region-or-line)

Buffer/Window Management:

Fill Column Indicator

Fill Column is used to reflow text automatically & highlight margins, as well as show a hard column line. See: Emacs Wiki: FillColumnIndicator. I changed the column fill to be a double pipe. See unicode table.

(use-package fill-column-indicator
  :ensure t
  :defer t
  :config
  (progn
    (setq-default fci-rule-column 79)
    (setq fci-rule-character ?\u2016)
    ;; automatically wrap to 79 characters.
    (setq-default fill-column 79)
    (setq-default git-commit-fill-column 79))
)

Useful package when paired with a presentation mode like: [[*\[\[https://github.com/takaxp/org-tree-slide\]\[org-tree-slide\]\]:][org-tree-slide]], give a fullscreen (distraction-free) presentation. See: YouTube: Emacs Tips - How to Give Presentations with Org Mode (Questions).

(use-package hide-mode-line :ensure t)

NOTE: Seeing LSP and other packages blowing up on this missing requirement.

(use-package treemacs
  :ensure t
  :defer t
  :custom
  (treemacs-project-follow-mode t)
  )

visual-fill-column:

Centre buffers, example for presentations

(use-package visual-fill-column
  :ensure t
  :custom
  (visual-fill-column-width 110)
  (visual-fill-column-center-text t)
  )

Notifications:

(use-package alert
  ;; TODO: Check if Mac can work with libnotify. It works on Linux.
  ;; Still not working + libnotify keeps being reinstalled by brew due to
  ;; different name.
  ;; :ensure-system-package (libnotify)
  :ensure t
  :commands (alert)
  :init
  (if (eq system-type 'darwin)
      (setq alert-default-style 'terminal-notifier)
    (setq alerqt-default-style 'libnotify)
    )
  (setq
   alert-fade-time 15
   )
  )

Notifications from scheduled items in the Org Agenda. Builds off: [[*\[\[https://github.com/jwiegley/alert\]\[alert\]\]:][alert]].

NOTE: On Mac’s I am using an Alert notification for terminal-notifier, so that notifications have to be explicitly closed.

(use-package org-alert
  ;; https://github.com/julienXX/terminal-notifier/issues/292 -  No Notification in macOS12.1 #292
  ;; https://github.com/julienXX/terminal-notifier
  ;; TODO: Check if Mac can work with libnotify. It works on Linux.
  ;; :ensure-system-package terminal-notifier
  :ensure t
  ;; :disabled t  ;; Why is this blowing up??
  :after (org)
  :config
  (setq
   alert-default-style 'libnotify
   org-alert-notify-cutoff 5
   org-alert-notify-after-event-cutoff 1
   )
  (org-alert-enable)
  )

Custom popup notifications (DEPRECATE!):

Very old way of doing custom notification pop-ups:

;; TODO: figure out why the built in `notifications` package doesn't play
;; sounds:
(defun djcb-popup (title msg &optional timeout icon sound)
  "Show a popup if we're on X, or echo it otherwise;
TITLE is the title of the message, MSG is the context.
Optionally, you can provide a TIMEOUT (milliseconds, default=5000) an ICON and
a SOUND to be played (default=/../alert.wav)"
  (interactive)
  (shell-command
   (concat "mplayer -really-quiet "
           (if sound sound "/usr/share/sounds/purple/alert.wav")
           " 2> /dev/null"))
  ;; Removed `(if (eq window-system 'x))` check since it wasn't doing the
  ;; notify-send on my terminal emacs session nested in tmux in a terminal
  ;; under cinnamon.
  (shell-command (concat "notify-send"
                         (if icon (concat " -i " icon) "")
                         (if timeout (concat " -t " timeout) " -t 5000")
                         " '" title "' '" msg "'"))
  ;; text only version
  (message (concat title ": " msg)))

Run example:

(djcb-popup "Warning" "The end is near"
            nil
            "/usr/share/icons/gnome/128x128/apps/libreoffice-base.png"
            "/usr/share/sounds/purple/alert.wav")

Version Control:

VC config (VC is built in version control package. Magit is an enhanced git VC package).

Follow symlinks:

(setq vc-follow-symlinks t)

magit - a pretty good git package with more features than the built in emacs “vc” package.

(use-package magit
  :ensure t
  :bind (
     ("<f3>" . magit-status)
     ("\C-ct" . magit-status)  ;; Alternative when on a touchbar Mac.
     ("\C-c\C-s" . magit-status)  ;; Overridden by =org-schedule=.
     ("\C-cg" . vc-git-grep)
     ("\C-cb" . magit-blame))
  :config
  (setq magit-auto-revert-mode t)
  ;; `M-x magit-describe-section-briefly`, then check the square brackets in:
  ;; `<magit-section ... [<section_name> status] ...>`.
  (setq
   magit-section-initial-visibility-alist
   '(
     (stashes . hide)
     (unpulled . show)
     (unpushed . show)
     (pullreqs . show)
     ))
  )

magit-svn (legacy):

Used this years ago when SVN and git-svn where part of my daily work routine. Haven’t needed to touch SVN in years, but keeping here for legacy reasons.

(use-package magit-svn
  :ensure t
  :defer t
  :after (magit)
  )

magit-popup (legacy):

magit/magit#3749 magit moved to using transient but some packages (magithub - vermiculus/magithub#402) haven’t updated, hence explicit definition of magit-popup

(use-package magit-popup
   :ensure t
   :after (magit)
   )

Builds on top of Magit to interact with VCS’s so that you can create/edit Issues/PR’s.

Replacement for magithub, which works with Gitlab/Github. See old commits for my old magithub config.

(use-package forge
  ;; https://www.reddit.com/r/emacs/comments/fe165f/pinentry_problems_in_osx/
  ;; to fix GPG timeouts due to no password provided/asked.
  ;; NOTE: for emacsclients, it asks in the main instance window.
  :if (not (eq system-type 'windows-nt))  ;; FIXME: Needs `cc` compiler defined.
  :ensure t
  :after (magit)
  :config
  (add-to-list 'forge-alist '("git-scm.clinithink.com:2009" "git-scm.clinithink.com/api/v4" "git-scm.clinithink.com" forge-gitlab-repository))
  (add-to-list 'forge-alist '("bitbucket.eigen.live" "bitbucket.eigen.live/rest/api/1.0" "bitbucket.eigen.live" forge-bitbucket-repository))
  (add-to-list 'forge-alist '("gitlab.eigen.live" "gitlab.eigen.live/api/v4" "gitlab.eigen.live" forge-gitlab-repository))
  )

Code Review is a package that builds on top of Magit, but supports interacting with PR’s to do code reviews (comments, diff view, approvals, etc).

  • M-x code-review-forge-pr-at-point on forge PR line.
  • r for transient menu in a code-review buffer.
(use-package code-review
  :ensure t
  :defer t
  :after (magit)
  :config
  (setq
   code-review-bitbucket-host "bitbucket.eigen.live/rest/api/1.0"
   code-review-gitlab-host "gitlab.eigen.live/api"
   code-review-gitlab-graphql-host "gitlab.eigen.live/api"
   ;; Dump requests into the logs for debugging. eg.
   ;; https://github.com/wandersoncferreira/code-review/issues/195.
   ;;
   ;; code-review-log-raw-request-responses t
   )
  )

A GNU Emacs major mode for keeping notes, authoring documents, computational notebooks, literate programming, maintaining to-do lists, planning projects, and more — in a fast and effective plain text system.

NOTE: Broken apart org mode config via: Github: jwiegley/use-package/issues/662 - Calling use-package multiple times on the same package #662.

calfw (Calendar):

See: http://cestlaz.github.io/posts/using-emacs-26-gcal/

(use-package calfw
  :ensure t
  :defer t
  :after (org)
  :bind
  (
   ("<f8>" . cfw:open-org-calendar)
   )
  :config
  (progn
    (use-package calfw-gcal
      ;; FIXME: 10year old package with deprecated `cl` requirement.
      ;; TODO: replace for: https://github.com/myuhe/org-gcal.el.
      :ensure t
  :defer t)

    (use-package calfw-ical
      :ensure t
  :defer t)

    (use-package calfw-org
      :ensure t
  :defer t)
    )
  ;; FIXME: what does this do??
  (setq cfw:org-overwrite-default-keybinding t)
  )

Core org-mode config:

(use-package org
  ;; NOTE: ~ox-confluence~ from ~org-contrib~ never worked well, compared to
  ;; the exports listed in: ~config.org~. Disabling for now.
  ;; https://emacs.stackexchange.com/questions/7890/org-plus-contrib-and-org-with-require-or-use-package
  ;; https://emacs.stackexchange.com/questions/70081/how-to-deal-with-this-message-important-please-install-org-from-gnu-elpa-as-o
  ;; :ensure org-contrib
  :ensure t
  :bind (
     ("C-c l" . org-store-link)
     ("C-c a" . org-agenda)
     ("C-c c" . org-capture))
  :init
  (progn
    (setq
     org-directory "~/org/"
     ;; org-agenda-files (list "~/org/" "~/org/personal/" "~/org/programming_notes/")
     org-agenda-files (apply 'append
                             (mapcar
                              (lambda (directory)
                                (directory-files-recursively
                                 directory org-agenda-file-regexp))
                              '("~/org/")))
     org-default-notes-file "~/org/notes.org"
     ;; refile level.
     ;; http://www.millingtons.eclipse.co.uk/glyn/dotemacs.html
     org-refile-targets (quote
                         ((org-agenda-files :maxlevel . 5)
                          ("~/org/personal/projects.org" :maxlevel . 2)
                          ("~/org/programming_notes/notes.org" :maxlevel . 5)))
     ;; Allow refiling to a file to support moving up to heading level 1
     org-refile-use-outline-path 'file
     ;; FIXME: Something has changed to the point where I can no longer refile
     ;; to headings in a file after the file selection part. Changing the
     ;; outline path option below allows me to do it, but it is super laggy
     ;; from all of the headings it is fuzzy searching through.
     ;;
     ;; I may have to give up on refiling to the top heading in a file with the
     ;; ~org-refile-use-outline-path 'file~ change above.
     org-outline-path-complete-in-steps nil
     org-log-done t
     ;; https://kundeveloper.com/blog/org-capture-3/ for `org-capture-templates` ideas.
     org-capture-templates '(
                             ("t" "Todo" entry (file+headline "~/org/todo.org" "UNSORTED")
                              "* TODO %?  %^G\n %U - %i\n  %a")
                             ("p" "Projects" entry (file+headline "~/org/personal/projects.org" "UNSORTED")
                              "* TODO %?\n %U - %i\n  %a")
                             ("b" "Buy" entry (file+headline "~/org/personal/buy.org" "UNSORTED")
                              "* TODO %?\n %U - %i\n  %a")
                             ("i" "Inbox - Dumping ground" entry (file "~/org/inbox.org") "* %?\n")
                             ("n" "Notes" entry (file+headline "~/org/programming_notes/notes.org" "UNSORTED")
                              "* TODO %?\n %U - %i\n  %a")
                             ("y" "YouTube: Watch List.\n\t\t*Link is pulled from X Clipboard!!*\n\t\t*NOTE:* if this is a Playlist;\n\t\t- manually delete ~v=<id>&~.\n\t\t- keep: ~list=<id>~!" entry (file+headline "~/org/personal/personal_todos.org" "YouTube Watch list:")
                              "* [[shell:mpv %x &][YouTube: %?]]  :WATCH:")
                             )
     )

    (global-set-key "\C-cr" (lambda () (interactive) (org-capture nil "t")))
    (global-set-key "\C-cn" (lambda () (interactive) (org-capture nil "n")))
    )
  :config
  ;; ;; Explicit requires from the `org-contrib` package.
  ;; (require 'ox-confluence)  ;; FIXME: wrong type arguments error!
  (setq
   org-link-file-path-type 'relative
   org-use-tag-inheritance nil  ;; Don't show un-tagged sub-headings when there is a tag on a high-level.
   )
)

Capture/Reminders:

macros:

  • Convert markdown links ([display_message](link)) to org links ([[link][display_message]]):
    (fset 'convert-markdown-link-to-org-link
     "\C-[xreplace-regexp\C-m\\[\\(.*\\)\\](\\(.*\\))\C-m[[\\2][\\1]]\C-m")
        

export:

Suggested Export Options at top of file: #+OPTIONS: \n:nil toc:nil num:nil. Or: #+OPTIONS: \n:nil toc:nil num:nil html-postamble:nil to remove the footer as well.

  • No line wrapping.
  • No TOC.
  • Don’t number headings.

Export org to Confluence:

Been trying different ways to export org files to then dump into Confluence. Current rating of exporters:

  1. Export to HTML.
    • Highlight region.
    • M-x org-html-export-as-html, cursor jumps to export buffer.
    • M-x browse-url-of-buffer, to open in your browser.
    • Select all in Browser tab and paste into Confluence edit mode.
  2. Export to ASCII.
    • M-x org-ascii-export-as-ascii.
    • Requires below config changes.
    • Issues around Headings being picked up by Confluence (eg. h3 == h2, no h3+).
    • Issues around Formatting being picked up by Confluence (eg. No Bold markup).
  3. Export to Markdown.
    • M-x org-md-export-as-markdown.
    • Great rendering in a /markdown macro, but other macros cannot be nested inside or work with the /markdown macro. eg. No /toc macro.
    • Pretty good rendering pasting into Confluence edit area, but no auto wrapping. ie. 80 characters.
  4. BROKEN: M-x ox-confluence from org-contrib throws errors on emacs29.

Confluence ascii export config:

Better ASCII export output from org files when the target is an Atlassian Confluence Wiki. Export via: M-x org-ascii-export-as-ascii (C-cC-etA).

TODO: figure out what Heading underlining style Confluence uses for H3-H5!!

(setq org-ascii-text-width 10000)  ;; Large text width to avoid line wrapping.
(setq org-ascii-inner-margin 0)  ;; Don't indent lines between headings.
;; Confluence expects H2 to be ~-~.
(setq org-ascii-underline '((ascii 61 45 45)
                            (latin1 61 126 45)
                            (utf-8 9552 9472 9548 9476 9480)))

Github blog: Fix exported links:

(defun org-custom-link-img-follow (path)
  "PATH to find custom linked images."
  (org-open-file-with-emacs
   (format "~/org/github_blog/images/%s" path)))

(defun org-custom-link-img-export (path desc format)
  "Rewrite custom linked images for export.
PATH - path to images.
DESC - Description to add as alt text..
FORMAT - .format to use."
  (cond
   ((eq format 'html)
    (format "<img src=\"http://jackson15j.github.io/%s\" alt=\"%s\"/>" path desc))))

(require 'org)
;; FIXME: `org-add-link-type` is deprecated. Replace with:
;; `org-link-set-parameters`.
(org-add-link-type "img" 'org-custom-link-img-follow 'org-custom-link-img-export)

load additional (optional) literate configs:

(let () (dolist (dot_emacs '("~/org/config.org"
                             ))
          "Loading my extra emacs dot files if they exist."
          (when (file-exists-p dot_emacs)
            (message (concat "Loading external literate config: " dot_emacs))
            (org-babel-load-file dot_emacs))))

Add: :async to an org-babel code block to run async when called with: C-cC-c.

FIXME: Comment out `ob-async`. It’s throwing errors on post-install restart!

org-agenda:

Custom Agenda views:

(use-package org
  :config
  (setq
   org-agenda-custom-commands '(
                                ;; Keep tags but hide `DONE` tasks: https://orgmode.org/manual/Matching-tags-and-properties.html
                                ("r" "Agenda Review"
                                 (
                                  (agenda "")
                                  (tags "ACTION" ((org-agenda-overriding-header "\nItems I need to action!! ~:ACTION:~")))
                                  (tags "CHASE" ((org-agenda-overriding-header "\nChase down these people!! ~:CHASE:~")))
                                  (tags "INVESTIGATE|INVESTIGATION" ((org-agenda-overriding-header "\nInvestigation tasks!! ~:INVESTIGATE:INVESTIGATION:~")))
                                  (tags "REVIEW|WIKI" ((org-agenda-overriding-header "\nDump this into Confluence!! ~:REVIEW:WIKI:~")))
                                  (tags "READ|WATCH" ((org-agenda-overriding-header "Books/Links I need to read/WATCH!! ~:READ:WATCH:~")))
                                  (tags "TRAINING" ((org-agenda-overriding-header "Current/Future training tasks ~:TRAINING:~")))
                                  (tags "ADMIN" ((org-agenda-overriding-header "Admin tasks ~:ADMIN:~")))
                                  (tags-todo "-ACTION-ADMIN-CHASE-READ-REVIEW-TRAINING-WATCH-WIKI" ((org-agenda-overriding-header "\nGeneral TODO's")))
                                  )
                                 nil  ;; settings
                                 ("/tmp/org_agenda_review.html" "/tmp/org_agenda_review.ics" "/tmp/org_agenda_review.txt")  ;; ~org-store-agenda-views~ output file
                                 )
                                ;; https://fortelabs.com/blog/para/
                                ("p" "PARA Personal (Project Area Resources Archive) Agenda Review"
                                 (
                                  (agenda "" ((org-agenda-files (list "~/org/" "~/org/personal/" "~/org/programming_notes/"))))
                                  (tags "ACTION|CHASE|INVESTIGATE|INVESTIGATION|TRAVEL" ((org-agenda-overriding-header "\nProject: \"a series of tasks linked to a goal, with a deadline.\"  ~:ACTION:CHASE:INVESTIGATE:INVESTIGATION:~") (org-agenda-files (list "~/org/" "~/org/personal/" "~/org/programming_notes/"))))
                                  (tags-todo "-ACTION-ADMIN-CHASE-EMACS-PERSONAL-READ-REVIEW-TRAINING-TRAVEL-WATCH-WIKI-WORKFLOW-STYLE=\"habit\"-SCHEDULED>=\"<now>\"-DEADLINE>=\"<now>\"" ((org-agenda-overriding-header "Project: (Tag to remove non-urgent TODO's out of this list!!)") (org-agenda-files (list "~/org/" "~/org/personal/" "~/org/programming_notes/"))))
                                  (tags "ADMIN|REVIEW|WIKI|WORKFLOW-STYLE=\"habit\"" ((org-agenda-overriding-header "\nAreas: \"a sphere of activity with a standard to be maintained over time.\"  ~:ADMIN:REVIEW:WIKI:WORKFLOW:~") (org-agenda-files (list "~/org/" "~/org/personal/" "~/org/programming_notes/"))))
                                  (tags "EMACS|PERSONAL-STYLE=\"habit\"|READ|TRAINING-STYLE=\"habit\"|WATCH|UNSORTED" ((org-agenda-overriding-header "\nResource: \"a topic or theme of ongoing interest.\"  ~:EMACS:PERSONAL:READ:TRAINING:WATCH:UNSORTED:~") (org-agenda-files (list "~/org/" "~/org/personal/" "~/org/programming_notes/"))))
                                  )
                                 nil  ;; settings
                                 ;; See: https://orgmode.org/manual/Exporting-Agenda-Views.html
                                 ;; ~M-x org-store-agenda-views~ outputs all files for all views.
                                 ;; Script export: ~emacs --batch -l ~/.emacs --eval '(org-store-agenda-views)'~
                                 ("/tmp/org_agenda_para.html" "/tmp/org_agenda_para.ics" "/tmp/org_agenda_para.txt")
                                 )
                                ("w" "PARA Work (Project Area Resources Archive) Agenda Review"
                                 (
                                  (agenda "" ((org-agenda-files (directory-files-recursively "~/org/work/" org-agenda-file-regexp))))
                                  (tags "ACTION|CHASE|INVESTIGATE|INVESTIGATION|TRAVEL" ((org-agenda-overriding-header "\nProject: \"a series of tasks linked to a goal, with a deadline.\"  ~:ACTION:CHASE:INVESTIGATE:INVESTIGATION:~") (org-agenda-files (directory-files-recursively "~/org/work/" org-agenda-file-regexp))))
                                  (tags-todo "-ACTION-ADMIN-CHASE-EMACS-PERSONAL-READ-REVIEW-TRAINING-TRAVEL-WATCH-WIKI-WORKFLOW" ((org-agenda-overriding-header "Project: (Tag to remove non-urgent TODO's out of this list!!)") (org-agenda-files (directory-files-recursively "~/org/work/" org-agenda-file-regexp))))
                                  (tags "ADMIN|REVIEW|WIKI|WORKFLOW" ((org-agenda-overriding-header "\nAreas: \"a sphere of activity with a standard to be maintained over time.\"  ~:ADMIN:REVIEW:WIKI:WORKFLOW:~") (org-agenda-files (directory-files-recursively "~/org/work/" org-agenda-file-regexp))))
                                  (tags "READ|TRAINING|WATCH|UNSORTED" ((org-agenda-overriding-header "\nResource: \"a topic or theme of ongoing interest.\"  ~:READ:TRAINING:WATCH:UNSORTED:~") (org-agenda-files (directory-files-recursively "~/org/work/" org-agenda-file-regexp))))
                                  )
                                 nil  ;; settings
                                 ;; See: https://orgmode.org/manual/Exporting-Agenda-Views.html
                                 ;; ~M-x org-store-agenda-views~ outputs all files for all views.
                                 ;; Script export: ~emacs --batch -l ~/.emacs --eval '(org-store-agenda-views)'~
                                 ("/tmp/org_agenda_para.html" "/tmp/org_agenda_para.ics" "/tmp/org_agenda_para.txt")
                                 )
                                ("d" "Agenda for Today (Compact view for Exporting to displays)"
                                 (
                                  (agenda)
                                  (tags "ACTION|CHASE|INVESTIGATE|INVESTIGATION|TRAVEL" ((org-agenda-overriding-header "Project: \"a series of tasks linked to a goal, with a deadline.\"  ~:ACTION:CHASE:INVESTIGATE:INVESTIGATION:~")))
                                  )
                                 (
                                  (org-agenda-span 1)
                                  (org-agenda-use-time-grid nil)
                                  )
                                 ("/tmp/org_agenda_today.html" "/tmp/org_agenda_today.ics" "/tmp/org_agenda_today.txt")
                                 )
                                ("i" "Personal agenda for last 2 weeks"
                                 (
                                  (agenda "")
                                  )
                                 (
                                  (org-agenda-span 15)
                                  (org-agenda-start-day "-14d")
                                  (org-agenda-skip-function-global nil)
                                  )
                                 )
                                ("y" "Personal agenda for month"
                                 (
                                  (agenda "")
                                  )
                                 (
                                  (org-agenda-span 'month)
                                  (org-agenda-skip-function-global nil)
                                  )
                                 )
                                ("o" "Work agenda for last 2 weeks (1-2-1 Reviews)"
                                 (
                                  (agenda "" ((org-agenda-files (directory-files-recursively "~/org/work/" org-agenda-file-regexp))))
                                  )
                                 (
                                  (org-agenda-span 15)
                                  (org-agenda-start-day "-14d")
                                  (org-agenda-skip-function-global nil)
                                  )
                                 )
                                ("u" "Work Month view"
                                 (
                                  (agenda "" ((org-agenda-files (directory-files-recursively "~/org/work/" org-agenda-file-regexp))))
                                  )
                                 (
                                  (org-agenda-span 'month)
                                  (org-agenda-skip-function-global nil)
                                  )
                                 )
                                )
   org-src-fontify-natively t
   org-overriding-columns-format "%CATEGORY %80ITEM %TODO %TAGS %5Effort(Est){:} %CLOCKSUM{:}"  ;; C-cC-xC-c in an Agenda view.
   org-agenda-compact-blocks t  ;; Compact agenda. Same as setting: `org-agenda-block-separator nil`.
   org-agenda-tags-column 100  ;; Stop tags rendering off the right of the buffer.
   org-agenda-skip-function-global '(org-agenda-skip-entry-if 'todo 'done)  ;; Hide `DONE` lines from Agenda view.
   )
  )

Repeated tasks / org#Tracking your habits:

  • Enable org-habit in agenda view: org#Tracking your habits.
  • Tag repeated tasks with a deadline (C-cC-d).
  • Add the repeat [and reminder] value.
  • Mark as done with C-cC-t, which will log that DOEN and update the deadline to the next future point.

Repeat:

  • every fortnight: put +2w into deadline/schedule datetime.
  • daily, but next iteration is after today, if marking as ~”DONE”~ after missing several days: put .+1d into deadline/schedule datetime.

See: Sachachua: Org-mode and habits.

(use-package org
  :custom
  (org-habit-graph-column 60)  ;; 40
  (org-habit-preceding-days 30)  ;; 21
  (org-habit-show-all-today t)
  :config
  (add-to-list 'org-modules 'org-habit)
  )

Eval Org-modules. See: Sachachua: dotemacs#modules:

(eval-after-load 'org
  '(org-load-modules-maybe t))

org-babel:

org-babel config:

(use-package ob-core
  :custom
  (
   (org-confirm-babel-evaluate . nil)
   )
  )

Initial babel core languages list:

Items like shell language supports multiple shells, but using those shells does not work since the core is ob-shell not ob-<sh|bash|dash|fish|zsh>.

;; active Babel languages
(org-babel-do-load-languages
 'org-babel-load-languages
 '(
   (awk . t)
   (C . t)
   (css . t)
   (dot . t)
   (emacs-lisp . t)
   (gnuplot . t)
   (makefile . t)
   (plantuml . t)
   (python . t)
   (shell . t)
   (sql . t)
   (sqlite . t)
   )
 )

Also see:

Redirect stderr to :results block:

See: StackOverflow: Org Bable Redirect stderr (-c option requires an argument).

Either:

  • Redirect all output at the file level:
    #+PROPERTY: header-args:shell :prologue "exec 2>&1" :epilogue ":" :results drawer
        
  • Redirect all output at the Heading level:
    :PROPERTIES:
    :header-args:shell: :prologue "exec 2>&1" :epilogue ":" :results drawer
    :END:
        

NOTE: C-cC-c on the Property block to refresh for the file.

org-jira:

;; (make-directory "~/org/jira/" t)
;; (use-package org-jira
;;   :ensure t
;;   :defer t
;;   :config
;;   (setq
;;    jiralib-url "https://eigentech.atlassian.net/"
;;    org-jira-working-dir "~/org/jira/"
;;    )
;;   )
;; This is an Emacs package that creates graphviz directed graphs from
;; the headings of an org file
;; https://github.com/theodorewiles/org-mind-map
(use-package org-mind-map
  ;; Switch to a fork due to org-mind-map waiting to be moved to new maintainers.
  :vc (:url "https://github.com/lockywolf/org-mind-map.git"
       :rev :newest)
  :init
  (require 'ox-org)
  :ensure t
  :ensure-system-package (gvgen . graphviz)
  :config
  (setq org-mind-map-default-graph-attribs
        '(("autosize" . "false")
          ("size" . "9,12")
          ("resolution" . "200")
          ("nodesep" . "0.75")
          ("overlap" . "false")
          ("spline" . "true")
          ("rankdir" . "LR")))
  ;; (setq org-mind-map-engine "dot")       ; Default. Directed Graph
  ;; (setq org-mind-map-engine "neato")  ; Undirected Spring Graph
  ;; (setq org-mind-map-engine "twopi")  ; Radial Layout
  ;; (setq org-mind-map-engine "fdp")    ; Undirected Spring Force-Directed
  (setq org-mind-map-engine "sfdp")   ; Multiscale version of fdp for the layout of large graphs
  ;; (setq org-mind-map-engine "circo")  ; Circular Layout
  )

Modern Org Presentation solution.

Base config stolen from: Github: jypma/emacsconf2021/blob/master/presentation.org.

(defun my/presentation-setup ()
  (shell-command "dunstctl set-paused true")
  (turn-off-display-fill-column-indicator-mode)
  (flyspell-mode 0)
  (setq text-scale-mode-amount 3)
  (org-display-inline-images)
  (text-scale-mode 1)
  (hide-mode-line-mode 1)
  (display-line-numbers-mode 0)
  ;; (visual-fill-column-mode 1) ;; doesn't work in org-tree-slide
  (visual-line-mode 1)
  (font-lock-flush)
  (font-lock-ensure))

(defun my/presentation-end ()
  (shell-command "dunstctl set-paused false")
  (turn-on-display-fill-column-indicator-mode)
  (flyspell-mode 1)
  (text-scale-mode 0)
  (hide-mode-line-mode 0)
  (display-line-numbers-mode 1)
  (org-remove-inline-images)
  ;; (visual-fill-column-mode 0)
  (visual-line-mode 0)
  (font-lock-flush)
  (font-lock-ensure))

(use-package org-tree-slide
  :ensure t
  ;; Load immediately, since it messes with org-mode faces
  :demand
  :hook
  ((org-tree-slide-play . my/presentation-setup)
   (org-tree-slide-stop . my/presentation-end))
  :bind
  (:map org-mode-map
        ("<f6>" . org-tree-slide-mode))
  (:map org-tree-slide-mode-map
        ("p" . 'org-tree-slide-move-previous-tree)
        ("n" . 'org-tree-slide-move-next-tree)
        )
  :custom
  (org-tree-slide-slide-in-effect nil)
  (org-tree-slide-activate-message "Presentation started.")
  (org-tree-slide-deactivate-message "Presentation ended.")
  (org-tree-slide-header t)
  (org-image-actual-width nil)
  )

todo keywords:

Applying styles to TODO keywords in org files + allow multiple sequences.

See:

  • org#Faces for TODO keywords.
  • org#Multiple sets in one file.
    • C-S-<left>/<right> to jump sub-sequences (Ctrl-Shift-<left>/<right>).
(setq org-todo-keyword-faces
      '(
        ("TODO" . org-warning)
        ("FUTURE" . (:foreground "black" :weight bold :background "DarkOrange1"))
        ("STARTED" . (:foreground "black" :background "gold1"))
        ("INPROGRESS" . (:foreground "white" :background "green4"))
        ("BLOCKED" . (:foreground "white" :weight bold :background "red4"))
        ("CANCELED" . (:foreground "blue" :weight bold :strike-through t))
        ("PARKED" . (:foreground "DarkGrey"))
        )
      )
(setq org-todo-keywords
      '(
        (sequence "TODO" "INPROGRESS" "BLOCKED" "|" "DONE" "CANCELED" "PARKED")
        )
      )

Diagrams:

Modes for drawing diagrams like: Ladder/Sequence, MindMaps, Class/Block/Object, UML diagrams.

mscgen:

.mscgen files are used to create diagrams from plaintext. These days I am using UML/mermaid.

(define-generic-mode
    'mscgen-mode                        ;; name of the mode to create
  '("#")                           ;; comments start with '#'
  '("label" "note" "width"
    "textcolour" "linecolour" "textbgcolour")                     ;; some keywords
  '(("=" . 'font-lock-operator)     ;; '=' is an operator
    ("=>" . 'font-lock-operator)
    ("->" . 'font-lock-operator)
    (";" . 'font-lock-builtin)     ;; ';' is a a built-in
    ("[" . 'font-lock-builtin)
    ("]" . 'font-lock-builtin)
    ("|" . 'font-lock-builtin)
    )
  '("\\.msc$")                      ;; files for which to activate this mode
  nil                         ;; other functions to call
  "A mode for mscgen files"            ;; doc string for this mode
  )
(defun mscgen-compile-buffer-hook()
  "Compile command to generate a PNG from the current mscgen buffer.

See: https://stackoverflow.com/questions/6138029/how-to-add-a-hook-to-only-run-in-a-particular-mode
for the use of the hook."
  (compile (concat "mscgen -T png " buffer-file-name " && mscgen -T svg " buffer-file-name))
  (message (concat "Generated PNG/SVG for: " buffer-file-name))
  )
(add-hook 'mscgen-mode-hook 'my-programming-defaults-config)
(add-hook 'mscgen-mode-hook
          (lambda ()
            (add-hook 'after-save-hook 'mscgen-compile-buffer-hook nil 'make-it-local)))

Mermaid is a new plaintext diagram markup that has native rendering support in Github (See: Github Docs: Creating Diagrams). To render locally, you need to install: =mermaid-cli=. Example that should render natively in Github:

sequenceDiagram
 A-->B: Works!
Loading

Pre-Reqs:

  • Add to top of file and then C-cC-c to both store errors in the RESULT block and to also ignore the puppeteer headless deprecation warning. NOTE: Minor spelling mistake in puppeteer for config #21:
    #+PROPERTY: header-args:mermaid :prologue "exec 2>&1" :epilogue ":" :pupeteer-config-file ~/.puppeteerrc
        
  • Add: {"headless": "new"} to: ~/.puppeteerrc.

brew install mermaid-cli` falls over with: ~Error: mermaid-cli has been disabled because it installs a pre-built copy of Chromium!.

Which is mentioned in the Closed:WontFix issue: update brew formula to work with 9.0.3 #288. Installing via npm globally instead.

(use-package mermaid-mode
  :ensure-system-package (mmdc . "npm install -g @mermaid-js/mermaid-cli")
  :ensure t
  )
(use-package ob-mermaid
  :ensure-system-package (mmdc . "npm install -g @mermaid-js/mermaid-cli")
  :ensure t
  :config
  (add-to-list 'org-babel-load-languages '(mermaid . t))
  (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)
  )

Create architecture/design images with UML.

Here are some good org-babel plantuml examples: Github: dfeich/org-babel-examples/blob/master/plantuml/plantuml-babel.org.

NOTE: On Mac’s brew does not symlink OpenJDK by default, to not break system packages. Run:

sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk
(defun plantuml-compile-buffer-hook()
  "Compile command to generate a PNG from the current plantuml buffer."
  (compile (concat "java -jar ~/org/plantuml.jar " buffer-file-name ";\njava -jar ~/org/plantuml.jar -tsvg " buffer-file-name))
  (message (concat "Generated PNG for: " buffer-file-name))
  )

(use-package plantuml-mode
  ;; https://plantuml.com/emacs
  :ensure-system-package ((dot . graphviz) (java))
  :ensure t
  :after (org org-src)
  ;; FIXME: since my tree-sit change in python to use `python-mode`
  ;; everywhere, it seems to have broken the `.plantuml` look-up in
  ;; `auto-mode-alist`. ie. plantuml files open up with `python-mode` ??
  :mode "\\.plantuml\\'"
  :hook
  (
   (plantuml-mode . my-programming-defaults-config)
   (plantuml-mode . (lambda () (add-hook 'after-save-hook 'plantuml-compile-buffer-hook nil 'make-it-local)))
   )
  :init
  ;; Enable plantuml-mode for PlantUML org code block
  (add-to-list 'org-src-lang-modes '("plantuml" . plantuml))
  :config
  (setq
   ;; Use plantuml server, once: ~(setq plantuml-default-exec-mode 'server)~.
   ;; https://hub.docker.com/r/plantuml/plantuml-server
   ;; docker run -d -p 8099:8080 plantuml/plantuml-server:jetty
   ;; plantuml-server-url "http://localhost:8099"

   ;; See: following issue for inability to use PlantUML server in org-babel:
   ;; https://github.com/skuro/plantuml-mode/issues/165
   org-plantuml-jar-path "~/org/plantuml.jar"
   plantuml-jar-path "~/org/plantuml.jar"
   plantuml-default-exec-mode 'jar
   )
  )

Docker:

(use-package docker
  :ensure t
  :defer t
  :bind ("C-c d" . docker)
  :custom
  (
   ;; https://github.com/Silex/docker.el/issues/188
   ;; Don't use vterm everywhere.
   (docker-run-async-with-buffer-function 'docker-run-async-with-buffer-shell)
   (docker-container-columns '(
                               (:name "Names" :width 40 :template "{{ json .Names }}" :sort nil :format nil)
                               (:name "Status" :width 30 :template "{{ json .Status }}" :sort nil :format nil)
                               (:name "Image" :width 40 :template "{{ json .Image }}" :sort nil :format nil)
                               (:name "Id" :width 12 :template "{{ json .ID }}" :sort nil :format nil)
                               (:name "Ports" :width 20 :template "{{ json .Ports }}" :sort nil :format nil)
                               (:name "Command" :width 23 :template "{{ json .Command }}" :sort nil :format nil)
                               (:name "Created" :width 23 :template "{{ json .CreatedAt }}" :sort nil :format (lambda (x) (format-time-string "%F %T" (date-to-time x))))
                               )
                             )
   )
  )

dockerfile:

eglot uses: https://github.com/rcjsuen/dockerfile-language-server-nodejs.

(use-package dockerfile-mode
  :ensure-system-package (docker-langserver . "npm install -g dockerfile-language-server-nodejs")
  :ensure t
  ;; TODO: Raise bug about how this `:after` call breaks `eglot` automatically
  ;; running.
  ;; :after (eglot)
  :hook
  (
   ((dockerfile-mode dockerfile-ts-mode) . eglot-ensure)
   ((dockerfile-mode dockerfile-ts-mode) . (lambda () (set (make-local-variable 'compile-command) "docker build .")))
   )
  )

Kubernetes:

;; (use-package kubernetes
;;   ;; https://kubernetes-el.github.io/kubernetes-el/
;;   :ensure t
;;   :defer t
;;   :commands (kubernetes-overview)
;;   :init
;;   ;; https://github.com/kubernetes-el/kubernetes-el/issues/265
;;   ;; Work around: cyclic dependency.
;;   ;; `Debugger entered--Lisp error: (invalid-function kubernetes-utils--save-window-state)`
;;   (defmacro kubernetes-utils--save-window-state (&rest body)
;;     `(let ((pos (point)) (col (current-column)) (window-start-line (window-start)) (inhibit-redisplay t))
;;        (save-excursion ,@body)
;;        (goto-char pos)
;;        (move-to-column col)
;;        (set-window-start (selected-window) window-start-line)))
;; )

tramp-container (built-in):

Tramp into a docker container with: C-x C-f /docker:[user@]container:/path/to/file

Originally used: docker-tramp, but updated to latest Emacs29 (on 2022-10-25) and now have this warning: ~ ■ Warning (emacs): Package ‘docker-tramp’ has been obsoleted, please use integrated package ‘tramp-container’ [2 times]~, so removing for: tramp-container.

NOTE: TRAMP natively supports Docker, Podman and Kubernetes. Need to look into how this will work in latest Emacs29 branch builds!!

Programming Languages:

ansible:

(use-package ansible
  ; https://github.com/k1LoW/emacs-ansible
  :ensure t
  :defer t
  :config
  (progn
    (add-hook 'yaml-mode-hook '(lambda () (ansible 1)))
    )

  (use-package ansible-doc
    ; https://github.com/lunaryorn/ansible-doc.el
    :ensure t
  :defer t
    :hook (yaml-mode . ansible-doc-mode)
    )

  (use-package company-ansible
    ; https://github.com/krzysztof-magosa/company-ansible
    :ensure t
  :defer t
    :after (company)
    :config
    (add-to-list 'company-backends 'company-ansible)
    )

  )

Completions:

Code completions. This can be done with the built-in completion-at-point (C-M-i), but using company-mode for a drop down at point.

company-mode:

(use-package company
  :ensure t
  :defer t
  :bind (:map company-active-map
         ("C-n" . company-select-next)
         ([(tab)] . company-complete)
         )
  :hook ((prog-mode . global-company-mode))
  :config
  (setq
    company-tooltip-limit 20 ; bigger popup window.
    company-idle-delay .3    ; decrease delay before autocompletion popup shows.
    ;; (setq company-backends (delete 'company-semantic company-backends))
    )
  )

company-statistics:

Rate completions by use.

(use-package company-statistics
  :ensure t
  :after (company-mode)
  :hook ((after-init . company-statistics-mode))
  )

++ C/CPP:

cmake:

(use-package cmake-mode
  :ensure-system-package (cmake)
  :ensure t
  :hook ((cmake-mode . eglot-ensure))
  )

cpp:

cc-mode:

TODO:

  • Move to eglot.
    • Treesit mode is being picked up now but eglot is not enabled in the mode.
  • Build compile_commands.json.

See: Clangd Docs: Editor Plugins.

(use-package cc-mode
  ;; https://emacs-lsp.github.io/lsp-mode/page/lsp-clangd/
  :ensure-system-package (clangd)
  :ensure t
  :after (eglot)
  :hook (((c++-mode c++-ts-mode c-mode c-ts-mode) . eglot-ensure))
  :config
  (add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode))
  (add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode))
  (add-to-list 'major-mode-remap-alist '(c-or-c++-mode . c-or-c++-ts-mode))
  (with-eval-after-load 'eglot
    (add-to-list 'eglot-server-programs '((c++-mode c++-ts-mode c-mode c-ts-mode) "clangd"))
    )
  )

cc-mode (historical):

My very very old setup, long before LSP was a thing. Haven’t used it in about a decade.

;; (use-package cc-mode
;;   ;; gdb on mac:
;;   ;; brew tap homebrew/dupes && brew install gdb
;;   ;; Note: gdb keybinding is: C-x C-a C-l, which I did have my rename term windows as.
;;   :ensure t
;;   :defer t
;;   :bind (
;;          ;; ("<f9>" . compile)
;;          ([remap comment-region] . 'recompile)  ; "C-c C-c"
;;          ("M-." . 'xref-find-definitions)  ; https://www.emacswiki.org/emacs/EmacsTags
;;          )
;;   :config
;;   (progn

;;     (use-package smart-compile
;;       :ensure t
;;       :defer t)

;;     (use-package xcscope
;;       ;; Use cscope files within emacs, to jump around C/C++ code.
;;       ;; https://github.com/dkogan/xcscope.el
;;       :ensure t
;;       :defer t
;;       :config
;;       (progn
;;         ;; Setup auto-magically hooks into c/c++ modes.
;;         (cscope-setup)
;;         )
;;       (define-key c++-mode-map [remap c-set-style] 'cscope-find-this-symbol)  ;; C-c .
;;       ;; Note etags search defaults to: M-.
;;       )

;;     (use-package company-c-headers
;;       ;; Complete c-headers
;;       :ensure t
;;       :defer t
;;       :config
;;       (push 'company-c-headers company-backends)
;;       )

;;     ;; cc-mode general settings.

;;     ;; g++-4.9 -g3 -Wall -std=c++11 -stdlib=libc++ -lc++ *.cpp
;;     ;; clang++ -g3 -Wall -std=c++11 -stdlib=libc++ -lc++ *.cpp
;;     (add-to-list 'smart-compile-alist '("\\.[Cc]+[Pp]*\\'" . "clang++ -g3 -Wall -std=c++11 -stdlib=libc++ -lc++ -o %n.out *.cpp"))
;;     (add-hook 'c-mode-common-hook 'my-programming-defaults-config)
;;     (setq c-basic-offset 4)  ;; http://emacswiki.org/emacs/IndentingC
;;     (setq c-default-style "linux")  ;; http://cc-mode.sourceforge.net/html-manual/Built_002din-Styles.html#Built_002din-Styles
;;     ;; FIXME: Either bound this to `*compilation*` window only, so it stops
;;     ;; jumping when I grep, or find the old stop-on-first-error behaviour I
;;     ;; used to use.
;;     (setq compilation-auto-jump-to-first-error nil)
;;     )
;;   (define-key c++-mode-map [remap comment-region] 'compile)  ;; C-c C-c
;;   )

clang:

(use-package clang-format
  ;; Applies clang-format to C++ files based on a .clang-format file in the
  ;; project.
  ;; requires `clang-format` to be installed from system package manger.
  :ensure-system-package (clang)
  :ensure t
  :after (cc-mode)
  :config
  (progn
    (define-key c++-mode-map (kbd "C-c #") 'clang-format-region)
    )
  )

Function to Create TAG file:

Used to use this a decade ago. Not sure if it’s worth keeping now that LSP is the common way to offload completions and look-ups.

(defun create-tags (dir-name)
  "Create tags file in directory: DIR-NAME."
  (interactive "Directory: ")
  (eshell-command
   ; (format "find %s -type f -name \"*.[ch]\" | etags -" dir-name))) ;; `.c`/`.h` in a non-git repo.
   (format "cd $(git rev-parse --show-toplevel) && git ls-files | etags -" dir-name)))  ;; tag all files.

C#:

FIXME: keep getting: `Unable to activate package ‘csharp-mode’.` messages, so disabling until I have time to re-implement with `lsp-mode`.

;; (defun my-csharp-mode-syntax ()
;;   "Hook for my tweaks to 'csharp-mode'."
;;   (interactive)
;;   ;; https://www.gnu.org/software/emacs/manual/html_node/efaq/Indenting-switch-statements.html
;;   ;; https://stackoverflow.com/questions/3954607/c-sharp-emacs-mode-questions-indentation-and-build#3956173
;;   ;; http://kirste.userpage.fu-berlin.de/chemnet/use/info/cc-mode/cc-mode_6.html
;;   ;; `C-cC-s` to see indent at point.
;;   (c-set-offset `inline-open 0)  ; Stop brackets being indented further on a method.
;;   )

;; (use-package csharp-mode
;;   ;; https://jamiecollinson.com/blog/my-emacs-config/#c-1
;;   :ensure t
;;   :defer t
;;   :init
;;   (add-hook 'csharp-mode-hook 'my-programming-defaults-config)
;;   (add-hook 'csharp-mode-hook 'my-csharp-mode-syntax)
;;   ;; https://stackoverflow.com/questions/4608679/can-i-change-emacs-default-compile-command
;;   (add-hook 'csharp-mode-hook (lambda () (set (make-local-variable 'compile-command) "cd $(git rev-parse --show-toplevel) && dotnet run")))

;;   (use-package omnisharp
;;     ;; https://github.com/OmniSharp/omnisharp-emacs
;;     ;; https://jamiecollinson.com/blog/my-emacs-config/#c-1
;;     ;; https://www.tuicool.com/articles/22a2Ejb
;;     ;; NOTE: Needs a project with a `.csproj` file to do completions. Done with:
;;     ;; `dotnet new <project_type>`
;;     ;; FIXME: Deferring since I don't have omnisharp installed. Currently not
;;     ;; doing csharp. Should do a check of packages installed.
;;     :defer t
;;     :after (company)
;;     :bind (:map omnisharp-command-map
;;            ;; FIXME: Make these not global to C++ !!
;;            ("C-c f" . 'omnisharp-run-code-action-refactoring)  ; Refactor/missing_imports/etc...
;;            ("M-." . 'omnisharp-go-to-definition)
;;            )
;;     :config
;;     (add-hook 'csharp-mode-hook 'omnisharp-mode)
;;     (add-to-list 'company-backends 'company-omnisharp))

;;   (use-package coverlay
;;     ;; https://github.com/twada/coverlay.el
;;     ;; Coverage from an LCOV file.
;;     ;; Watch a file via: `M-x coverlay-watch-file /path/to/lcov-file`. or:
;;     ;; `C-c C-l w`.
;;     :ensure t
;;     :defer t
;;     :init
;;     (setq coverlay:mark-tested-lines nil)
;;     )
;;   )

css:

TODO: switch over to eglot!

(use-package css-mode
  ; https://emacs-lsp.github.io/lsp-mode/page/lsp-css/
  :ensure t
  :ensure-system-package (vscode-langservers-extracted)
  :defer t
  :hook ((css-mode css-ts-mode) . eglot-ensure)
  )

csv:

(use-package csv-mode
  :ensure t
  :defer t)

debugging:

DAP (lsp-mode):

(use-package dap-mode
  :if (not (eq system-type 'windows-nt))  ;; FIXME: (void-function dap-ui-mode)
  :ensure t
  :defer t
  :after (lsp hydra)
  :bind (
         ([f6] . dap-hydra)
         ([f7] . 'dap-ui-repl)
         )
  :commands
  (
   dap-mode
   dap-ui-mode
   dap-tooltip-mode
   dap-ui-controls-mode
   )
  :config
  (setq
  ;; NOTE: For Python. install: `debugpy` python package in the project!
   dap-python-debugger 'debugpy   ;; The default: `ptvsd` is deprecated!
   dap-ui-variable-length 1000  ;; https://github.com/emacs-lsp/dap-mode/issues/416 - don't truncate `locals` variables.
   dap-internal-terminal 'dap-internal-terminal-shell  ;; Forgotten how to scroll `vterm` so using shell.
   )
  ;; https://www.reddit.com/r/emacs/comments/tckmb2/dapmode_breakpoints_not_showing_when_in_terminal/
  (add-hook 'dap-stopped-hook
            (lambda (arg) (call-interactively #'dap-hydra)))
  )
;; (use-package dap-LANGUAGE) to load the dap adapter for your language
(with-eval-after-load 'dap-faces
  (unless (display-graphic-p)
    (set-face-background 'dap-ui-marker-face "color-166") ; An orange background for the line to execute
    (set-face-attribute 'dap-ui-marker-face nil :inherit nil) ; Do not inherit other styles
    (set-face-background 'dap-ui-pending-breakpoint-face "blue") ; Blue background for breakpoints line
    (set-face-attribute 'dap-ui-verified-breakpoint-face nil :inherit 'dap-ui-pending-breakpoint-face)
    )
  )
(use-package realgud
  :ensure t
  :defer t)

Major mode for .env files.

(use-package dotenv-mode
  :ensure t)

elisp:

(add-hook 'emacs-lisp-mode-hook 'my-programming-defaults-config)
;; code from: http://www.emacswiki.org/emacs/EmacsLispMode
(add-hook 'emacs-lisp-mode-hook
          (lambda ()
            ;; Pretty-print eval'd expressions.
            (define-key emacs-lisp-mode-map
                        "\C-x\C-e" 'pp-eval-last-sexp)
            ;; ;; Recompile if .elc exists. ;; recompiles everything on every save -cas
            ;; (add-hook (make-local-variable 'after-save-hook)
            ;;           (lambda ()
            ;;             (byte-force-recompile default-directory)))
            (define-key emacs-lisp-mode-map
                        "\r" 'reindent-then-newline-and-indent)))
(add-hook 'emacs-lisp-mode-hook 'eldoc-mode)

erlang:

FIXME: erlang mode is throwing errors on start in latest emacs28!!

;; (use-package erlang
;;   ;; (require 'erlang-start)
;;   :ensure t
;;  :defer t
;;   )

gherkin:

(use-package feature-mode
  :ensure t
  :defer t
  :mode "\\.spec\\'"
  )

gnuplot:

Required by M-x org-plot/gnuplot.

(use-package gnuplot
  :ensure-system-package (gnuplot)
  :ensure t
  :defer t
  )

Mode for editing gnuplot files.

(use-package gnuplot-mode
  :ensure t
  :defer t
  )

go:

Go config links:

Requires go & gopls to be installed. See:

Also see: Add optional support for tree-sitter #396, which is tracking issues with supporting the new go-ts-mode.

(use-package go-mode
  :ensure-system-package (go gopls)
  :ensure t
  :after eglot
  :functions flycheck-mode
  :preface
  (defun cas/go-config ()
    "Tame tab indenting for go mode."
    (setq tab-width 4)
    (setq go-ts-mode-indent-offset 4)
    (setq indent-tabs-mode t)
    (add-hook 'before-save-hook #'eglot-format-buffer -10 t)
    (add-hook 'before-save-hook #'gofmt-before-save)
    ;; Need the above line to load the: ~gofmt~ package in emacs. Why!?
    ;; (add-hook 'before-save-hook 'gofmt nil t)
    (if (not (string-match "go" compile-command))
        (set (make-local-variable 'compile-command)
             "go build -v && go test -v && go vet"))
    )
  :hook (
         ((go-mode go-ts-mode) . cas/go-config)
         ((go-mode go-ts-mode) . eglot-ensure)
     )
  )

Debug Go programs with: Delve, via: go-dlv on top of realgud.

For help either look at: Github: go-delve/delve/blob/master/Documentation/cli/README.md, or: help in a running delve process.

Typical workflow might be:

  • Debug Tests: M-x dlv <return> dlv test <return>, Debug App: dlv debug.
  • Set Breakpoint: b <file>:<line>, List: bp, toggle: toggle <int>
  • Start/Continue: c.
  • Step: s, Step Over: n, Step Out: n.
  • Print variable: p <variable>.
  • Call function: call <func>.
  • Restart: r. **NOTE:** need to restart debug session to pick up file changes!!
  • Exit: exit
(use-package go-dlv
  :ensure-system-package (delve)
  :ensure t
  :after (realgud)
  )

Go support in org-code blocks.

(use-package ob-go
  :ensure t
  :config
  (add-to-list 'org-babel-load-languages '(go . t))
  (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)
  )

This will allow the following code block to run:

fmt.Println("Current Time:", time.Now())
(use-package graphql-mode
  :ensure t
  :defer t
  )

Dependency on GraphQL-mode to do requests.

(use-package request
  :ensure t
  :defer t
  )

groovy:

(use-package groovy-mode
  ; https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes
  :ensure t
  :defer t
  :mode (
         ("\\.groovy\\'" . groovy-mode)
         ("\\Jenkinsfile*\\'" . groovy-mode)
         )
  :config
  (progn
    (add-hook 'groovy-mode-hook 'my-programming-defaults-config)
    )
  )

html:

; https://emacs-lsp.github.io/lsp-mode/page/lsp-html/
;; (add-hook 'html-mode-hook 'lsp)

i3wm:

(use-package i3wm-config-mode
  :ensure t
  :defer t)

See: InnoSetup mode: https://jrsoftware.org/isinfo.php

(use-package iss-mode
  :mode "\\.iss\\'"
  :ensure t
  :defer t
  :init
  (setq iss-compiler-path "C:/Program Files (x86)/Inno Setup 6")
  )

java:

(defun my-java-mode-syntax ()
  "Hook for my tweaks to `java-mode`."
  (interactive)
  ;; https://www.gnu.org/software/emacs/manual/html_node/efaq/Indenting-switch-statements.html
  (c-set-offset 'case-label '+)  ; A "case" or "default" label.
  (c-set-offset 'brace-list-entry '++)  ; Subsequent lines in an enum or static array list.
  (c-set-offset `arglist-intro `+)  ; function fields on a new line.
  )

;; https://writequit.org/eos/eos-java.html
;; https://github.com/dakrone/emacs-java-imports
;; https://github.com/mopemope/meghanada-emacs
(use-package meghanada
  :ensure t
  :defer t
  :init
  (add-hook 'java-mode-hook #'meghanada-mode)
  (add-hook 'java-mode-hook 'flycheck-mode)
  (add-hook 'java-mode-hook 'my-programming-defaults-config)
  ;; Java warnings stop compilation scrolling, so let's always scroll.
  (add-hook 'java-mode-hook (lambda() compilation-scroll-output t))
  (add-hook 'java-mode-hook (lambda () compile-command "cd $(git rev-parse --show-toplevel) && mvn clean verify"))
  (add-hook 'java-mode-hook 'my-java-mode-syntax)
  )

(use-package mvn
  :ensure t
  :defer t
  :init
  ;; Correctly colourise the compilation buffer for maven calls.
  ;; https://github.com/apg/mvn-el
  (ignore-errors
    (require 'ansi-color)
    (defun colorize-compilation-buffer ()
      (when (eq major-mode 'compilation-mode)
        (let ((inhibit-read-only t))
          (if (boundp 'compilation-filter-start)
              (ansi-color-apply-on-region compilation-filter-start (point))))))
    (add-hook 'compilation-filter-hook 'colorize-compilation-buffer))
  )

javascript:

;; https://github.com/codesuki/add-node-modules-path
;; (use-package add-node-modules-path
;;   :ensure t
;;   :defer t
;;   )
;; https://github.com/jscheid/prettier.el
;; (use-package prettier
;;   :ensure t
;;   :defer t
;;   )
; https://github.com/prettier/prettier-emacs
; Requires global prettier install: `npm install -g prettier`.
;; (use-package prettier-js
;;   :ensure t
;;   :defer t
;;   )
; https://emacs.cafe/emacs/javascript/setup/2017/05/09/emacs-setup-javascript-2.html
; https://emacs-lsp.github.io/lsp-mode/tutorials/reactjs-tutorial/ = ts-ls.
; https://emacs-lsp.github.io/lsp-mode/page/lsp-eslint/
; https://classic.yarnpkg.com/en/docs/cli/global
; - move yarn global install path to home dir and then install eslint globally.
; `yarn config set prefix ~/.yarn`
; `npx -p node@14 yarn global add eslint`
; `M-x lsp-install-server <ret> eslint <ret>`

(use-package js2-mode
  :ensure t
  :defer t
  :mode ("\\.js\\'" "\\.jsx\\'" "\\.mjs\\'")
  :hook (
         ;; (js2-mode . add-node-modules-path)
         ;; (js2-mode . prettier-js-mode)  ; runs prettier on save.
         ;; (js2-mode . prettier-mode)  ; runs prettier on save.
         (js2-mode . eglot-ensure)
         )
;;    :config
  )

;; FIXME: need to update the path to my local node-modules for my project that
;; is in a sub-directory of the repo.
;; (use-package eslint-fix
;;   ; https://github.com/codesuki/eslint-fix
;;   :ensure t
;;   :defer t
;;   :hook (
;;          (js-mode . selint-fix)
;;          (js2-mode . selint-fix)
;;          )
;;   :init
;;   (setq eslint-fix-executable "npx eslint")
;; )

json:

json-mode:

(use-package json-mode
  :ensure t
  :defer t
  :mode ("\\.json\\'" . json-mode)
  :hook (
         (json-mode . my-programming-defaults-config)
         (json-mode . (lambda () (auto-fill-mode -1)))  ;; disables auto fill at column.
         (json-mode . (lambda () (setq js-indent-level 2)))
         )
  )

json-format:

;; *****************************************************
;; *****************************************************
;; Json programming
;; *****************************************************
;; *****************************************************
; TODO: Figure out which package is requiring `json-reformat` ??
;; Debugger entered--Lisp error: (file-missing "Cannot open load file" "No such file or directory" "json-reformat")
;;   require(json-reformat)
;;   byte-code("\300\301!\210\300\302!\210\300\303!\210\300\304!\210\305\306\307\310\311\301%\207" [require js rx json-snatcher json-reformat custom-declare-group json-mode nil "Major mode for editing JSON files." :group] 6)
;;   json-mode()
;;   set-auto-mode-0(json-mode nil)
;;   set-auto-mode--apply-alist((("\\.iss\\'" . iss-mode) ("\\.msc$" . mscgen-mode) ("\\.rcp\\'" . emacs-lisp-mode) (".*mutt.*" . mail-mode) ("\\.plantuml\\'" . plantuml-mode) ("\\.odc\\'" . archive-mode) ("\\.odf\\'" . archive-mode) ("\\.odi\\'" . archive-mode) ("\\.otp\\'" . archive-mode) ("\\.odp\\'" . archive-mode) ("\\.otg\\'" . archive-mode) ("\\.odg\\'" . archive-mode) ("\\.ots\\'" . archive-mode) ("\\.ods\\'" . archive-mode) ("\\.odm\\'" . archive-mode) ("\\.ott\\'" . archive-mode) ("\\.odt\\'" . archive-mode) ("\\.mjs\\'" . js2-mode) ("\\.jsx\\'" . js2-mode) ("\\.js\\'" . js2-mode) ("\\.py\\'" . python-mode) ("\\.restclient\\'" . restclient-mode) ("\\.json\\'" . json-mode) ("\\.yaml\\'" . yaml-mode) ("\\.yml\\'" . yaml-mode) ("\\.\\(e?ya?\\|ra\\)ml\\'" . yaml-mode) ("\\.md\\'" . markdown-mode) ("\\Jenkinsfile*\\'" . groovy-mode) ("\\.groovy\\'" . groovy-mode) ("\\.php\\'" . php-mode) ("\\.\\(?:php[s345]?\\|phtml\\)\\'" . php-mode-maybe) ("\\.\\(?:php\\.inc\\|stub\\)\\'" . php-mode) ("/\\.php_cs\\(?:\\.dist\\)?\\'" . php-mode) ("web.config$" . xml-mode) ("\\.cmake\\'" . cmake-mode) ("CMakeLists\\.txt\\'" . cmake-mode) ("\\.tsv\\'" . tsv-mode) ("\\.[Cc][Ss][Vv]\\'" . csv-mode) ("\\.dockerfile\\'" . dockerfile-mode) ("/Dockerfile\\(?:\\.[^/\\]*\\)?\\'" . dockerfile-mode) ("\\.hrl\\'" . erlang-mode) ("\\.erl\\'" . erlang-mode) ("/ebin/.+\\.app" . erlang-mode) ("\\.yrl" . erlang-mode) ("\\.xrl$" . erlang-mode) ("\\.hrl$" . erlang-mode) ("\\.escript" . erlang-mode) ("\\.app\\.src$" . erlang-mode) ("\\.erl$" . erlang-mode) ("go\\.mod\\'" . go-dot-mod-mode) ...) nil nil)
;;   set-auto-mode()
;;   normal-mode(t)
;;   after-find-file(nil nil)
;;   find-file-noselect-1(#<buffer package.json> "~/work/Apollo/Unlock/unlock_webui/package.json" :nowarn nil "~/work/Apollo/Unlock/unlock_webui/package.json" (27399170 66307))
;;   find-file-noselect("/home/craig/work/Apollo/Unlock/unlock_webui/packag..." :nowarn)
;;   desktop-restore-file-buffer("/home/craig/work/Apollo/Unlock/unlock_webui/packag..." "package.json" nil)
;;   desktop-create-buffer(208 "/home/craig/work/Apollo/Unlock/unlock_webui/packag..." "package.json" fundamental-mode (override-global-mode global-whitespace-mode company-mode projectile-mode which-key-mode dap-mode global-auto-revert-mode) 2720 (nil nil) nil nil ((buffer-display-time 24951 42966 348475 416000) (buffer-file-coding-system . utf-8-unix)) ((mark-ring nil)))
;;   eval-buffer(#<buffer  *load*> nil "/home/craig/.emacs.desktop" nil t)  ; Reading at buffer position 15343
;;   load-with-code-conversion("/home/craig/.emacs.desktop" "/home/craig/.emacs.desktop" t t)
;;   load("/home/craig/.emacs.desktop" t t t)
;;   desktop-read()
;;   #f(compiled-function () #<bytecode -0x19a5bc467a428ba3>)()
;;   run-hooks(after-init-hook delayed-warnings-hook)
;;   command-line()
;;   normal-top-level()

(use-package json-reformat
  :ensure t
  :defer t)

linting:

flycheck:

Setup Flycheck (Code checking on the fly (replaces flymake)). Used to run this for years, but moving back to using emacs built-ins.

(use-package flycheck                   ; On-the-fly syntax checking
  :ensure t
  :defer t
  :bind (:map flycheck-mode-map
         ("C-c e" . list-flycheck-errors)
         ("C-c T f" . flycheck-mode)
         ("C-c j" . flycheck-next-error)
        )
  ;; :init (global-flycheck-mode)
  :config
  (progn
    (setq
     flycheck-completion-system 'ido
     flycheck-highlighting-mode 'lines
     flycheck-display-errors-delay 0.0
     flycheck-flake8-maximum-complexity 10
     flycheck-flake8rc "setup.cfg"
     flycheck-highlighting-mode (quote lines)
     ;; Set the standard library to libc++ so that C++11 headers will work
     flycheck-clang-standard-library "libc++"
     )
    (set-face-attribute 'flycheck-error nil :background "DarkRed")  ; dark red
    (set-face-attribute 'flycheck-warning nil :background "DarkBlue")  ; dark blue
    (set-face-attribute 'flycheck-info nil :background "DarkGreen")  ; dark green
    ;; Use italic face for checker name
    (set-face-attribute 'flycheck-error-list-checker-name nil :inherit 'italic)
  )
  :diminish flycheck-mode)
(flycheck-mode flycheck-mode-line) ; Flycheck status
'(flycheck-error-list-column-number ((t (:inherit font-lock-constant-face :background "blue"))))
'(flycheck-warning ((t (:background "DarkBlue" :underline (:color "DarkOrange" :style wave)))))


;; ;; Chain modes after `lsp`.
;; ;; https://rat.dev/flycheck/flycheck/issues/1762
;; (defvar-local my/flycheck-local-cache nil)
;; (defun my/flycheck-checker-get (fn checker property)
;;   (or (alist-get property (alist-get checker my/flycheck-local-cache))
;;       (funcall fn checker property)))
;; (advice-add 'flycheck-checker-get :around 'my/flycheck-checker-get)
;; (add-hook 'lsp-managed-mode-hook
;;           (lambda ()
;;             (when (derived-mode-p 'python-mode)
;;               (setq my/flycheck-local-cache '((lsp . ((next-checkers . (python-pylint)))))))))

log4j:

Log file highlighting

(use-package log4j-mode
  :ensure t
  :defer t
  :mode "\\.log\\'"
  )
'(log4j-font-lock-fatal-face ((t (:foreground "darkred" :weight bold))))
'(log4j-font-lock-info-face ((t (:foreground "ForestGreen"))))
'(log4j-font-lock-warn-face ((t (:foreground "orange"))))

LSP (Language Server Protocol):

lsp-mode is the external, feature-rich version of: [[*\[\[https://joaotavora.github.io/eglot/\]\[eglot\]\]:][eglot]] (built-in), for interacting with LSP Servers in emacs.

LSP dependencies:

Seeing LSP and other packages blowing up on this missing requirement.

(use-package posframe
  :ensure t
  :defer t
  )

LSP core:

;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
(setq lsp-keymap-prefix "s-l")


(use-package lsp-mode
  :ensure t
  :defer t
  :hook (;; replace XXX-mode with concrete major-mode(e. g. python-mode)

         ;; Python workflow:
         ;; * `pipenv install --dev python-language-server[all]`.
         ;; * Start pipenv: `C-cC-pa`.
         ;; * Start lsp: `M-x lsp`.
         (rust-mode . lsp)
         ;; if you want which-key integration
         (lsp-mode . lsp-enable-which-key-integration)
         (lsp-mode . my-programming-defaults-config)
         )
  :commands lsp
  :config
  (setq
   lsp-file-watch-threshold 20000
   gc-cons-threshold 100000000
   read-process-output-max (* 1024 1024 4)  ;; 4MB
        )
  )

LSP UI:

(use-package lsp-ui
  ;; https://github.com/emacs-lsp/lsp-ui
  :ensure t
  :defer t
  :after (lsp)
  :commands (
             lsp-ui-mode
             lsp-ui-peek-mode
             lsp-ui-sideline-mode
             )
  :bind (:map lsp-command-map
         ([remap xref-find-definitions] . #'lsp-ui-peek-find-definitions)  ;; M-.
         ([remap xref-find-references] . #'lsp-ui-peek-find-references)  ;; M-?
         )
  :config
  (setq
   lsp-ui-doc-show-with-cursor t
   )
  )

LSP Treemacs:

(use-package lsp-treemacs
  :after (lsp))

LSP Python Extensions:

I preferred jedi over rope for ease of setup and usage, but have moved away from Jedi for pyright ([[*\[\[https://emacs-lsp.github.io/lsp-pyright/\]\[lsp-pyright\]\]:][lsp-pyright]]) since it is installed outside of dependencies (so more consistent usage with emacs across repos + no longer have to fight to install dev dependencies for local editor completions). See: https://github.com/pappasam/jedi-language-server.

;; (use-package lsp-jedi
;;   :ensure t
;;   :defer t
;;   :after (python-mode lsp)
;;  )

My Current choice of sourcing completions for python: Github: emacs-lsp/lsp-pyright.

(use-package lsp-pyright
  :disabled
  ;; :ensure t
  :defer t
  :after (python-mode lsp)
  :hook (python-mode . (lambda ()
                         (require 'lsp-pyright)
                         (lsp))))  ; or lsp-deferred

lsp-python-ms:

NOTE: Working on some code that prevents me installing Jedi due to dependency conflicts. Trying out MS Python, but eventually moved over to: [[*\[\[https://emacs-lsp.github.io/lsp-pyright/\]\[lsp-pyright\]\]:][lsp-pyright]]. Error:

(ignore-error module-not-gpl-compatible
  ;; Added ingore-error due to noise from tree-sitter-langs `python.dylib`.
  ;; See: https://github.com/emacs-tree-sitter/elisp-tree-sitter/issues/100
for a similar problem on NixOS.
)
(use-package lsp-python-ms
  :disabled
  ;; :ensure t
  :defer t
  :after (python-mode lsp)
  :init (setq lsp-python-ms-auto-install-server t)
  :hook (python-mode . (lambda ()
                         (require 'lsp-python-ms)
                         ;; Using `lsp-deferred` since it handles showing
                         ;; errors in the buffer after the MS LSP agent has
                         ;; finished analysis (instead of `lsp`).
                         (lsp-deferred))))

make-mode (built-in):

FIXME: remove the eglot-ensure hook on prog-mode, since there is no lsp-server for Makefile’s.

(use-package make-mode
  :ensure t
  :preface
  (defun cas/make-mode-config ()
    "Set config just for Makefile buffers."
    (setq indent-tabs-mode t)
    ;; (remove-hook 'prog-mode-hook 'eglot-ensure)
    )
  :hook ((makefile-mode . cas/make-mode-config))
  )

markdown:

NOTE:

  • flymd looks to be broken and unmaintained. Use impatient-mode for live previews.
  • M-x markdown-preview, requires: markdown, to be installed with system package manager.

Look at:

;; https://www.emacswiki.org/emacs/KeyboardMacros
;; https://www.emacswiki.org/emacs/KeyboardMacrosTricks
(fset 'convert-markdown-ref-to-list
      "\C-[xreplace-regexp\C-m\\[\\(.*\\)\\].*\C-m* [\\1].\C-m")
(fset 'convert-markdown-github-url-to-ref
      "\C-[xreplace-regexp\C-m.*github.com/\\(.*\\)/\\(.*\\)\C-m[Github: \\1/\\2]: https://github.com/\\1/\\2\C-m")
;; FIXME: figure out how to feed the `LFD` or `C-qC-j` without it
;; counting as a real `RET` and breaking the `replace-regexp` with:
;; `\\(` !!
(defalias 'strip-a-ids-from-org-markdown-export
  (kmacro "M-< M-x r e p l a c e - r e g e x p RET \\ ( < a SPC i d = .* > < / a > \\ ) RET RET"))

(use-package markdown-mode
  ;; ~markdown~ in arch package manager.
  ;; :ensure-system-package (markdown)  ;; Required by ~M-x markdown-preview~.
  :ensure t
  :ensure-system-package (marksman)
  :mode ("README\\.md\\'" . gfm-mode)
  ;; multimarkdown is in brew/yay, but not pulling down on arch??
  ;; :init (setq markdown-command "multimarkdown")
  :bind (
         ("C-c C-a b" . convert-markdown-ref-to-list)
         ("C-c C-a g" . convert-markdown-github-url-to-ref)
         ("C-c C-a s" . strip-a-ids-from-org-markdown-export)
         )
  :hook (
         (markdown-mode . my-text-mode-config)
         (markdown-mode . eglot-ensure)
         )
  )

impatient-mode is a way of doing live previews of the current buffer in a web browser.

(use-package impatient-mode
  ; start webserver with: `M-x httpd-start`.
  ; Then set the mode on the buffer: `M-x impatient-mode`.
  :ensure t
  :defer t
  )

my-markdown-preview:

http-start doesn’t blow up when port is in use, so this ends up sending the impatient-mode generated URL to whatever service is already running on the default port of 8080.

See: https://blog.bitsandbobs.net/blog/emacs-markdown-live-preview/

(defun my-markdown-filter (buffer)
  "Function to allow `impatient-mode` to preview markdown.  Usage:

* `M-x httpd-start`
* Go to required BUFFER.
* `M-x impatient-mode`
* `M-x imp-set-user-filter RET markdown-html RET`"
  (princ
   (with-temp-buffer
     (let ((tmp (buffer-name)))
       (set-buffer buffer)
       (set-buffer (markdown tmp))
       (format "<!DOCTYPE html><html><title>Markdown preview</title><link rel=\"stylesheet\" href = \"https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.min.css\"/>
<body><article class=\"markdown-body\" style=\"box-sizing: border-box;min-width: 200px;max-width: 980px;margin: 0 auto;padding: 45px;\">%s</article></body></html>" (buffer-string))))
   (current-buffer)))


(defun my-markdown-preview ()
  "Preview markdown."
  (interactive)
  (unless (process-status "httpd")
    (setq httpd-port 8088)
    (httpd-start))
  (impatient-mode)
  (imp-set-user-filter 'my-markdown-filter)
  (imp-visit-buffer))

html-to-markdown:

(use-package html-to-markdown
  ;; Convert html code to markdown.
  :ensure t
  :defer t)

markdown-toc:

(use-package markdown-toc
  ;; https://github.com/ardumont/markdown-toc
  ;; Used to generate a table of contents in a markdown file.
  :ensure t
  :defer t)

pcap (wireshark) file support.

(use-package pcap-mode
  :ensure t
  :defer t)

php:

Need to run the php-language-server for eglot to connect to:

docker kill php-language-server
docker rm php-language-server
docker pull felixfbecker/php-language-server
docker run --detach -p2088:2088 --restart=always --name php-language-server felixfbecker/php-language-server

What’s Next?

  1. Sign in to your Docker account → docker login
  2. View a summary of image vulnerabilities and recommendations → docker scout quickview felixfbecker/php-language-server

WARNING: The requested image’s platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested b9a761ffbf9a77c0fa4fbdbc390e7f43977f75338963d7285232766297d903c2

NOTE: On Mac’s; eglot will not connect if it is set to localhost!

(use-package php-mode
  :ensure t
  :defer t
  :mode ("\\.php\\'" . php-mode)
  :hook (
         (php-mode-hook . my-programming-defaults-config)
         (php-mode . eglot-ensure)
         )
  ;; :custom
  ;; ;; See: https://2metz.fr/blog/configuring-emacs-eglot-lsp-with-docker-containers/
  ;; ;; for an example of eglot starting docker containers.
  ;; (eglot-withhold-process-id "1")
  :config
  (with-eval-after-load 'eglot
    (add-to-list 'eglot-server-programs
                 '(php-mode . ("127.0.0.1" 2088))))
  )
;;                   '(php-mode . ("docker" "run" "--rm" "--detach" "--name=php-language-server" "felixfbecker/php-language-server"))))
(use-package powershell
  :ensure t
  :defer t
  :hook (
         (powershell-mode . my-programming-defaults-config)
         ; (powershell-mode . lsp) ;; No `Expand-Archive` on Arch pwsh, so cannot install `pwsh-ls` automatically.
         )
  )

python:

Historical Links:

python (python-mode):

NOTE: This still requires running: M-x eglot and then picking the python LSP server (suggest: pyright-langserver).

(use-package python
  :ensure-system-package ((python3 . python) (pyright))
  :after eglot
  :ensure t
  :functions flycheck-mode
  :preface
  (defun cas/python-config ()
      "Python additional config."
      (if (not (string-match "python" compile-command))
          (set (make-local-variable 'compile-command)
               "pytest"))
      )
  :hook (
         (python-ts-mode . cas/python-config)
         ((python-mode python-ts-mode) . eglot-ensure)
         )
  :config
  (setq
   ;; See: https://github.com/renzmann/treesit-auto#keep-track-of-your-hooks
   python-ts-mode-hook python-mode-hook
   )
  )

Linters:

Uses Github: psf/black to reformat python buffer on save.

(use-package blacken
  :ensure t
  :hook (python-mode . blacken-mode)
  ;; :init
  ;; NOTE: Commented out below line due to currently working on projects that
  ;; require `black` but have no: `[tool.black]` in the `pyproject.toml` file.
  ;; (setq blacken-only-if-project-is-blackened t)
  )

Calls isort to sort imports.

TODO: figure out why this is cause code to be eaten from the top of the file on save.

;; (use-package isortify
;;   :ensure t
;;   :defer t
;;   :after (python-mode)
;;   :hook (python-mode . isortify-mode)
;;   )

Mentioned as the Emacs Ruff integration. FIXME: bound to only python buffers (with ruff installed??).

(use-package flymake-ruff
  :ensure-system-package ((ruff))
  :ensure t
  :hook (eglot-managed-mode . flymake-ruff-load)
  :custom
  ;; https://github.com/renzmann/.emacs.d/blob/emacs-29/README.org#python
  (python-check-command "ruff")
  )

pyright:

(with-eval-after-load 'compile
  (add-to-list 'compilation-error-regexp-alist-alist
               '(pyright "^[[:blank:]]+\\(.+\\):\\([0-9]+\\):\\([0-9]+\\).*$" 1 2 3))
  (add-to-list 'compilation-error-regexp-alist 'pyright))

Package Management:

conda:

;; FIXME: auto activation blows up when a file has no conda env associated to it.
;;
(when (eq system-type 'darwin)
  ;; FIXME: Bound this to my Work laptop only and not break my personal linux
  ;; laptop when I don't touch conda.
  (use-package conda
    :after (python-mode)
    :ensure t
    :defer t
    :config
    ;; https://github.com/necaris/conda.el/issues/107 - stopped working with
    ;;conda 4.13.0
    ;;
    ;; Brew location for `miniforge`.
    ;; TODO: bound to `darwin`.
    ;; TODO: check all available paths to see which exists or look into ENV variables ??
    (setq conda-anaconda-home (expand-file-name "/opt/homebrew/Caskroom/miniforge/base/"))
    (setq conda-env-home-directory (expand-file-name "/opt/homebrew/Caskroom/miniforge/base/"))
    ;; ;; Web install location for `miniconda`.
    ;; (setq conda-anaconda-home (expand-file-name "~/opt/miniconda3/"))
    ;; (setq conda-env-home-directory (expand-file-name "~/opt/miniconda3/"))
    ;; if you want interactive shell support, include:
    (conda-env-initialize-interactive-shells)
    ;; if you want eshell support, include:
    ;;  (conda-env-initialize-eshell)
    ;;  (defun conda-autoload ()
    ;;    (interactive)
    ;;    "auto activate conda if environment.yml exists."
    ;;    (f-traverse-upwards (lambda (path)
    ;;                          (let ((venv-path (f-expand "environment.yml" path)))
    ;;                            (when (f-exists? venv-path)
    ;;                              (conda-env-activate-for-buffer)
    ;;                              )))))
    ;; NOTE: Using above function to load env for each buffer, instead of the
    ;; global mode, since the global setting below doesn't gracefully handle
    ;; buffers that don't have a conda env.
    ;;
    ;; ;; if you want auto-activation (see below for details), include:
    ;; (conda-env-autoactivate-mode t)
    ;; ;; if you want to automatically activate a conda environment on the opening of a file:
    ;; (add-to-hook 'find-file-hook (lambda () (when (bound-and-true-p conda-project-env-path)
    ;;                                           (conda-env-activate-for-buffer))))
    ;; modeline
    ;; (setq-default mode-line-format (cons '(:exec conda-env-current-name) mode-line-format))
    ;; :hook (
    ;;        (python-mode . conda-autoload)
    ;;        )
  )
)

FIXME: removing since current work is poetry in a conda env. Advice is to just use conda to manage the venv loading, since poetry is looking in the wrong location.

(use-package poetry
  :ensure t
  :defer t
  :after (python-mode)
  ;; :config
  ;; (poetry-tracking-mode)  ;; activate poetry virtualenv's on buffer change.
  )

Virtual Env Management:

Global pyright use local venv + eglot:

Configure global pyright to pick up project local venv. Starting eglot, will then call the correctly configured pyright (Still need to pyvenv-activate then restart eglot, for the rest of emacs to be happy).

(defun pyrightconfig-write (virtualenv)
  "Write a `pyrightconfig.json' file at the Git root of a project
with `venvPath' and `venv' set to the absolute path of
`virtualenv'.  When run interactively, prompts for a directory to
select."
  (interactive "DEnv: ")
  ;; Naming convention for venvPath matches the field for pyrightconfig.json
  (let* ((venv-dir (tramp-file-local-name (file-truename virtualenv)))
         (venv-file-name (directory-file-name venv-dir))
         (venvPath (file-name-directory venv-file-name))
         (venv (file-name-base venv-file-name))
         (base-dir (vc-git-root default-directory))
         (out-file (expand-file-name "pyrightconfig.json" base-dir))
         (out-contents (json-encode (list :venvPath venvPath :venv venv))))
    (with-temp-file out-file (insert out-contents))
    (message (concat "Configured `" out-file "` to use environment `" venv-dir))))

The replacement to virtualenv. Do C-cC-pa or M-x pipenv-activate to start a projects pipenv.

;; (use-package pipenv
;;   :ensure t
;;   :defer t
;;   :after (python-mode)
;;   :hook (python-mode . pipenv-mode)
;;   :init
;;   (setq
;;    pipenv-projectile-after-switch-function
;;    #'pipenv-projectile-after-switch-default))

pyvenv:

(use-package pyvenv
  :ensure t
  :defer t
  :after (python-mode)
  :functions pyvenv-autoload
  :config
  (defun pyvenv-autoload ()
    "auto activate venv directory if exists. See: https://github.com/jorgenschaefer/pyvenv/issues/51"
    (interactive)
    (f-traverse-upwards (lambda (path)
                          (let ((venv-path (f-expand ".venv" path)))
                            (when (f-exists? venv-path)
                              (pyvenv-activate venv-path)
                              )))))
  :hook (
         (python-mode . pyvenv-autoload)
         ;; Modified from: https://github.com/jorgenschaefer/pyvenv/issues/95
         ;; FIXME: correct this so it runs LSP after above call, so I don't
         ;; need to do: C-xC-v.
         ;; (pyvenv-post-activate-hooks . lsp)
         )
  )
(use-package rust-mode
  :ensure t
  :defer t
  :hook (rust-mode . eglot-ensure)
  )

sh/bash:

(use-package sh-script
  :ensure-system-package ((shellcheck) (bash-language-server))
  :ensure t
  :defer t
  :hook (((shell-script-mode sh-mode bash-ts-mode) . eglot-ensure))
  )

sql:

(use-package sql
  :ensure-system-package (sqlfluff)
  :ensure t
  :config
  (setq
   sql-dialect 'postgres
   sql-linter-program 'sqlfluff
   indent-tabs-mode nil  ;; spaces instead of tabs
   )
  )

Testing out SQLFluff for linting.

(use-package flymake-sqlfluff
  :ensure-system-package (sqlfluff)
  :ensure t)
(use-package sql-indent
  :ensure t)

Terraform is infrastructure as code to abstract across the big Cloud providers.

(use-package terraform-mode
  :ensure-system-package
  (
   (terraform)
   (terraform-ls)
   )
  :ensure t
  :hook (((terraform-mode terraform-ts-mode) . eglot-ensure))
  :config (setq terraform-format-on-save t)
  ;; https://github.com/hashicorp/terraform-ls/blob/main/docs/USAGE.md
  (with-eval-after-load 'eglot
    (add-to-list 'eglot-server-programs
                 `(terraform-mode . ,(eglot-alternatives
                                      '(("terraform-ls" "serve")
                                        ("terraform-lsp" "serve"))))))
  )
(use-package typescript-mode
  :ensure t
  :ensure-system-package (typescript-language-server)
  )

xml:

nxml-mode:

(use-package nxml-mode
  :mode ("web.config$" . xml-mode)
  :init
  (progn
    (add-hook 'nxml-mode-hook 'my-programming-defaults-config)
    (add-hook 'nxml-mode-hook (lambda () (auto-fill-mode -1)))  ;; disables auto fill at column.
    ;; http://www.nuxeo.com/blog/nxml-mode-tabs/
    (add-hook 'nxml-mode-hook (lambda () (setq indent-tabs-mode nil)))
    (setq
     nxml-child-indent 4
     )
    )
  )

Pretty print XML:

(defun bf-pretty-print-xml-region (begin end)
  "Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this.  The function inserts linebreaks to separate tags that have
nothing but whitespace between them.  It then indents the markup
by using nxml's indentation rules."
  (interactive "r")
  (save-excursion
    (nxml-mode)
    (goto-char begin)
    (while (search-forward-regexp "\>[ \\t]*\<" nil t)
      (backward-char) (insert "\n") (setq end (1+ end)))
    (indent-region begin end))
  (message "Ah, much better!"))

Usage:

  • Past XML into an nxml-mode buffer.
  • To expand single-line XML: Select region or jump to start and call: bf-pretty-print-xml-region.
  • To indent multi-line XML: Select region and call: indent-region.

yaml:

Use :ensure-system-package to install the: Github: redhat-developer/yaml-language-server for eglot to use. NOTE: Look at the github page to configure schemas for the YAML file (eg. Kubernetes schema) to do completions!

(use-package yaml-mode
  :ensure-system-package (yaml-language-server)
  :ensure t
  :hook (((yaml-mode yaml-ts-mode) . eglot-ensure))
  )

yaml schemas:

RedHat maintains a whole library of JSON schemas for it’s Github: redhat-developer/yaml-language-server to use. These need to be pulled in dynamically, so that emacs can appropriately warn/highlight/complete/document the YAML in the current buffer.

Links:

Hopefully, Github: yveszoundi/eglot-yaml solves this problem for eglot.

M-x eglot-yaml-schema-for-buffer to select a JSON schema for the current YAML buffer.

NOTE: Not in emacs package managers! Commented out for now.

;; (use-package eglot-yaml
;;   :ensure t
;;   :after (eglot)
;;   :hook ((yaml-ts-mode . eglot-yaml-init))
;;   )

RSS feeds in emacs.

An Emacs web feeds client.

(use-package elfeed
  :ensure t
  :defer t
  :bind
  (:map elfeed-search-mode-map
        ("l" . elfeed-search-tag--star))
  (:map elfeed-show-mode-map
        ("l" . elfeed-show-tag--star))
  :hook (
         (elfeed-show-mode . (lambda () (setq-local shr-width 80)))
         )
  :custom
  (elfeed-use-curl t)
  (elfeed-log-level 'debug)
  :config (setq-default word-wrap t)
  ;; (setq elfeed-log-level 'debug)
  (defun elfeed-show-tag--star ()
    (interactive)
    (elfeed-show-tag 'star))
  (defun elfeed-search-tag--star ()
    (interactive)
    (elfeed-search-toggle-all 'star))
  )

Configure the Elfeed RSS reader with an Orgmode file.

(use-package elfeed-org
  :ensure t
  :defer t
  :config
  (setq
   rmh-elfeed-org-files (list "~/org/personal/elfeed.org")
   )
  :init (elfeed-org)
  )
(use-package elfeed-protocol
  :after (elfeed elfeed-org)
  :init
  (setq
   ;; curl recommend
   elfeed-use-curl t
   elfeed-set-timeout 36000
   elfeed-curl-extra-arguments '("--insecure") ;necessary for https without a trust certificate
   ;; Setup Fever
   elfeed-protocol-update-unread-only t
   elfeed-protocol-fever-fetch-category-as-tag t
   ;; ~.authinfo.gpg~ contents: ~machine <ip/hostname> port <port> login <user> password <password>~.
   elfeed-protocol-feeds '(("fever+http://craig@192.168.0.98:8095"
                            :api-url "http://craig@192.168.0.98:8095/api/fever.php"
                            :use-authinfo t))
   )
  ;; enable elfeed-protocol
  (elfeed-protocol-enable)
  :ensure t
  :defer t
  :custom
  (
   (elfeed-protocol-log-trace t)
   (elfeed-protocol-fever-maxsize 10)
   )
  )
 (setq my-elfeed-update-timer
	(run-at-time 15 15
		     (lambda () (when (= elfeed-curl-queue-active 0)
				  (elfeed-protocol-fever-update-older "fever+http://craig@192.168.0.98:8095")))))
 (cancel-timer my-elfeed-update-timer)

Nuclear fever update:

(defun elfeed-nuclear-update ()
  (interactive)
  (cl-loop for entry in (elfeed-search-selected)
	     do (elfeed-untag-1 entry 'unread))
  (elfeed-protocol-fever-reinit "http://craig@192.168.0.98:8095")
  )
(defun elfeed-protocol-advice-rmh-elfeed-org-export-feed (headline)
 "Advice for `rmh-elfeed-org-export-feed', add elfeed-protocol ID as suffix for each feed."
  (let* ((url (car headline))
         (proto-id (car (elfeed-protocol-feed-list))))
    (when proto-id
      (setcar headline (elfeed-protocol-format-subfeed-id proto-id url)))))
(advice-add 'rmh-elfeed-org-export-feed :before #'elfeed-protocol-advice-rmh-elfeed-org-export-feed)

Update old tags on config change with: M-x elfeed-apply-hooks-now.

(use-package elfeed-autotag
  :after (elfeed elfeed-org elfeed-protocol)
  :init
  (setq elfeed-autotag-files '("~/org/personal/elfeed.org"))
  (elfeed-autotag)
  :ensure t
  :defer t
  )

Youtube integration for Elfeed, the feed reader for Emacs.

(use-package elfeed-tube
  :ensure-system-package ((mpv) (yt-dlp))
  :ensure t
  :defer t
  :after (elfeed)
  :demand t
  :config
  ;; (setq elfeed-tube-auto-save-p nil) ; default value
  ;; (setq elfeed-tube-auto-fetch-p t)  ; default value
  (elfeed-tube-setup)

  :bind (:map elfeed-show-mode-map
         ("F" . elfeed-tube-fetch)
         ([remap save-buffer] . elfeed-tube-save)))

If you want “live” captions and better MPV support:

(use-package elfeed-tube-mpv
  :ensure-system-package (mpv)
  :ensure t
  :bind (
         (:map elfeed-show-mode-map
               ("C-c C-f" . elfeed-tube-mpv-follow-mode)
               ("C-c C-w" . elfeed-tube-mpv-where)
               ("v" . elfeed-tube-mpv)
               )
         (:map elfeed-search-mode-map
               ("v" . elfeed-tube-mpv)
               )
         )
  )

A frontend for elfeed (like Mu4e Dashboard).

(use-package elfeed-dashboard
  :ensure t
  :defer t
  :config
  (setq elfeed-dashboard-file "~/org/personal/elfeed-dashboard.org")
  ;; update feed counts on elfeed-quit
  (advice-add 'elfeed-search-quit-window :after #'elfeed-dashboard-update-links))

Alternative to [[*\[\[https://github.com/manojm321/elfeed-dashboard\]\[elfeed-dashboard\]\]:][elfeed-dashboard]].

(use-package elfeed-summary
  :ensure t
  :defer t
  :custom
  (
   (elfeed-summary-default-filter "")
   (elfeed-summary-settings
    '(
      ;; (group (:title . "All feeds") (:elements (query . :all)))
      (group (:title . "Searches")
             (:elements
              (search (:filter . "+in-progress")
                      (:title . "InProgress videos"))
              (search (:filter . "+star")
                      (:title . "Starred"))
              (search (:filter . "+favourite")
                      (:title . "Favourites"))
              (search (:filter . "@1-days-ago +unread")
                      (:title . "Unread today"))
              (search (:filter . "@7-days-ago +unread")
                      (:title . "Unread entries this week"))
              (search (:filter . "@6-months-ago emacs")
                      (:title . "Something about Emacs"))))
      (group (:title . "Videos")
             (:elements
              (group
               (:title . "RPGs")
               (:elements
                (query . (and youtube solorpg))))
              (group
               (:title . "Coffee")
               (:elements
                (query . (and youtube coffee))))
              (group
               (:title . "Documentaries")
               (:elements
                (query . (and youtube documentary))))
              (group
               (:title . "Development")
               (:elements
                (query . (and youtube (design dev programming work)))))
              ))
      (group (:title . "Blogs")
             (:elements
              (group
               (:title . "RPGs")
               (:elements
                (query . (and solorpg (not youtube)))))
              (group
               (:title . "Documentaries")
               (:elements
                (query . (and documentary (not youtube)))))
              (group
               (:title . "Development")
               (:elements
                (query . (and (design dev programming work ci tech security) (not youtube)))))
              ))
      (group (:title . "All other feeds") (:elements :misc))
      ;; (group (:title . "Tags Tree")
      ;;        (:elements
      ;;         (auto-tags (:source . (query . :all)))))
      )
    )
   )
  )

FIXME: Raise bug around missing Powerline version in melpa.

Future elfeed packages to pull in:

Music:

Mingus (MPD client)

MPD references:

(use-package mingus
  :ensure t
  :defer t
  :bind
  (
   ("C-c m" . mingus)
   ("<f9>" . mingus-toggle)
   ("C-<f12>" . mingus-prev)
   ("<f12>" . mingus-next)
   )
  :custom
  (
   (mingus-mpd-host "raudio-office.local")
   )
  )

Looking to see if there are any good alternative MPD clients to mingus for controlling my remote MPD servers.

  • C-x Z Prefix
    • l Playlist.
    • N Artists.
    • : Browser.
    • C Connect to Profile. Profiles defined via: libmpdel.
    • SPC Play/Pause toggle.
(use-package mpdel
  :ensure t
  :custom
  (
   (libmpdel-hostname "raudio-office.local")
   )
  :config
  (setq libmpdel-profiles
   '(
     ("Local server" "localhost" 6600 ipv4)
     ("RAudio-Office server" "raudio-office.local" 6600 ipv4)
     ("RAudio-Office2 server" "raudio-office2.local" 6600 ipv4)
     ("Volumio-Office server" "volumio-office.local" 6600 ipv4)
     ("Volumio-Kitchen server" "volumio-kitchen.local" 6600 ipv4)
     )
   )
  (mpdel-mode)
  )

Reading:

Packages around reading (eg. novels/epubs, Speed Reading, etc).

Speed reading by line or word.

(use-package amread-mode
  :ensure t
  :commands (amread-mode)
  :custom
  (
   (amread-scroll-style 'word)
   (amread-voice-reader-language 'english)
   (amread-word-speed 10.0)  ;; WPS eg. 300WPM = 5WPS.
   )
  :custom-face
  (amread-highlight-face ((t (:background "red4" :foreground "white"))))
  )
(use-package devdocs
  :ensure t
  :defer t
  :hook (
         (c-mode . (lambda () (setq-local devdocs-current-docs '("c"))))
         (c++-mode . (lambda () (setq-local devdocs-current-docs '("cpp" "cmake~3.20"))))
         (python-mode . (lambda () (setq-local devdocs-current-docs '("python~3.9" "django~3.2" "django_rest_framework"))))
         )
  )

Emacs-based screen reader to read words when passing over them, or the whole buffer with M-< (beginning-of-buffer). Toggle with: M-x eloud-mode.

NOTE:

(use-package eloud
  :ensure t
  :ensure-system-package (espeak)
  :config
  (if (eq system-type 'darwin)
      (setq eloud-espeak-path "/usr/local/bin/espeak"))
  (setq eloud-speech-rate 350)
  )

irfc:

iRFC (Download & View RFC’s). FIXME: appears to not exist anymore.

;; (use-package irfc
;;   :ensure t
;;   :defer t
;;   :config
;;   (progn
;;     (setq
;;      irfc-directory "~/Downloads/rfcs/"
;;      irfc-assoc-mode t)
;;     )
;;   )

Reddit client. Guessing this is dead after the public API shutdown, but here is my original note: FIXME: uncomment once Debugger entered--Lisp error: (void-variable hierarchy--make) is fixed.

;; (use-package md4rd
;;   :ensure t
;;   :defer t
;;   )

nov (ereader mode - epub):

Open .epub archive and then M-x nov-mode.

(use-package nov
  :ensure t
  :mode ("\\.epub\\'" . nov-mode)
  :custom
  (nov-save-place-file "~/org/personal/nov_history")
  )

Replacement for built-in doc-view + ghostscript dependency to view PDF’s. Renders in memory, instead of storing images in an on-disk cache.

(use-package pdf-tools
  :ensure t
  :config
  (pdf-tools-install)
  )

Speed reading in a buffer by flashing each word in turn. Spritz clone for speed reading.

(use-package spray
  :ensure t
  :defer t)

Commands

In spray-mode buffers, following commands are available:

  • spray-start/stop (SPC) pause or resume spraying.
  • spray-backward-word (h, <left>) pause and back to the last word.
  • spray-forward-word (l, <right>) inverse of spray-backward-word.
  • spray-faster (f) increases speed.
  • spray-slower (s) decreases speed.
  • spray-quit (q, <return>) quit spray-mode.

sos (StackOverflow):

Stackoverflow search. FIXME: package doesn’t exist any more?

;; (use-package sos
;;   :ensure t
;;   :defer t
;;   :bind (("<f5>" . sos))
;;   )

Highlight word stems in text buffers, thereby providing artificial fixation points to improve speed reading.

(use-package stem-reading-mode
  :ensure t
  :defer t)

Terminals:

ansi-term:

ansi-term is terminal emulator. I originally preferred it to multi-term/eshell/shell, but find shell works better with paths and running of applications (eg. `aws` CLI client correctly logging in).

Code from: https://github.com/jwalgran/dotfiles/blob/master/.emacs.d/config.el

(use-package term
  :demand t
  :bind (("<f2>" . visit-ansi-term)
         ;; Note: gdb keybinding is: C-x C-a C-l, which I did have my rename term windows as.
         ;; ("C-x C-a" . open-term)
         )
  :init
  (progn
    ;; https://github.com/ahinz/emacs-config/blob/7e025076097f045aea2a0aedd0523ee996753346/.emacs.d/ah-modes.el#L268
    (defun open-named-term (new-buffer-name cmd &rest switches)
      (setq term-ansi-buffer-name (generate-new-buffer-name new-buffer-name))
      (setq term-ansi-buffer-name (apply 'make-term term-ansi-buffer-name cmd nil switches))
      (set-buffer term-ansi-buffer-name)
      (term-mode)
      (term-char-mode)
      (term-set-escape-char ?\C-x)
      (switch-to-buffer term-ansi-buffer-name))

    ;; https://github.com/ahinz/emacs-config/blob/7e025076097f045aea2a0aedd0523ee996753346/.emacs.d/ah-modes.el#L268
    (defun open-term (name)
      (interactive "sName: ")
      (open-named-term name "/bin/bash"))

    (defun visit-ansi-term ()
      "If the current buffer is:
         1) a running ansi-term named *ansi-term*, rename it.
         2) a stopped ansi-term, kill it and create a new one.
         3) a non ansi-term, go to an already running ansi-term
            or start a new one while killing a defunt one"
      (interactive)
      (let ((is-term (string= "term-mode" major-mode))
            (is-running (term-check-proc (buffer-name)))
            (term-cmd "/bin/bash")
            (anon-term (get-buffer "*ansi-term*")))
        (if is-term
            (if is-running
                (if (string= "*ansi-term*" (buffer-name))
                    (call-interactively 'rename-buffer)
                  (if anon-term
                      (switch-to-buffer "*ansi-term*")
                    (ansi-term term-cmd)))
              (kill-buffer (buffer-name))
              (ansi-term term-cmd))
          (if anon-term
              (if (term-check-proc "*ansi-term*")
                  (switch-to-buffer "*ansi-term*")
                (kill-buffer "*ansi-term*")
                (ansi-term term-cmd))
            (ansi-term term-cmd)))))

    ;; Make ansi-term buffers close when you kill the shell process
    (defun term-sentinel--my-advice-term-sentinel (proc msg)
      (if (memq (process-status proc) '(signal exit))
          (let ((buffer (process-buffer proc)))
            ad-do-it
            (kill-buffer buffer))
        ad-do-it))
    (advice-add 'term-sentinel :around #'my-advice-term-sentinel)
    )

  (add-hook 'ansi-term-hook (lambda () (global-hl-line-mode 0)))  ; http://stackoverflow.com/questions/9990370/how-to-disable-hl-line-feature-in-specified-mode
  )

eshell (builtin):

Add the following programs to the list of programs that eshell won’t complain about not being a proper terminal. This will move out of line-mode and into paging mode (eg. like scrolling through a man page on a real terminal). See:

NOTE: This will use ansi-term for those command calls, so can use: C-xC-j, and: C-cC-k, to jump in and out of editing mode.

Bindings:

  • C-p / C-n to move up/down by line.
  • C-cC-p / C-cC-n to move up/down to each input/prompt.
(use-package eshell
  :ensure t
  :config
  (setq eshell-history-size 1000000)
  (with-eval-after-load 'em-term
    (add-to-list 'eshell-visual-commands "aws"))
  )

vterm:

Vterm is a terminal with pretty good ncurses support and compliance.

NOTES: Requires cmake installed on the system to compile!!

  • C-cC-t to enter/exit copy-mode.
(use-package vterm
  :if (not (eq system-type 'windows-nt))  ;; FIXME: compiling on Windows.
  :ensure-system-package (cmake)
  :ensure t
  :after (cmake-mode)
  :init (setq vterm-always-compile-module t)
  :config (setq vterm-max-scrollback 100000)
  )

Typing:

Touch typing practice. Call: M-x speed-type-text.

(use-package speed-type
  :ensure t
  :defer t)

Emacs Monkeytype is a typing game/tutor inspired by monkeytype.com but for Emacs.

  • M-x monkeytype-<buffer|region>.
  • M-x monkeytype-stop or C-cC-cs.
(use-package monkeytype
  :ensure t
  :defer t
  :config
  (setq
   ;; How often to update mode-line
   monkeytype-mode-line-interval-update 10
   ;; Use space instead or newline
   monkeytype-treat-newline-as-space t
   ;; Minimum amount of transitions for test
   ;; If not enough repeat them
   monkeytype-minimum-transitions 50
   ;; Inserts debugging log, this can take a while
   ;; if typing text is too long.
   monkeytype-insert-log nil
   ;; Default directory for saving Monkeytype data
   monkeytype-directory "~/.monkeytype"
   ;; Format for time-stamped files for saving.
   monkeytype-file-name "%a-%d-%b-%Y-%H-%M-%S"
   ;; Toggle randomise text
   monkeytype-randomize t
   ;; Toggle downcase text
   monkeytype-dowcase t
   ;; Amount of words for most mistyped words test
   monkeytype-most-mistyped-amount 100
   ;; Toggle auto-fill on typing text
   monkeytype-auto-fill nil
   ;; Toggle auto-fill on words related typing text
   monkeytype-words-auto-fill t
   ;; Toggle auto deletion of trailing white space
   monkeytype-delete-trailing-whitespace t
   ;; Regexp used to divide and extracts words
   monkeytype-excluded-chars-regexp "[^[:alnum:]']"
   ;; Toggle converting downloaded text to ASCII
   monkeytype-asciify t
   )
  )

Unsorted:

Create visual menu’s like what `magit` provides, but easily customised.

(use-package hydra :ensure t)

Video:

Search YouTube from emacs, play via mpv, download via yt-dlp.

(use-package yeetube
  :ensure
  :ensure-system-package ((wget))
  :custom
  (yeetube-display-thumbnails nil)
  (yeetube-results-limit 50)
  )

Web:

Run up a rest client in emacs to quickly test APIs. See:

Eg. Run (C-cC-c) the following in an empty buffer with restclient-mode on:

GET https://api.github.com
User-Agent: Emacs Restclient
(use-package restclient
  :ensure t
  :defer t
  :mode ("\\.restclient\\'" . restclient-mode)
  )

ob-restclient:

Add restclient support to org-babel code blocks.

Eg. Run (C-cC-c) the following code block.

GET https://api.github.com
User-Agent: Emacs Restclient
(use-package ob-restclient
  :ensure t
  :after (restclient)
  :config
  (add-to-list 'org-babel-load-languages '(restclient . t))
  (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)
  )

Links:

Configs:

Configs that look good enough to go back and maybe learn/steal from:

Packages to try:

About

My main .emacs file.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages