Skip to content

Not another Doom emacs config...except this one is blatantly plagiarised from tecosaur

Notifications You must be signed in to change notification settings

dylanbmorgan/dylan-doom-config

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Doom Emacs Literate Config

Table of Contents

Introduction

GNU Emacs is an extendable and highly customisable text editor. It is based on an Emacs Lisp interpreter with extensions for text editing. Emacs has been extended in essentially all areas of computing, giving rise to a vast array of packages supporting, e.g., email, IRC and XMPP messaging, spreadsheets, remote server editing, and much more. Emacs includes extensive documentation on all aspects of the system, from basic editing to writing large Lisp programs. It has full Unicode support for nearly all human languages.

Installation Instructions

  1. cd ~/.doom.d/
  2. Install the necessary programs when you inevitably get lots of errors!
  3. Waste lots of time learning how to use emacs, tweaking the configuration yourself, get frustrated, and ultimately return to using vim or VScode

Use-package guide

Setup

Lexical Binding

I think this has to go at the top of the file (almost like a shebang)

;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-

Buffers

  • I’d much rather have my new buffers in org-mode than fundamental-mode
  • Nicer default buffer names
  • Only include the buffer name in the title, and then if applicable, the project folder
    • Also mark if the file has unsaved changes
;; (setq-default major-mode 'org-mode)

(setq doom-fallback-buffer-name "► Doom"
      +doom-dashboard-name "► Doom")

(setq frame-title-format
      '(""
        (:eval
         (if (s-contains-p org-roam-directory (or buffer-file-name ""))
             (replace-regexp-in-string
              ".*/[0-9]*-?" ""
              (subst-char-in-string ?_ ?  buffer-file-name))
           "%b"))
        (:eval
         (let ((project-name (projectile-project-name)))
           (unless (string= "-" project-name)
             (format (if (buffer-modified-p)  " ◉ %s" "  ●  %s") project-name))))))

Calculator

Set a keybinding for the Emacs calculator

(map! :leader
      (:prefix ("a" . "Calculator")
       :desc "Calculator" "c" #'calc
       :desc "Reset" "R" #'calc-reset))

ChatGPT

For now the ChatGPT API is paid for so I cannot use these but I’ll keep the configuration here

ChatGPT-Shell

Lazy load API key

(setq chatgpt-shell-openai-key
      (lambda ()
        (auth-source-pick-first-password :host "api.openai.com")))

Org-AI

Add a querying keybind for the chatgpt package I’m using

(use-package! org-ai
  :commands
  (org-ai-mode
   org-ai-global-mode)
  :init
  (add-hook 'org-mode-hook #'org-ai-mode) ; enable org-ai in org-mode
  (org-ai-global-mode) ; installs global keybindings on C-c M-a
  :config
  (setq org-ai-default-chat-model "gpt-4o") ; if you are on the gpt-4 beta:
  (org-ai-install-yasnippets)) ; if you are using yasnippet and want `ai` snippets

  ;; Use the default bindings but change the leader
  ;; (map! :leader
  ;;       :prefix ("a" . "ai")
  ;;       :desc "Start on project" "p" #'org-ai-on-project
  ;;       :desc "Open prompt" "P" #'org-ai-prompt-in-new-buffer
  ;;       :desc "AI on region" "r" #'org-ai-on-region
  ;;       :desc "Refactor code" "c" #'org-ai-refactor-code
  ;;       :desc "Summarise marked text" "s" #'org-ai-summarize
  ;;       :desc "Switch chat model" "m" #'org-ai-switch-chat-model
  ;;       :desc "URL request buffer" "!" #'org-ai-open-request-buffer
  ;;       :desc "Account usage" "$" #'org-ai-open-account-usage-page
  ;;       :desc "Speech input" "t" #'org-ai-talk-input-toggle
  ;;       :desc "Speech output" "T" #'org-ai-talk-output-toggle
  ;;       :desc "Read region" "R" #'org-ai-talk-read-region
  ;;       :desc "Mark prompt at point" "SPC" #'org-ai-mark-region-at-point))

Delays

I like to have custom delays for company mode, the leader key, and the spell checker:

(setq which-key-idle-delay 0.2)

(setq company-idle-delay 0.3
      company-maximum-prefix-length 3)

(after! spell-fu
  (setq spell-fu-idle-delay 0.5))

Deft

(setq deft-directory "~/Documents/deft/")

Ellama

(use-package! ellama
  :defer t
  :init
  (setopt ellama-keymap-prefix "C-c e"))

Eval

Enable inline evaluation of code, but use a nicer prefix

(setq eros-eval-result-prefix "") ; default =>

Evil

When I want to make a substitution, I want it to be global more often than not — so let’s make that the default.

(after! evil
  (setq evil-ex-substitute-global t     ; I like my s/../.. to by global by default
        evil-move-cursor-back nil       ; Don't move the block cursor when toggling insert mode
        evil-kill-on-visual-paste nil)) ; Don't put overwritten text in the kill ring

File types

Ebooks

Integrate books into emacs

(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))

General

  • Let Emacs know I am using fish as my default shell
  • Delete files to trash
  • Stretch cursor to the glyph width
  • Raise undo limit to 80MB
  • Whether actions are undone in several steps
  • Nobody likes to lose work
  • How many seconds passwords are cached
  • Controls if scroll commands move point to keep its screen position unchanged
  • Number of lines of margin at the top and bottom of a window
  • Show traceback on error
  • Iterate through CamelCase words
  • Replace I-search binding with swiper
  • Include a ‘leader-undo’ button
  • Visual fix for indent guides
  • Disable massive toolbar on MacOS
(setq shell-file-name (executable-find "bash"))
(setq vterm-shell (executable-find "fish"))
(setq explicit-shell-file-name (executable-find "fish"))

(setq delete-by-moving-to-trash t
      x-stretch-cursor t)

(setq undo-limit 80000000
      evil-want-fine-undo t
      auto-save-default t
      password-cache-expiry 300
      scroll-preserve-screen-position 'always
      scroll-margin 4)
      ;; debug-on-error t)

(global-subword-mode t)

(map! "C-s" #'swiper)
(map! "C-M-s" #'swiper-thing-at-point)
(map! "C-S-s" #'isearch-forward-regexp)
(map! "C-S-r" #'isearch-backward-regexp)

;; TODO
;; (map! which-key-mode-map
;;       "DEL" #'which-key-undo)

;; (after! highlight-indent-guides
;;   (highlight-indent-guides-auto-set-faces))

(when (string= (system-name) "maccie")
  (add-hook 'doom-after-init-hook (lambda () (tool-bar-mode 1) (tool-bar-mode 0))))

gptel

(use-package! gptel
  :commands gptel gptel-menu gptel-mode gptel-send gptel-set-tpic
  :config
  ;;  (setq! gptel-api-key "your key"))
  (setq gptel-model "zephyr:latest"
        gptel-backend (gptel-make-ollama "Ollama"
                        :host "localhost:11434"
                        :stream t
                        :models '("zephyr:latest"))))

(add-hook 'gptel-post-stream-hook 'gptel-auto-scroll)
(add-hook 'gptel-post-response-functions 'gptel-end-oF-response) ; TODO Bind key to end of response

Languagetool

Lines

This determines the style of line numbers in effect. If set to `nil’, line numbers are disabled. For relative line numbers, set this to `relative’.

Automatically wrap text when it reaches the end of the screen

(setq display-line-numbers-type 'relative)

(add-hook 'text-mode-hook 'turn-on-visual-line-mode)
(setq visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow))

;; (setq-default auto-fill-function 'do-auto-fill)

Personal Information

Some functionality uses this to identify you, e.g. GPG configuration, email clients, file templates, and snippets.

Set the GPG directories and increase the cache expiry

(setq user-full-name "Dylan Morgan"
      user-mail-address "dbmorgan98@gmail.com")

(setq auth-sources '("~/.authinfo.gpg" "authinfo")
      auth-source-cache-expiry 21600) ; Change default to 6 hours to get me through most of a work day

Projectile

Change the default sort order so it lists the most recent files and directories opened first and enable project caching

(setq projectile-sort-order 'recentf
      projectile-auto-discover t)

(setq projectile-enable-caching t)
(setq projectile-file-exists-remote-cache-expire (* 10 60))

(map! :leader
      (:prefix-map ("p" . "project")
       :desc "Search project rg" "h" #'counsel-projectile-rg))

(map! :leader
      (:prefix-map ("p" . "project")
       :desc "Search project ag" "H" #'counsel-projectile-ag))

Spelling

My spelling is really bad so it needs checkling

(after! spell-fu
  (setq ispell-personal-dictionary "~/.config/emacs/.local/etc/ispell/.pws")
  (setq ispell-dictionary "en_GB"))

(use-package! jinx
  :defer t
  :init
  (add-hook 'doom-init-ui-hook #'global-jinx-mode)
  :config
  (setq jinx-languages "en_GB")
  ;; Extra face(s) to ignore
  (push 'org-inline-src-block
        (alist-get 'org-mode jinx-exclude-faces)))
;;   ;; Take over the relevant bindings.
;;   (after! ispell
;;     (global-set-key [remap ispell-word] #'jinx-correct))
;;   (after! evil-commands
;;     (global-set-key [remap evil-next-flyspell-error] #'jinx-next)
;;     (global-set-key [remap evil-prev-flyspell-error] #'jinx-previous))

systemd

Use emacs as a client.

Setup the systemd file here

#+name emacsclient service

[Unit]
Description=Emacs server daemon
Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
Wants=gpg-agent.service

[Service]
Type=forking
ExecStart=fish -c '/home/dylanmorgan/Applications/emacs-29.3/build/src/emacs --daemon && /home/dylanmorgan/Applications/emacs-29.3/build/lib-src/emacsclient -c --eval "(delete-frame)"'
ExecStop=/home/dylanmorgan/Applications/emacs-29.3/build/lib-src/emacsclient --no-wait --eval "(progn (setq kill-emacs-hook nil) (kill emacs))"
Environment=COLORTERM=truecolor
Restart=on-failure

[Install]
WantedBy=default.target

which is then enabled by

systemctl --user enable emacs.service

For some reason if a frame isn’t opened early in the initialisation process, the daemon doesn’t seem to like opening frames later — hence the && emacsclient part of the ExecStart value.

It can now be nice to use this as a ‘default app’ for opening files. If we add an appropriate desktop entry, and enable it in the desktop environment.

[Desktop Entry]
Name=Emacs client
GenericName=Text Editor
Comment=A flexible platform for end-user applications
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
Exec=/home/dylanmorgan/Applications/emacs-29.3/build/lib-src/emacsclient -create-frame --alternate-editor="" --no-wait %F
Icon=emacs
Type=Application
Terminal=false
Categories=TextEditor;Utility;
StartupWMClass=Emacs
Keywords=Text;Editor;
X-KDE-StartupNotify=false

Lastly, while I’m not sure quite why it happens, but after a bit it seems that new Emacsclient frames start on the *scratch* buffer instead of the dashboard. I prefer the dashboard, so let’s ensure that’s always switched to in new frames.

Treemacs

To enable bidirectional synchronisation of LSP workspace folders and treemacs projects.

(lsp-treemacs-sync-mode 1)
;; (add-hook 'projectile-find-file-hook #'+treemacs/toggle 'append)
;; (add-hook 'projectile-find-file-hook #'treemacs-select-window 'append)

General settings

(use-package! treemacs
  :defer t
  :config
  (progn
    (setq treemacs-eldoc-display                   'detailed
          treemacs-find-workspace-method           'find-for-file-or-pick-first
          treemacs-missing-project-action          'remove
          treemacs-move-forward-on-expand          t
          treemacs-project-follow-cleanup          t
          treemacs-indent-guide-style              'line
          treemacs-recenter-distance               0.2
          treemacs-recenter-after-file-follow      'always
          treemacs-recenter-after-tag-follow       'always
          treemacs-recenter-after-project-jump     'always
          treemacs-recenter-after-project-expand   'always
          treemacs-project-follow-into-home        t
          treemacs-show-hidden-files               nil
          treemacs-sorting                         'alphabetic-numeric-case-insensitive-asc
          treemacs-select-when-already-in-treemacs 'next-or-back
          treemacs-tag-follow-delay                1.0
          treemacs-width-increment                 5)

    ;; The default width and height of the icons is 22 pixels. If you are
    ;; using a Hi-DPI display, uncomment this to double the icon size.
    ;;(treemacs-resize-icons 44)
    (treemacs-follow-mode t)
    (treemacs-project-follow-mode t)
    (treemacs-filewatch-mode t)
    (treemacs-fringe-indicator-mode 'always)
    (treemacs-indent-guide-mode t)
    (when treemacs-python-executable
      (treemacs-git-commit-diff-mode t))

    (pcase (cons (not (null (executable-find "git")))
                 (not (null treemacs-python-executable)))
      (`(t . t)
       (treemacs-git-mode 'deferred))
      (`(t . _)
       (treemacs-git-mode 'simple))))

  ;; :bind
  (map! :nvi "M-0" nil)  ; unbind from go to last workspace
  (map! "M-0" #'treemacs-select-window))
  ;;       ("C-x t 1"   . treemacs-delete-other-windows)
  ;;       ("C-x t t"   . treemacs)
  ;;       ("C-x t d"   . treemacs-select-directory)
  ;;       ("C-x t B"   . treemacs-bookmark)
  ;;       ("C-x t C-t" . treemacs-find-file)
  ;;       ("C-x t M-t" . treemacs-find-tag)))

Tramp

Faster than the default scp (for small files)

(setq tramp-default-method "ssh")

Improve tramp prompt recognition

(after! tramp
  (setenv "SHELL" "/bin/bash")
  (setq tramp-shell-prompt-pattern "\\(?:^\\|\n\\|\x0d\\)[^]#$%>\n]*#?[]#$%>] *\\(\e\\[[0-9;]*[a-zA-Z] *\\)*")) ;; default + 

Web

Default to opening links in emacs webkit

(setq browse-url-browser-function 'xwidget-webkit-browse-url)

Windows

Moom

Moom is a package for manipulating the size and location of the actual emacs window. This is particularly useful on my mac.

Firstly, set the default margin

;; (setq moom-user-margin '(50 50 50 50)) ; {top, bottom, left, right}
;; (moom-mode 1)

Within Emacs

  • Make Doom emacs ask which buffer to see after splitting a window.
  • Take new window space from all other windows (not just current).
  • Window rotation is nice, and can be found under SPC w r and SPC w R.
    • Layout rotation is also nice though. Let’s stash this under SPC w a.
  • We could also do with adding the missing arrow-key variants of the window navigation/swapping commands.
  • I also like to be able to preview buffers when I switch them.
(setq evil-vsplit-window-right t
      evil-split-window-below t)

(defadvice! prompt-for-buffer (&rest _)
  :after '(evil-window-split evil-window-vsplit)
  (counsel-buffer-or-recentf))

(setq window-combination-resize t)

(map! :map evil-window-map
      "SPC" #'rotate-layout
      ;; Navigation
      "<left>"     #'evil-window-left
      "<down>"     #'evil-window-down
      "<up>"       #'evil-window-up
      "<right>"    #'evil-window-right
      ;; Swapping windows
      "C-<left>"       #'+evil/window-move-left
      "C-<down>"       #'+evil/window-move-down
      "C-<up>"         #'+evil/window-move-up
      "C-<right>"      #'+evil/window-move-right)

;; (map! :map switch-workspace-buffer)
;; (map! :leader
;;       (:prefix-map ("," . "Switch buffer")
;;        :desc "Search project rg" "h" #'counsel-projectile-rg))

(map! :leader
      :desc "Switch buffer" "," #'counsel-switch-buffer
      :desc "Switch workspace buffer" "\\" #'persp-switch-to-buffer)

Yasnippets

Enable nested snippets

(setq yas-triggers-in-field t)

Smart parentheses

(sp-local-pair
 '(org-mode)
 "<<" ">>"
 :actions '(insert))

Appearance

Fonts

Doom exposes five (optional) variables for controlling fonts in Doom. Here are the three important ones:

  • `doom-font’
  • `doom-variable-pitch-font’
  • `doom-big-font’ – used for `doom-big-font-mode’
    • use this for presentations or streaming.

They all accept either a font-spec, font string (“Input Mono-12”), or xlfd font string. You generally only need doom-font and doom-variable-pitch-font.

(setq doom-font (font-spec :family "FiraCode Nerd Font" :size 16)
      doom-big-font (font-spec :family "FiraCode Nerd Font" :size 22))
      ;; doom-variable-pitch-font (font-spec :family "InputMonoNarrow Nerd Font" :size 18))
      ;; doom-serif-font (font-spec :family "Droid*Sans*M*" :size 16 :weight 'light))

Use LaTeX as the default input method to type special characters

(after! text-mode
  (set-input-method 'TeX))

Disable prettify symbols globally

(setq global-prettify-symbols-mode nil)

Minimap

Display the minimap (doesn’t work well with org files \therefore disabled)

;; (setq minimap-mode 0)

Modeline

Adjust some settings

(display-time-mode 1) ; Show the time
(size-indication-mode 1) ; Info about what's going on
(setq display-time-default-load-average nil) ; Hide the load average
(setq all-the-icons-scale-factor 1.2) ; prevent the end of the modeline from being cut off

Alter the colour of the filename in the buffer when modifications have been made to a file

(custom-set-faces!
  '(doom-modeline-buffer-modified :foreground "orchid2"))

Conditionally hide the encoding

(defun doom-modeline-conditional-buffer-encoding ()
  "We expect the encoding to be LF UTF-8, so only show the modeline when this is not the case"
  (setq-local doom-modeline-buffer-encoding
              (unless (and (memq (plist-get (coding-system-plist buffer-file-coding-system) :category)
                                 '(coding-category-undecided coding-category-utf-8))
                           (not (memq (coding-system-eol-type buffer-file-coding-system) '(1 2))))
                t)))

(add-hook 'after-change-major-mode-hook #'doom-modeline-conditional-buffer-encoding)

Alter the modeline for viewing PDFs

(after! doom-modeline
  (doom-modeline-def-segment buffer-name
    "Display the current buffer's name, without any other information."
    (concat
     (doom-modeline-spc)
     (doom-modeline--buffer-name)))

  (doom-modeline-def-segment pdf-icon
    "PDF icon from all-the-icons."
    (concat
     (doom-modeline-spc)
     (doom-modeline-icon 'octicon "file-pdf" nil nil
                         :face (if (doom-modeline--active)
                                   'all-the-icons-red
                                 'mode-line-inactive)
                         :v-adjust 0.02)))

  (defun doom-modeline-update-pdf-pages ()
    "Update PDF pages."
    (setq doom-modeline--pdf-pages
          (let ((current-page-str (number-to-string (eval `(pdf-view-current-page))))
                (total-page-str (number-to-string (pdf-cache-number-of-pages))))
            (concat
             (propertize
              (concat (make-string (- (length total-page-str) (length current-page-str)) ? )
                      " P" current-page-str)
              'face 'mode-line)
             (propertize (concat "/" total-page-str) 'face 'doom-modeline-buffer-minor-mode)))))

  (doom-modeline-def-segment pdf-pages
    "Display PDF pages."
    (if (doom-modeline--active) doom-modeline--pdf-pages
      (propertize doom-modeline--pdf-pages 'face 'mode-line-inactive)))

  (doom-modeline-def-modeline 'pdf
    '(bar window-number pdf-pages pdf-icon buffer-name)
    '(misc-info matches major-mode process vcs)))

Splash Screen

  • Change this to an SVG image

Not to toot my own trumpet, but I like this pretty cool splash screen that I made

(setq fancy-splash-image "~/.doom.d/splash/black-doom-hole.png")

Tabs

(after! centaur-tabs
  (centaur-tabs-mode -1)
  (setq centaur-tabs-set-icons t
        ;; centaur-tabs-style "wave"
        ;; centaur-tabs-set-modified-marker t
        centaur-tabs-modified-marker "o"
        centaur-tabs-close-button "×"
        centaur-tabs-set-bar 'left
        centaur-tabs-gray-out-icons 'buffer))
  ;; (centaur-tabs-change-fonts "P22 Underground Book" 160))
;; (setq x-underline-at-descent-line t)

Theme

There are two ways to load a theme. Both assume the theme is installed and available. You can either set `doom-theme’ or manually load a theme with the `load-theme’ function. The default is doom-one.

I’ve found a few themes I like, so here we will load a random one on opening emacs

Also add blur and opacity (blur doesn’t work)

;; (use-package autothemer

(defun random-choice (items)
  (let* ((size (length items))
         (index (random size)))
    (nth index items)))

(setq random-theme (random-choice '(doom-dracula doom-palenight doom-one)))

;; (setq random-theme (random-choice '(doom-dracula doom-snazzy doom-palenight doom-moonlight doom-vibrant doom-laserwave doom-horizon doom-one doom-city-lights doom-wilmersdorf catppuccin-1 catppuccin-2))) ; doom-tokyo-night)))

(cond ((string= random-theme "catppuccin-1") (setq doom-theme 'catppuccin-macchiato))
      ((string= random-theme "catppuccin-2") (setq doom-theme 'catppuccin-frappe))
      (t (setq doom-theme random-theme)))

;; (set-frame-parameter (selected-frame) 'alpha '(85 . 50))
;; (add-to-list 'default-frame-alist '(alpha . (85 . 50)))

(doom/set-frame-opacity 100)
;; (doom/set-frame-opacity 95)
;; (doom/set-frame-opacity 85)

Languages

General

Github Copilot

Firstly unbind aya-create from C-TAB

(map! :nvi "C-TAB" nil)
(map! :nvi "C-<tab>" nil)

Then define the keybindings to use for Github copilot

;; accept completion from copilot and fallback to company
(use-package! copilot
  :defer t
  :hook ((prog-mode . copilot-mode)
         (sh-mode . copilot-mode))
  :bind (:map copilot-completion-map
              ("C-S-<iso-lefttab>" . 'copilot-accept-completion-by-word)
              ("C-S-<tab>" . 'copilot-accept-completion-by-word)
              ("C-TAB" . 'copilot-accept-completion-by-line)
              ("C-<tab>" . 'copilot-accept-completion-by-line)
              ("C-M-TAB" . 'copilot-accept-completion)
              ("C-M-<tab>" . 'copilot-accept-completion)))
  ;; :config
  ;; (when (string= (system-name) "apollo")
  ;;   (setq copilot-node-executable "~/.local/share/nvm/v17.9.1/bin/node"))
  ;; (when (string= (system-name) "maccie")
  ;;   (setq copilot-node-executable "/Users/dylanmorgan/.local/share/nvm/v17.9.1/bin/node")))

(map! :leader
      :desc "Toggle Copilot" "c g" #'copilot-mode)

Rainbow Delimiters

Better syntax highlighting for code

(add-hook! 'prog-mode-hook #'rainbow-delimiters-mode)
(add-hook! 'sh-mode-hook #'rainbow-delimiters-mode)

Visual Line Mode

Enable word wrapping almost everywhere

(+global-word-wrap-mode +1)
;; (add-hook! 'prog-mode-hook #'+word-wrap-mode)
;; (add-hook! 'sh-mode-hook #'+word-wrap-mode)

Docker

Setup lsp-docker

;; Uncomment the next line if you are using this from source
;; (add-to-list 'load-path "<path-to-lsp-docker-dir>")

;; (require 'lsp-docker)

;; (defvar lsp-docker-client-packages
;;     '(lsp-css lsp-clients lsp-bash lsp-go lsp-html lsp-typescript ; ruff-lsp
;;       lsp-terraform lsp-clangd))

;; (setq lsp-docker-client-configs
;;     '((:server-id bash-ls :docker-server-id bashls-docker :server-command "bash-language-server start")
;;       (:server-id clangd :docker-server-id clangd-docker :server-command "clangd")
;;       (:server-id css-ls :docker-server-id cssls-docker :server-command "css-languageserver --stdio")
;;       ;; (:server-id dockerfile-ls :docker-server-id dockerfilels-docker :server-command "docker-langserver --stdio")
;;       (:server-id gopls :docker-server-id gopls-docker :server-command "gopls")
;;       (:server-id html-ls :docker-server-id htmls-docker :server-command "html-languageserver --stdio")))
;;       ;; (:server-id ruff-lsp :docker-server-id pyls-docker :server-command "pyls")))
;;       ;; (:server-id ts-ls :docker-server-id tsls-docker :server-command "typescript-language-server --stdio")))

;; (require 'lsp-docker)
;; (lsp-docker-init-clients
;;   :path-mappings '(("path-to-projects-you-want-to-use" . "~/Programming/projects /"))
;;   :client-packages lsp-docker-client-packages
;;   :client-configs lsp-docker-client-configs)

Magit

Add keybindings to push to remote and view diffs.

(map! :leader
      :desc "Magit pull" "g p" #'magit-pull
      :desc "Magit push" "g P" #'magit-push
      :desc "Magit diff" "g d" #'magit-diff
      :desc "Magit stash" "g z" #'magit-stash
      :desc "Magit stage all" "g a" #'magit-stage-modified
      :desc "Magit unstage all" "g A" #'magit-unstage-all)

Bash

Default Scripting Shell

Always use the bash shell for scripting

(after! sh-mode
  (sh-set-shell "bash"))
  ;; (when (equal (string-match-p (regexp-quote "*PKGBUILD")
  ;;                              (buffer-file-name))
  ;;              "PKGBUILD")
  ;;   (sh-set-shell "bash")))

Tab Spacing

Set default tab width to 2:

(after! sh-mode
  (setq sh-indentation
        sh-basic-offset 2))

Fortran

General

Set indentation for fortran and f90

(after! f90
  (setq f90-do-indent 2)
  (setq f90-if-indent 2)
  (setq f90-type-indent 2)
  (setq f90-program-indent 2)
  (setq f90-continuation-indent 4)
  (setq f90-smart-end 'blink)

  ;; TODO: copy rc params file from apollo to mac
  (set-formatter! 'fprettify '("fprettify" "-i 2" "-l 88" "-w 4" "--whitespace-comma=true" "--whitespace-assignment=true" "--whitespace-decl=true" "--whitespace-relational=true" "--whitespace-plusminus=true" "--whitespace-multdiv=true" "--whitespace-print=true" "--whitespace-type=true" "--whitespace-intrinsics=true" "--strict-indent" "--enable-decl" "--enable-replacements" "--c-relations" "--case 1 1 1 1" "--strip-comments" "--disable-fypp") :modes '(f90-mode fortran-mode)))

(after! fortran
  (setq fortran-continuation-string "&")
  (setq fortran-do-indent 2)
  (setq fortran-if-indent 2)
  (setq fortran-structure-indent 2)

  (set-formatter! 'fprettify '("fprettify" "-i 2" "-l 88" "-w 4" "--whitespace-comma=true" "--whitespace-assignment=true" "--whitespace-decl=true" "--whitespace-relational=true" "--whitespace-plusminus=true" "--whitespace-multdiv=true" "--whitespace-print=true" "--whitespace-type=true" "--whitespace-intrinsics=true" "--strict-indent" "--enable-decl" "--enable-replacements" "--c-relations" "--case 1 1 1 1" "--strip-comments" "--disable-fypp") :modes '(f90-mode fortran-mode)))

Set Fortran and Fortran 90 mode for appropriate extensions

(setq auto-mode-alist
      (cons '("\\.F90$" . f90-mode) auto-mode-alist))
(setq auto-mode-alist
      (cons '("\\.f90$" . f90-mode) auto-mode-alist))
(setq auto-mode-alist
      (cons '("\\.pf$" . f90-mode) auto-mode-alist))
(setq auto-mode-alist
      (cons '("\\.pf$" . f90-mode) auto-mode-alist))
(setq auto-mode-alist
      (cons '("\\.fpp$" . f90-mode) auto-mode-alist))
(setq auto-mode-alist
      (cons '("\\.F$" . fortran-mode) auto-mode-alist))
(setq auto-mode-alist
      (cons '("\\.f$" . fortran-mode) auto-mode-alist))

LSP

(use-package! lsp-mode
  :hook (f90-mode . lsp-deferred))

Julia

LSP

Automatically start when opening a julia file

;; (use-package! eglot-jl
;;   :defer  t)

(use-package! julia-mode
  :defer t
  :init
  (setenv "JULIA_NUM_THREADS" "6")
  :interpreter ("julia" . julia-mode))

  ;; :config
  ;; (add-hook 'julia-mode-hook 'eglot-jl-init)
  ;; (add-hook 'julia-mode-hook 'eglot-ensure))

(add-hook! 'julia-mode-hook #'lsp-mode)

Julia-lsp doesn’t work without this

(after! julia-mode
  (add-hook 'julia-mode-hook #'rainbow-delimiters-mode-enable)
  (add-hook! 'julia-mode-hook
    (setq-local lsp-enable-folding t
                lsp-folding-range-limit 100)))

Change directory for LanguageServer.jl and SymbolServer.jl

;; (use-package! lsp-julia
;;   :config)
;;   (setq lsp-julia-default-environment "~/.julia/environments/v1.8"))

LaTeX

Biblio

(setq! bibtex-completion-bibliography '("~/Documents/warwick/thesus/references.bib"))

CDLaTeX

Set new environments for:

  • Non-numbered equations
  • Non-numbered equations with bmatrix

Then, set shortcuts for these environments

Also make some additions/modifications to the maths symbol alist

(eval-after-load 'latex
                 '(define-key LaTeX-mode-map [(tab)] 'cdlatex-tab))

(after! tex-mode
  (setq cdlatex-env-alist
        '(("non-numbered equation" "\\begin{equation*}\n    ?\n\\end{equation*}" nil)
          ("equation" "\\begin{equation} \\label{?}\n    \n\\end{equation}" nil) ; This might not work
          ("bmatrix" "\\begin{equation*}\n    ?\n    \\begin{bmatrix}\n        \n    \\end{bmatrix}\n\\end{equation*}" nil)
          ("vmatrix" "\\begin{equation*}\n    ?\n    \\begin{vmatrix}\n        \n    \\end{vmatrix}\n\\end{equation*}" nil)
          ("pmatrix" "\\begin{equation*}\n    ?\n    \\begin{pmatrix}\n        \n    \\end{pmatrix}\n\\end{equation*}" nil)
          ("split" "\\begin{equation} \\label{?}\n    \\begin{split}\n        \n    \\end{split}\n\\end{equation}" nil)
          ("non-numbered split" "\\begin{equation*}\n    \\begin{split}\n        ?\n    \\end{split}\n\\end{equation*}" nil)))
  (setq cdlatex-command-alist
        '(("neq" "Insert non-numbered equation env" "" cdlatex-environment ("non-numbered equation") t nil)
          ("equ" "Insert numbered equation env" "" cdlatex-environment ("equation") t nil) ; This might not work
          ("bmat" "Insert bmatrix env" "" cdlatex-environment ("bmatrix") t nil)
          ("vmat" "Insert vmatrix env" "" cdlatex-environment ("vmatrix") t nil)
          ("pmat" "Insert pmatrix env" "" cdlatex-environment ("pmatrix") t nil)
          ("spl" "Insert split env" "" cdlatex-environment ("split") t nil)
          ("nspl" "Insert non-numbered split env" "" cdlatex-environment ("non-numbered split") t nil)))
  (setq cdlatex-math-symbol-alist
        '((?= ("\\equiv" "\\leftrightarrow" "\\longleftrightarrow"))
          (?! ("\\neq"))
          (?+ ("\\cup" "\\pm"))
          (?^ ("\\uparrow" "\\downarrow"))
          (?: ("\\cdots" "\\vdots" "\\ddots"))
          (?b ("\\beta" "\\mathbb{?}"))
          (?i ("\\in" "\\implies" "\\imath"))
          (?I ("\\int" "\\Im"))
          (?F ("\\Phi"))
          (?P ("\\Pi" "\\propto"))
          (?Q ("\\Theta" "\\quad" "\\qquad"))
          (?S ("\\Sigma" "\\sum" "\\arcsin"))
          (?t ("\\tau" "\\therefore" "\\tan"))
          (?T ("\\times" "" "\\arctan"))
          (?V ())
          (?/ ("\\frac{?}{}" "\\not")) ;; Normal fr command doesn't work properly
          (?< ("\\leq" "\\ll" "\\longleftarrow"))
          (?> ("\\geq" "\\gg" "\\longrightarrow"))
          (?$ ("\\leftarrow" "" ""))
          (?% ("\\rightarrow" "" "")))))

Company Math

Enable a company completion back-end for LaTeX maths symbols

(add-to-list 'company-backends 'company-math-symbols-unicode)

Compilation

Use LuaLaTeX with LaTeXMK

(setq TeX-command-extra-options "-lualatex -pdflua")

General

(after! tex-mode
  (setq-default TeX-master nil))

LSP

Set the lsp servers for use in latex mode

(use-package! lsp-ltex
  ;; :hook (text-mode . (lambda ()
  ;;                      require 'lsp-ltex
  ;;                      (lsp)))
  :hook (latex-mode . lsp-deferred)
  :init
  (setq lsp-ltex-version (gethash "ltex-ls" (json-parse-string (shell-command-to-string "ltex-ls -V")))
        lsp-ltex-server-store-path nil
        lsp-ltex-language "en-GB"
        lsp-ltex-mother-tongue "en-GB"
        lsp-ltex-completion-enabled t)
  :config
  (set-lsp-priority! 'ltex-ls 2))

(after! tex-mode
  ;; When on mac
  (when (string= (system-name) "maccie")
    (add-to-list 'load-path "/opt/homebrew/bin/texlab")
    (setq lsp-latex-texlab-executable "/opt/homebrew/bin/texlab"))

  ;; When on arch
  (when (string= (system-name) "arch")
    (add-to-list 'load-path "/usr/bin/texlab")
    (setq lsp-latex-texlab-executable "/usr/bin/texlab"))

  (with-eval-after-load "tex-mode"
    (add-hook 'tex-mode-hook 'lsp)
    (add-hook 'latex-mode-hook 'lsp))
  (with-eval-after-load "bibtex"
    (add-hook 'bibtex-mode-hook 'lsp)))

RefTeX

Set the default bibliography location

(setq reftex-default-bibliography "~/Documents/warwick/thesus/references.bib")

Change the default method of adding/searching for citations with reftex

(map! :map reftex-mode-map
      :localleader
      :desc "reftex-cite" "r" #'reftex-citation
      :desc "reftex-label" "l" #'reftex-label)

Zotero

Use the zotra-server backend

(after! tex-mode
  (setq zotra-backend 'zotra-server)
  (setq zotra-local-server-directory "~/Applications/zotra-server/"))

LSP

General

Configure general settings for LSP

(after! lsp-mode
  (setq lsp-enable-symbol-highlighting t
        lsp-lens-enable t
        lsp-headerline-breadcrumb-enable t
        lsp-modeline-code-actions-enable t
        lsp-modeline-diagnostics-enable t
        lsp-diagnostics-provider :auto
        lsp-eldoc-enable-hover t
        lsp-completion-provider :auto
        lsp-completion-show-detail t
        lsp-completion-show-kind t
        lsp-signature-mode t
        lsp-signature-auto-activate t
        lsp-signature-render-documentation t
        lsp-idle-delay 1.0))

lsp-ui

Configure lsp-ui settings

(after! lsp-mode
  (setq lsp-ui-sideline-enable t
        ;; lsp-ui-sideline-mode 1
        lsp-ui-sideline-delay 1
        lsp-ui-sideline-show-symbol t
        lsp-ui-sideline-show-diagnostics t
        lsp-ui-sideline-show-hover t
        lsp-ui-sideline-show-code-actions t
        lsp-ui-sideline-update-mode 'point
        lsp-ui-peek-enable t
        lsp-ui-peek-show-directory t
        lsp-ui-doc-enable t
        ;; lsp-ui-doc-frame-mode t ; This breaks 'q' for some reason
        lsp-ui-doc-delay 1
        lsp-ui-doc-show-with-cursor t
        lsp-ui-doc-show-with-mouse t
        lsp-ui-doc-header t
        lsp-ui-doc-use-childframe t
        lsp-ui-doc-position 'top
        lsp-ui-doc-max-height 25
        lsp-ui-doc-use-webkit t
        lsp-ui-imenu-enable t
        lsp-ui-imenu-kind-position 'left
        lsp-ui-imenu-buffer-position 'right
        lsp-ui-imenu-window-width 35
        lsp-ui-imenu-auto-refresh t
        lsp-ui-imenu-auto-refresh-delay 1.0)

  (map! :map lsp-ui-mode-map "C-," #'lsp-ui-doc-focus-frame)
  (map! :map lsp-ui-mode-map "C-;" #'lsp-ui-sideline-execute-code-action))

;; (map! :after lsp-mode
;;       :map lsp-mode-map
;;       :leader
;;       :prefix ("#" . "custom")
;;       :prefix ("# l" . "lsp")
;;       :desc "open imenu"
;;       "i" #'lsp-ui-imenu
;;       "I" #'lsp-ui-imenu--refresh)

DAP

Enable the DAP debugger

(after! dap-mode
  (setq dap-python-debugger 'debugpy))

(map! :after dap-mode
      :map dap-mode-map
      :leader
      :prefix ("d" . "dap")

      ;; basics
      :desc "dap next"          "n" #'dap-next
      :desc "dap step in"       "i" #'dap-step-in
      :desc "dap step out"      "o" #'dap-step-out
      :desc "dap continue"      "c" #'dap-continue
      :desc "dap hydra"         "h" #'dap-hydra
      :desc "dap debug restart" "r" #'dap-debug-restart
      :desc "dap debug"         "s" #'dap-debug

      ;; debug
      :prefix ("dd" . "Debug")
      :desc "dap debug recent"  "r" #'dap-debug-recent
      :desc "dap debug last"    "l" #'dap-debug-last

      ;; eval
      :prefix ("de" . "Eval")
      :desc "eval"                "e" #'dap-eval
      :desc "eval region"         "r" #'dap-eval-region
      :desc "eval thing at point" "s" #'dap-eval-thing-at-point
      :desc "add expression"      "a" #'dap-ui-expressions-add
      :desc "remove expression"   "d" #'dap-ui-expressions-remove

      :prefix ("db" . "Breakpoint")
      :desc "dap breakpoint toggle"      "b" #'dap-breakpoint-toggle
      :desc "dap breakpoint condition"   "c" #'dap-breakpoint-condition
      :desc "dap breakpoint hit count"   "h" #'dap-breakpoint-hit-condition
      :desc "dap breakpoint log message" "l" #'dap-breakpoint-log-message)

Markdown

Github API rate limit

Github has a rate limit, limiting how long grip-mode will work for. The following should get around this. This also uses a github authentication token and parses it from a file stored in this directory so it doesn’t get made public when I publish this to github.

(after! grip-mode
  (setq grip-github-user "grip-github-user")
  (setq grip-github-password (substring
                              (with-temp-buffer
                                (insert-file-contents "~/.doom.d/grip_pw.txt")
                                (buffer-string)) 0 -1)))

Line Wrapping

Use visual line wrapping

(add-hook! (gfm-mode markdown-mode) #'visual-line-mode #'turn-off-auto-fill)

Live Preview

Automatically open live preview when opening a markdown file

(after! markdown-mode
  ;; (add-hook! 'markdown-mode-hook #'grip-mode)
  (setq grip-sleep-time 2
        grip-preview-use-webkit t)
  (when (string= (system-name) "arch")
    (setq grip-binary-path "/usr/bin/grip"))
  (when (string= (system-name) "maccie")
    (setq grip-binary-path "/opt/homebrew/bin/grip")))

Markdown Style Customisation

Mirror the style that markdown renders in

(custom-set-faces!
  '(markdown-header-face-1 :height 1.25 :weight extra-bold :inherit markdown-header-face)
  '(markdown-header-face-2 :height 1.15 :weight bold       :inherit markdown-header-face)
  '(markdown-header-face-3 :height 1.08 :weight bold       :inherit markdown-header-face)
  '(markdown-header-face-4 :height 1.00 :weight bold       :inherit markdown-header-face)
  '(markdown-header-face-5 :height 0.90 :weight bold       :inherit markdown-header-face)
  '(markdown-header-face-6 :height 0.75 :weight extra-bold :inherit markdown-header-face))

Obsidian

;; (use-package! obsidian
;;   :ensure t
;;   :demand t
;;   :custom
;;   ;; This directory will be used for `obsidian-capture' if set.
;;   (obsidian-inbox-directory "inbox")
;;   ;; Create missing files in inbox? - when clicking on a wiki link
;;   ;; t: in inbox, nil: next to the file with the link
;;   ;; default: t
;;   ;(obsidian-wiki-link-create-file-in-inbox nil)
;;   ;; The directory for daily notes (file name is YYYY-MM-DD.md)
;;   (obsidian-daily-notes-directory "daily_notes")
;;   ;; Directory of note templates, unset (nil) by default
;;   ;(obsidian-templates-directory "Templates")
;;   ;; Daily Note template name - requires a template directory. Default: Daily Note Template.md
;;   ;(setq obsidian-daily-note-template "Daily Note Template.md")
;;   :config
;;   (obsidian-specify-path "~/Documents/obsidian/")
;;   ;; Activate detection of Obsidian vault
;;   (global-obsidian-mode t)
;;   (map! :map obsidian-mode-map
;;         :localleader
;;         :prefix ("O" . "Obsidian")
;;         ;; Replace C-c C-o with Obsidian.el's implementation. It's ok to use another key binding.
;;         :desc "follow link" "o" #'obsidian-follow-link-at-point
;;         ;; Jump to backlinks
;;         :desc "backlink jump" "b" #'obsidian-backlink-jump
;;         :desc "insert link" "l" #'obsidian-insert-wikilink
;;         ;; If you prefer you can use `obsidian-insert-link'
;;         :desc "insert wikilink" "w" #'obsidian-insert-wikilink
;;         ;; Open a note
;;         :desc "jump" "j" #'obsidian-jump
;;         ;; Capture a new note in the inbox
;;         :desc "capture" "c" #'obsidian-capture
;;         ;; Create a daily note
;;         :desc "daily note" #'obsidian-daily-note)

Python

Disable prettify-symbols in python modes

(after! python
  (prettify-symbols-mode -1))

Formatters and Linters

Black

(use-package! python-black
  :after python
  :config
  (add-hook! 'python-mode-hook #'python-black-on-save-mode)
  (map! :map python-mode-map
        :localleader
        :prefix ("b" . "black")
        :desc "blacken buffer" "b" #'python-black-buffer
        :desc "blacken region" "r" #'python-black-region
        :desc "blacken statement" "s" #'python-black-statement))

(setq-hook! 'python-mode-hook +format-with-lsp nil)

Ruff

;; (use-package! lsp-mode
;;   :hook (python-mode . lsp-deferred)
;;   ;; :commands lsp-deferred
;;   :custom
;;   (lsp-ruff-lsp-ruff-path ["usr/bin/ruff server"])
;;   (lsp-ruff-lsp-ruff-args ["–-config /home/dylanmorgan/.config/ruff/ruff.toml" "--preview"])
;;   ;; (lsp-ruff-lsp-python-path "python")
;;   (lsp-ruff-lsp-advertize-fix-all t)
;;   (lsp-ruff-lsp-advertize-organize-imports t)
;;   (lsp-ruff-lsp-log-level "info")
;;   (lsp-ruff-lsp-show-notifications "onError"))

;; TODO when ruff formatting leaves alpha dev
;; (after! python
  ;; (setf (alist-get 'ruff apheleia-formatters) '("ruff format --config ~/.config/ruff/ruff.toml --target-version py39 -q"
  ;;                                               (eval (when buffer-file-name
  ;;                                                       (concat "--stdin-filename=" buffer-file-name)))
  ;;                                               "-"))
  ;; (setf (alist-get 'python-mode apheleia-mode-alist) '(ruff))
  ;; (add-hook! 'before-save-hook #'format-with-lsp t)
  ;; (add-hook! 'before-save-hook #'lsp-organize-imports))

Also add ruff to flycheck

;; (after! flycheck
;;   ;; (require 'flycheck)

;;   (flycheck-define-checker python-ruff
;;     "A Python syntax and style checker using the ruff utility.
;;   To override the path to the ruff executable, set
;;   `flycheck-python-ruff-executable'.
;;   See URL `http://pypi.python.org/pypi/ruff'."

;;     :command ("ruff format --config /home/dylanmorgan/.config/ruff/ruff.toml --target-version py312 -q"
;;               (eval (when buffer-file-name
;;                       (concat "--stdin-filename=" buffer-file-name)))
;;               "-")
;;     :standard-input t
;;     :error-filter (lambda (errors)
;;                     (let ((errors (flycheck-sanitize-errors errors)))
;;                       (seq-map #'flycheck-flake8-fix-error-level errors)))
;;     :error-patterns
;;     ((warning line-start
;;               (file-name) ":" line ":" (optional column ":") " "
;;               (id (one-or-more (any alpha)) (one-or-more digit)) " "
;;               (message (one-or-more not-newline))
;;               line-end))
;;     :modes python-mode)

;;   (add-to-list 'flycheck-checkers 'python-ruff)
;;   (provide 'flycheck-ruff))

Enable ruff over tramp

;; (lsp-register-client
;;     (make-lsp-client
;;         :new-connection (lsp-tramp-connection "ruff-lsp")
;;         :activation-fn (lsp-activate-on "python")
;;         :major-modes '(python-mode)
;;         :remote? t
;;         :add-on? t
;;         :server-id 'ruff-lsp))

Pyright

(after! lsp-mode
  (setq lsp-pyright-disable-language-services nil
        lsp-pyright-disable-organize-imports nil
        lsp-pyright-auto-import-completions t
        lsp-pyright-auto-search-paths t
        lsp-pyright-diagnostic-mode "openFilesOnly"
        lsp-pyright-log-level "info"
        lsp-pyright-typechecking-mode "basic"
        lsp-pyright-use-library-code-for-types t
        lsp-completion-enable t))

Enable pyright over tramp

;; (lsp-register-client
;;     (make-lsp-client
;;         :new-connection (lsp-tramp-connection "pyright")
;;         :activation-fn (lsp-activate-on "python")
;;         :major-modes '(python-mode)
;;         :remote? t
;;         :add-on? t
;;         :server-id 'pyright)
;;         :tramp-remote-path )

Jupyter

Loading jupyter instead of emacs-jupyter

;; (use-package jupyter
;;   :after (ob-jupyter ob-python)
;;   :config
;;   (setq jupyter-api-authentication-method 'password)
;;   (setq jupyter-eval-use-overlays nil)
;;   (setq org-babel-default-header-args:jupyter-python '((:session . "/jpy:localhost#8888:py")
;;                                                        (:kernel . "conda-env-edge-py")
;;                                                        (:async . "yes")
;;                                                        (:pandoc t)))
;;   (add-to-list 'savehist-additional-variables 'jupyter-server-kernel-names)
;;   (setq ob-async-no-async-languages-alist '("jupyter-python"))
;;   (add-to-list 'org-structure-template-alist '("j" . "src jupyter-python")))

;; (advice-add 'request--netscape-cookie-parse :around #'fix-request-netscape-cookie-parse)

(after! ein
  (when (string= (system-name) "arch")
    (setq ein:jupyter-default-server-command "/home/dylanmorgan/.local/bin/jupyter-lab"))
  (when (string= (system-name) "maccie")
    (setq ein:jupyter-default-server-command "/opt/homebrew/bin/jupyter-lab")))

numpydoc

(use-package! numpydoc
  :after python
  :config
  (map! :map python-mode-map
        :localleader
        :desc "numpydoc" "n" #'numpydoc-generate)
  ;; (setq numpydoc-template-long "")
  (setq numpydoc-insertion-style 'yas))

Poetry

Set keybindings for poetry and disable over tramp

(use-package! poetry
  :after python
  :hook (python-mode . (lambda ()
                         (interactive)
                         (if (file-remote-p default-directory)
                             (setq package-load-list '(all
                                                       (poetry nil))))))
  :config
  (map! :map python-mode-map
        :localleader
        :desc "poetry" "p" #'poetry))

Rust

Formatters and Linters

(after! rustic
   (setq rustic-format-on-save t)
   (setq rustic-lsp-server 'rust-analyzer))

;; (add-hook! 'rust-mode-hook #'prettify-symbols-mode)

DAP

(after! rustic
  (require 'dap-cpptools)
  (dap-register-debug-template "Rust::GDB Run Configuration"
                               (list :type "gdb"
                                     :request "launch"
                                     :name "GDB::Run"
                                     :gdbpath "rust-gdb"
                                     :target nil
                                     :cwd nil)))

Org-mode

Auto Tangle

Add #+auto_tange: t to the org header to automatically tangle when a document is saved

Also set a keybinding for this

(defun insert-auto-tangle-tag ()
  "Insert auto-tangle tag in a literate config."
  (interactive)
  (evil-org-open-below 1)
  (insert "#+auto_tangle: t ")
  (evil-force-normal-state))

(map! :map org-mode-map
      :after org-mode
      :localleader
      :prefix ("j" . "org header")
      :desc "auto tangle tag"
      "a" 'insert-auto-tangle-tag)

Agenda

Set filepath for org agenda

;; (setq org-agenda-files '("~/Documents/"))

Super Agenda

Babel

Buffers

Make creating org buffers a little easier

(evil-define-command +evil-buffer-org-new (_count file)
  "Creates a new ORG buffer replacing the current window, optionally editing a certain FILE"
  :repeat nil
  (interactive "P<f>")
  (if file
      (evil-edit file)
    (let ((buffer (generate-new-buffer "*new org*")))
      (set-window-buffer nil buffer)
      (with-current-buffer buffer
        (org-mode)
        (setq-local doom-real-buffer-p t)))))

(map! :leader
      (:prefix "b"
       :desc "New empty Org buffer" "o" #'+evil-buffer-org-new))

Capture

Quickly take down notes

(setq org-capture-templates
      '(("t" "Tasks" entry
         (file+headline "" "Inbox")
         "* TODO %?\n %U")
        ("c" "Phone Call" entry
         (file+headline "" "Inbox")
         "* TODO Call %?\n %U")
        ("m" "Meeting" entry
         (file+headline "" "Meetings")
         "* %?\n %U")))

Exporting

I like to export markdown files written in org as README.org. I’m creating a shortcut to use for this in future.

I also export a lot of org files to markdown so I will also add another shortcut for that command here.

(map! :map org-mode-map
      :after org-mode
      :localleader
      :desc "org-export-to-org"
      "E" 'org-org-export-to-org
      :desc "org-export-as-md"
      "M" 'org-pandoc-export-to-markdown)

File Conversions

Leaving org is sad. Thankfully, there’s a way around this!

  • Package installed in packages.el
(use-package! org-pandoc-import
  :after org-mode)

File Headers

Provide different options for default headers for emacs org files

(defun org-literate-config ()
  (interactive)
  (setq title (read-string "Title: "))
  (setq filename (read-string "Original file name: "))
  (insert "#+TITLE: " title " \n"
          "#+AUTHOR: Dylan Morgan\n"
          "#+EMAIL: dbmorgan98@gmail.com\n"
          "#+PROPERTY: header-args :tangle " filename "\n"
          "#+STARTUP: content\n\n"
          "* Table of Contents :toc:\n\n"))

(defun org-header-notes ()
  (interactive)
  (setq title (read-string "Title: "))
  (insert "#+TITLE: " title " \n"
          "#+AUTHOR: Dylan Morgan\n"
          "#+EMAIL: dbmorgan98@gmail.com\n"
          "#+STARTUP: content\n\n"
          "* Table of Contents :toc:\n\n"))

(defun org-header-notes-custom-property ()
  (interactive)
  (setq title (read-string "Title: "))
  (setq properties (read-string "Properties: "))
  (insert "#+TITLE: " title " \n"
          "#+AUTHOR: Dylan Morgan\n"
          "#+EMAIL: dbmorgan98@gmail.com\n"
          "#+PROPERTY: " properties "\n"
          "#+STARTUP: content\n\n"
          "* Table of Contents :toc:\n\n"))

(defun org-header-with-readme ()
  (interactive)
  (setq title (read-string "Title: "))
  (insert "#+TITLE: " title " \n"
          "#+AUTHOR: Dylan Morgan\n"
          "#+EMAIL: dbmorgan98@gmail.com\n"
          "#+STARTUP: content\n"
          "#+EXPORT_FILE_NAME: ./README.org\n\n"
          "* Table of Contents :toc:\n\n"))

(map! :map org-mode-map
      :after org-mode
      :localleader
      :prefix ("j" . "org header")
      :desc "literate config"
      "l" 'org-literate-config
      :desc "note taking"
      "n" 'org-header-notes
      :desc "notes custom property"
      "p" 'org-header-notes-custom-property
      :desc "header with readme"
      "r" 'org-header-with-readme)

General

  • Default file location
    • If you use `org’ and don’t want your org files in the default location below, change `org-directory’. It must be set before org loads!
  • It’s convenient to have properties inherited
  • Alphabetical lists
  • Export processes in external emacs process
  • Try to not accidentally do weird stuff in invisible regions
(setq org-directory "~/Documents/org/"
      org-use-property-inheritance t
      org-list-allow-alphabetical t
      org-export-in-background t
      org-fold-catch-invisible-edits 'smart)

Special Block Extras

(use-package! org-special-block-extras
  :hook (org-mode . org-special-block-extras-mode))

Headings

Show all headings on opening an org file and assign numbers to those headings

(after! org-mode
  (setq org-startup-folded 'content
        org-startup-numerated nil))

Set plain list indents such that the bullet point style signifies the indentation level

(after! org
  (setq org-cycle-include-plain-lists 'integrate)
  (setq org-list-demote-modify-bullet '(("+" . "-")
                                        ("-" . "+")
                                        ("1." . "a.")
                                        ("1)" . "a)")))

  (setq org-list-use-circular-motion t)
  (setq org-list-allow-alphabetical t))

Images

Automatically display images when opening an org file

(after! org-mode
  (setq org-startup-with-inline-images t))

Keybindings

Change some of the org keybinding

;; (defun org-insert-newline-heading ()
;;   ('newline)
;;   ('org-insert-heading))

;; (map! :map org-mode-map
;;       :after org
;;       :desc "Insert Heading"
;;       "M-<return>" 'org-insert-newline-heading)

(map! :map org-mode-map
      :after org
      :desc "Insert Heading"
      "M-<return>" 'org-insert-heading)

LaTeX Fragments

CDLaTeX

Enable cdlatex by default and edit an environment after inserting one.

(after! org-mode
  (setq org-startup-with-latex-preview t)
  (add-hook! 'org-mode-hook 'turn-on-org-cdlatex)

  (defadvice! org-edit-latex-emv-after-insert ()
    :after #'org-cdlatex-environment-indent
    (org-edit-latex-environment)))

In-line Fragments

Use org-fragtog mode to automatically generate latex fragments For some reason this doesn’t work on my mac, so I will only enable this for my home computer

Change Latex fragment size

(add-hook! 'org-mode-hook #'org-fragtog-mode)

;; (defun update-org-latex-fragments ()
;;   (org-latex-preview '(64))
;;   (plist-put org-format-latex-options :background "Transparent" :scale 1.5 text-scale-mode-amount)
;;   (org-latex-preview '(16)))
;; (add-hook 'text-scale-mode-hook 'update-org-latex-fragments)

(after! org-mode
  '(org-format-latex-options
    (quote
     (:foreground default :background default :scale 1.5 :html-foreground "Black" :html-background "Transparent" :html-scale 1 :matchers
      ("begin" "$1" "$" "$$" "\\(" "\\[")))))

Listing

Use listing instead of verbatim src blocks

(after! org-mode
  (add-to-list 'org-latex-packages-alist '("" "listings"))
  (setq org-latex-listings 'listings))

Prettier Highlighting

We want fragments to look lovely

(after! org-mode
  (setq org-highlight-latex-and-related '(native script entities))
  (require 'org-src)
  (add-to-list 'org-src-block-faces '("latex" (:inherit default :extend t))))

Prettier Rendering

Make LaTeX fragments look better in text

;; (setq org-format-latex-header "\\documentclass{article}
;; \\usepackage[usenames]{xcolor}

;; \\usepackage[T1]{fontenc}

;; \\usepackage{booktabs}

;; \\pagestyle{empty}             % do not remove
;; % The settings below are copied from fullpage.sty
;; \\setlength{\\textwidth}{\\paperwidth}
;; \\addtolength{\\textwidth}{-3cm}
;; \\setlength{\\oddsidemargin}{1.5cm}
;; \\addtolength{\\oddsidemargin}{-2.54cm}
;; \\setlength{\\evensidemargin}{\\oddsidemargin}
;; \\setlength{\\textheight}{\\paperheight}
;; \\addtolength{\\textheight}{-\\headheight}
;; \\addtolength{\\textheight}{-\\headsep}
;; \\addtolength{\\textheight}{-\\footskip}
;; \\addtolength{\\textheight}{-3cm}
;; \\setlength{\\topmargin}{1.5cm}
;; \\addtolength{\\topmargin}{-2.54cm}
;; % my custom stuff
;; \\usepackage{arev}
;; ")

Make background colour transparent

;; (setq org-format-latex-options
;;       (plist-put org-format-latex-options :background "Transparent"))

Scimax

Lets try this stuff from Scimax

(after! org-mode
  (defun scimax-org-latex-fragment-justify (justification)
    "Justify the latex fragment at point with JUSTIFICATION.
JUSTIFICATION is a symbol for 'left, 'center or 'right."
    (interactive
     (list (intern-soft
            (completing-read "Justification (left): " '(left center right)
                             nil t nil nil 'left))))
    (let* ((ov (ov-at))
           (beg (ov-beg ov))
           (end (ov-end ov))
           (shift (- beg (line-beginning-position)))
           (img (overlay-get ov 'display))
           (img (and (and img (consp img) (eq (car img) 'image)
                          (image-type-available-p (plist-get (cdr img) :type)))
                     img))
           space-left offset)
      (when (and img
                 ;; This means the equation is at the start of the line
                 (= beg (line-beginning-position))
                 (or
                  (string= "" (s-trim (buffer-substring end (line-end-position))))
                  (eq 'latex-environment (car (org-element-context)))))
        (setq space-left (- (window-max-chars-per-line) (car (image-size img)))
              offset (floor (cond
                             ((eq justification 'center)
                              (- (/ space-left 2) shift))
                             ((eq justification 'right)
                              (- space-left shift))
                             (t
                              0))))
        (when (>= offset 0)
          (overlay-put ov 'before-string (make-string offset ?\ ))))))

  (defun scimax-org-latex-fragment-justify-advice ()
    "After advice function to justify fragments."
    (scimax-org-latex-fragment-justify (or (plist-get org-format-latex-options :justify) 'left)))

  (defun scimax-toggle-latex-fragment-justification ()
    "Toggle if LaTeX fragment justification options can be used."
    (interactive)
    (if (not (get 'scimax-org-latex-fragment-justify-advice 'enabled))
        (progn
          (advice-add 'org--format-latex-make-overlay :after 'scimax-org-latex-fragment-justify-advice)
          (put 'scimax-org-latex-fragment-justify-advice 'enabled t)
          (message "Latex fragment justification enabled"))
      (advice-remove 'org--format-latex-make-overlay 'scimax-org-latex-fragment-justify-advice)
      (put 'scimax-org-latex-fragment-justify-advice 'enabled nil)
      (message "Latex fragment justification disabled")))

  ;; Numbered equations all have (1) as the number for fragments with vanilla
  ;; org-mode. This code injects the correct numbers into the previews so they
  ;; look good.
  (defun scimax-org-renumber-environment (orig-func &rest args)
    "A function to inject numbers in LaTeX fragment previews."
    (let ((results '())
          (counter -1)
          (numberp))
      (setq results (cl-loop for (begin . env) in
                             (org-element-map (org-element-parse-buffer) 'latex-environment
                               (lambda (env)
                                 (cons
                                  (org-element-property :begin env)
                                  (org-element-property :value env))))
                             collect
                             (cond
                              ((and (string-match "\\\\begin{equation}" env)
                                    (not (string-match "\\\\tag{" env)))
                               (cl-incf counter)
                               (cons begin counter))
                              ((string-match "\\\\begin{align}" env)
                               (prog2
                                   (cl-incf counter)
                                   (cons begin counter)
                                 (with-temp-buffer
                                   (insert env)
                                   (goto-char (point-min))
                                   ;; \\ is used for a new line. Each one leads to a number
                                   (cl-incf counter (count-matches "\\\\$"))
                                   ;; unless there are nonumbers.
                                   (goto-char (point-min))
                                   (cl-decf counter (count-matches "\\nonumber")))))
                              (t
                               (cons begin nil)))))

      (when (setq numberp (cdr (assoc (point) results)))
        (setf (car args)
              (concat
               (format "\\setcounter{equation}{%s}\n" numberp)
               (car args)))))

    (apply orig-func args))


  (defun scimax-toggle-latex-equation-numbering ()
    "Toggle whether LaTeX fragments are numbered."
    (interactive)
    (if (not (get 'scimax-org-renumber-environment 'enabled))
        (progn
          (advice-add 'org-create-formula-image :around #'scimax-org-renumber-environment)
          (put 'scimax-org-renumber-environment 'enabled t)
          (message "Latex numbering enabled"))
      (advice-remove 'org-create-formula-image #'scimax-org-renumber-environment)
      (put 'scimax-org-renumber-environment 'enabled nil)
      (message "Latex numbering disabled.")))

  (advice-add 'org-create-formula-image :around #'scimax-org-renumber-environment)
  (put 'scimax-org-renumber-environment 'enabled t))

Presentations

Beamer

Use the Warwick theme by default

(after! org-beamer-mode
  (setq org-beamer-theme "[progressbar=foot]Warwick"))

Org Present

For more advanced functionality, we can also make presentations using org-present

(defun my/org-present-prepare-slide (buffer-name heading)
  (org-overview)  ; Show only top-level headlines
  (org-show-entry)  ; Unfold the current entry
  (org-show-children))  ; Show only direct subheadings of the slide but don't expand them

(defun mu/org-present-start ()
  ;; Tweak font sizes
  (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch)
                                     (header-line (:height 4.0) variable-pitch)
                                     (org-document-title (:height 1.75) org-document-title)
                                     (org-code (:height 1.55) org-code)
                                     (org-verbatim (:height 1.55) org-verbatim)
                                     (org-block (:height 1.25) org-block)
                                     (org-block-begin-line (:height 0.7) org-block)))

  ;; Set a blank header line string to create blank space at the top
  (setq header-line-format " ")

  ;; Display inline images automatically
  (org-display-inline-images)

  ;; Center the presentation and wrap lines
  (visual-fill-column-mode 1)
  (visual-line-mode 1))

(defun my/org-present-end ()
  ;; Reset font customizations
  (setq-local face-remapping-alist '((default variable-pitch default)))

  ;; Clear the header line string so that it isn't displayed
  (setq header-line-format nil)

  ;; Stop displaying inline images
  (org-remove-inline-images)

  ;; Stop centering the document
  (visual-fill-column-mode 0)
  (visual-line-mode 0))

(use-package! org-present
  :hook
  (org-mode-hook . variable-pitch-mode)
  (org-present-mode-hook . my/org-present-start)
  (org-present-mode-quit-hook . my/org-present-end)
  (org-present-after-navigate-functions . my/org-present-prepare-slide)
  :config
  ;; Set reusable font name variables
  (defvar my/fixed-width-font "FiraCode Nerd Font"
    "The font to use for monospaced (fixed width) text.")
  (defvar my/variable-width-font "Iosevka Aile"
    "The font to use for variable-pitch (document) text.")

  (set-face-attribute 'default nil :font my/fixed-width-font :weight 'light :height 180)
  (set-face-attribute 'fixed-pitch nil :font my/fixed-width-font :weight 'light :height 190)
  (set-face-attribute 'variable-pitch nil :font my/variable-width-font :weight 'light :height 1.3)

  ;; Load org-faces to make sure we can set appropriate faces
  (require 'org-faces)

  ;; Resize Org headings
  (dolist (face '((org-level-1 . 1.2)
                  (org-level-2 . 1.1)
                  (org-level-3 . 1.05)
                  (org-level-4 . 1.0)
                  (org-level-5 . 1.1)
                  (org-level-6 . 1.1)
                  (org-level-7 . 1.1)
                  (org-level-8 . 1.1)))
    (set-face-attribute (car face) nil :font my/variable-width-font :weight 'medium :height (cdr face)))

  ;; Make the document title a bit bigger
  (set-face-attribute 'org-document-title nil :font my/variable-width-font :weight 'bold :height 1.3)

  ;; Make sure certain org faces use the fixed-pitch face when variable-pitch-mode is on
  (set-face-attribute 'org-block nil :foreground nil :inherit 'fixed-pitch)
  (set-face-attribute 'org-table nil :inherit 'fixed-pitch)
  (set-face-attribute 'org-formula nil :inherit 'fixed-pitch)
  (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
  (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
  (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch)

  ;; Configure fill width
  (setq visual-fill-column-width 110
        visual-fill-column-center-text t))

Reveal.js

(setq org-re-reveal-theme "solarized"
      org-re-reveal-revealjs-version "5.1"
      org-re-reveal-slide-number "c/t"
      org-re-reveal-mousewheel "t")

Tree Slides

It is possible to give presentations in org-mode using org-tree-slide

(use-package! org-tree-slide
  :after org-mode
  :config
  (setq org-image-actual-width nil))

Prettification

Emphasis Markers

We don’t want to see underscores and asterisks when writing italic and bold text.

(after! org
  (setq org-hide-emphasis-markers t))

Pretty Mode

Make all the things look pretty

(after! org-mode
  (setq org-pretty-entities t)
  (setq +org-pretty-mode t))

Preview

Live preview org files in github-flavoured markdown

(eval-after-load "org"
  '(require 'ox-gfm nil t))

Roam

(after! org-roam-mode
  (setq org-roam-directory "~/Documents/org/roam")
  (org-roam-db-autosync-mode))

org-roam-ui

(use-package! websocket
    :after org-roam)

(use-package! org-roam-ui
    :after org-mode
    ;; normally we'd recommend hooking orui after org-roam, but since org-roam does not have
    ;; a hookable mode anymore, you're advised to pick something yourself
    ;; if you don't care about startup time, use
    ;; :hook (after-init . org-roam-ui-mode)
    :config
    (setq org-roam-ui-sync-theme t
          org-roam-ui-follow t
          org-roam-ui-update-on-save t
          org-roam-ui-open-on-start t))

Snippet Helpers

Typing out src block headers all the time is a pain

(after! org-mode
  (defun +yas/org-src-header-p ()
    "Determine whether `point' is within a src-block header or header-args."
    (pcase (org-element-type (org-element-context))
      ('src-block (< (point) ; before code part of the src-block
                     (save-excursion (goto-char (org-element-property :begin (org-element-context)))
                                     (forward-line 1)
                                     (point))))
      ('inline-src-block (< (point) ; before code part of the inline-src-block
                            (save-excursion (goto-char (org-element-property :begin (org-element-context)))
                                            (search-forward "]{")
                                            (point))))
      ('keyword (string-match-p "^header-args" (org-element-property :value (org-element-context))))))

  (defun +yas/org-prompt-header-arg (arg question values)
    "Prompt the user to set ARG header property to one of VALUES with QUESTION.
  The default value is identified and indicated. If either default is selected,
  or no selection is made: nil is returned."
    (let* ((src-block-p (not (looking-back "^#\\+property:[ \t]+header-args:.*" (line-beginning-position))))
           (default
             (or
              (cdr (assoc arg
                          (if src-block-p
                              (nth 2 (org-babel-get-src-block-info t))
                            (org-babel-merge-params
                             org-babel-default-header-args
                             (let ((lang-headers
                                    (intern (concat "org-babel-default-header-args:"
                                                    (+yas/org-src-lang)))))
                               (when (boundp lang-headers) (eval lang-headers t)))))))
              ""))
           default-value)
      (setq values (mapcar
                    (lambda (value)
                      (if (string-match-p (regexp-quote value) default)
                          (setq default-value
                                (concat value " "
                                        (propertize "(default)" 'face 'font-lock-doc-face)))
                        value))
                    values))
      (let ((selection (consult--read question values :default default-value)))
        (unless (or (string-match-p "(default)$" selection)
                    (string= "" selection))
          selection))))

  (defun +yas/org-src-lang ()
    "Try to find the current language of the src/header at `point'. Return nil otherwise."
    (let ((context (org-element-context)))
      (pcase (org-element-type context)
        ('src-block (org-element-property :language context))
        ('inline-src-block (org-element-property :language context))
        ('keyword (when (string-match "^header-args:\\([^ ]+\\)" (org-element-property :value context))
                    (match-string 1 (org-element-property :value context)))))))

  (defun +yas/org-last-src-lang ()
    "Return the language of the last src-block, if it exists."
    (save-excursion
      (beginning-of-line)
      (when (re-search-backward "^[ \t]*#\\+begin_src" nil t)
        (org-element-property :language (org-element-context)))))

  (defun +yas/org-most-common-no-property-lang ()
    "Find the lang with the most source blocks that has no global header-args, else nil."
    (let (src-langs header-langs)
      (save-excursion
        (goto-char (point-min))
        (while (re-search-forward "^[ \t]*#\\+begin_src" nil t)
          (push (+yas/org-src-lang) src-langs))
        (goto-char (point-min))
        (while (re-search-forward "^[ \t]*#\\+property: +header-args" nil t)
          (push (+yas/org-src-lang) header-langs)))

      (setq src-langs
            (mapcar #'car
                    ;; sort alist by frequency (desc.)
                    (sort
                     ;; generate alist with form (value . frequency)
                     (cl-loop for (n . m) in (seq-group-by #'identity src-langs)
                              collect (cons n (length m)))
                     (lambda (a b) (> (cdr a) (cdr b))))))

      (car (cl-set-difference src-langs header-langs :test #'string=))))

  (defun org-syntax-convert-keyword-case-to-lower ()
    "Convert all #+KEYWORDS to #+keywords."
    (interactive)
    (save-excursion
      (goto-char (point-min))
      (let ((count 0)
            (case-fold-search nil))
        (while (re-search-forward "^[ \t]*#\\+[A-Z_]+" nil t)
          (unless (s-matches-p "RESULTS" (match-string 0))
            (replace-match (downcase (match-string 0)) t)
            (setq count (1+ count))))
        (message "Replaced %d occurances" count))))

  (defun org-auto-file-export ()
    "Export to file if #+export_file_name is found in org file metadata"
    (interactive)
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward "^[ \t]*#\\+export_file_name:*" nil t)
      ;; (while (re-search-forward "*export_file_name:*" nil t)
        (setq org_export_fname (org-org-export-to-org))
        (message "Exported org file %s" org_export_fname))))

  (add-hook 'org-mode-hook
            (lambda ()
              (add-hook 'before-save-hook #'org-syntax-convert-keyword-case-to-lower nil 'make-it-local)
              (add-hook 'after-save-hook #'org-auto-file-export nil 'make-it-local))))

SRC Blocks

  • Use python code blocks in org mode (as well as some other languages thrown in)
  • Don’t require :results output as a header in python SRC blocks
  • Formatting for source code blocks
(after! org-mode
  (require 'ob-emacs-lisp)
  (require 'ob-fortran)
  (require 'ob-julia)
  (require 'ob-latex)
  (require 'ob-lua)
  (require 'ob-python)
  (require 'ob-shell)

  (setq org-babel-default-header-args
        (cons '(:results . "output")
              (assq-delete-all :results org-babel-default-header-args)))

  (setq org-src-fontify-natively t
        org-src-preserve-indentation t
        org-src-tab-acts-natively t))

Specify shortcuts for src blocks with specific languages (not working)

;; (after! org
;;   (setq org-structure-template-alist
;;         '(("lsp" . "#begin_src emacs-lisp\n?\n#+end_src")
;;           ("f90" . "#begin_src f90\n?\n#+end_src")
;;           ("f" . "#begin_src fortran\n?\n#+end_src")
;;           ("jl" . "#begin_src julia\n?\n#+end_src")
;;           ("tex" . "#begin_src latex\n?\n#+end_src")
;;           ("lua" . "#begin_src lua\n?\n#+end_src")
;;           ("py" . "#begin_src python\n?\n#+end_src")
;;           ("sh" . "#begin_src shell\n?\n#+end_src"))))

Support lsp in SRC blocks (not working)

;; (cl-defmacro lsp-org-babel-enable (lang)
;;   "Support LANG in org source code block."
;;   (setq centaur-lsp 'lsp-mode)
;;   (cl-check-type lang stringp)
;;   (let* ((edit-pre (intern (format "org-babel-edit-prep:%s" lang)))
;;          (intern-pre (intern (format "lsp--%s" (symbol-name edit-pre)))))
;;     `(progn
;;        (defun ,intern-pre (info)
;;          (let ((file-name (->> info caddr (alist-get :file))))
;;            (unless file-name
;;              (setq file-name (make-temp-file "babel-lsp-")))
;;            (setq buffer-file-name file-name)
;;            (lsp-deferred)))
;;        (put ',intern-pre 'function-documentation
;;             (format "Enable lsp-mode in the buffer of org source block (%s)."
;;                     (upcase ,lang)))
;;        (if (fboundp ',edit-pre)
;;            (advice-add ',edit-pre :after ',intern-pre)
;;          (progn
;;            (defun ,edit-pre (info)
;;              (,intern-pre info))
;;            (put ',edit-pre 'function-documentation
;;                 (format "Prepare local buffer environment for org source block (%s)."
;;                         (upcase ,lang))))))))
;; (defvar org-babel-lang-list
;;   '("python" "ipython" "bash" "sh" "emacs-lisp" "fortran" "f90" "julia" "shell" "lua" "latex"))
;; (dolist (lang org-babel-lang-list)
;;   (eval `(lsp-org-babel-enable ,lang)))

;; (defun org-babel-edit-prep:python (babel-info)
;;   (setq-local buffer-file-name (->> babel-info caddr (alist-get :tangle)))
;;   (lsp))

Table of Contents

Generate a table of contents and set a shortcut

(use-package! toc-org
  :commands toc-org-enable
  :init (add-hook 'org-mode-hook 'toc-org-enable))

(after! org-mode
  (defun add-toc ()
    (interactive)
    (insert "* Table of Contents :toc:\n\n"))

  (map! :map org-mode-map
        :after org
        :localleader
        :prefix ("C" . "insert toc")
        :desc "insert-toc"
        "C" #'add-toc))

‘TODO’s

Automatically log when a ‘TODO’ is marked as completed

(after! org-mode
  (setq org-log-done 'time)
  (setq org-closed-keep-when-no-todo 'non-nil))

Shells

vterm

This is basically just like opening a fish shell in a buffer in emacs

;; (defun custom-vterm-popup ()
;;   (if (window-dedicated-p nil)
;;       (message "yep")
;;     (message "nope")))

;; (map! :leader
;;       :desc "Custom vterm popup" "o t" #'custom-vterm-popup)

(use-package! vterm
  :after vterm
  :init
  :config
  (setq vterm-kill-buffer-on-exit t
        vterm-always-compile-module t
        vterm-ignore-blink-cursor nil))

eshell

STRT General

Eshell is an emacs ‘shell’ written in elisp.

  • eshell-syntax-highlighting – adds fish/zsh-like syntax highlighting.
  • eshell-rc-script – your profile for eshell; like a bashrc for eshell.
  • eshell-aliases-file – sets an aliases file for the eshell.
(use-package! eshell-syntax-highlighting
  :after esh-mode
  :config
  (eshell-syntax-highlighting-global-mode +1)
  (setq eshell-rc-script (concat user-emacs-directory "eshell/profile")
        eshell-aliases-file (concat user-emacs-directory "eshell/aliases")
        eshell-history-size 5000
        eshell-buffer-maximum-lines 5000
        eshell-hist-ignoredups t
        eshell-scroll-to-bottom-on-input t
        eshell-destroy-buffer-when-process-dies t
        eshell-visual-commands'("fish" "htop" "ssh" "top" "zsh")))

Automatically close the command buffer on exit

(after! eshell
  (setq eshell-destroy-buffer-when-process-dies t))

Fish Completions

This package extends the pcomplete completion framework with completion from the fish shell. The fish shell has smart completion for a wide range of programs. fish does not require any special configuration to work with this package. Eshell, which uses pcomplete for completion, can be made to fall back on fish when it does not find any completion candidate with its native completion support. M-x shell can be made to use fish. This will disable the underlying shell completion.

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

The condition will prevent the package from loading if fish is not found (change the executable name according to you local installation. Alternatively, you can simply load the package with (require ‘fish-completion) and call fish-completion-mode manually. Optionally, if the package bash-completion is installed, fish-completion-complete can be configured to fall back on bash to further try completing. See fish-completion-fallback-on-bash-p.

Prompt

Fancier prompt:

Edit: I actually don’t like this, but will just keep it around for now.

;; (defun with-face (str &rest face-plist)
;;    (propertize str 'face face-plist))

;;  (defun shk-eshell-prompt ()
;;    (let ((header-bg "#fff"))
;;      (concat
;;       (with-face (concat (eshell/pwd) " ") :background header-bg)
;;       (with-face (format-time-string "(%Y-%m-%d %H:%M) " (current-time)) :background header-bg :foreground "#888")
;;       (with-face
;;        (or (ignore-errors (format "(%s)" (vc-responsible-backend default-directory))) "")
;;        :background header-bg)
;;       (with-face "\n" :background header-bg)
;;       (with-face user-login-name :foreground "blue")
;;       "@"
;;       (with-face "localhost" :foreground "green")
;;       (if (= (user-uid) 0)
;;           (with-face " #" :foreground "red")
;;         " $")
;;       " ")))
;;  (setq eshell-prompt-function 'shk-eshell-prompt)
;;  (setq eshell-highlight-prompt nil)

Help

Here are some additional functions/macros that could help you configure Doom:

  • `load!’ for loading external *.el files relative to this one
  • `use-package!’ for configuring packages
  • `after!’ for running code after a package has loaded
  • `add-load-path!’ for adding directories to the `load-path’, relative to this file. Emacs searches the `load-path’ when you load packages with `require’ or `use-package’.
  • `map!’ for binding new keys

To get information about any of these functions/macros, move the cursor over the highlighted symbol at press ‘K’ (non-evil users must press ‘C-c c k’). This will open documentation for it, including demos of how they are used.

You can also try ‘gd’ (or ‘C-c c d’) to jump to their definition and see how they are implemented.

About

Not another Doom emacs config...except this one is blatantly plagiarised from tecosaur

Resources

Stars

Watchers

Forks