Emacs Configuration
Table of Contents
- System Dependent Variables
- Packages and Management
- General Emacs
- General Development
- Languages
- Org-Mode
- Agenda and GTD
- Terminals
- Theme and Frame
- Shell Backend and Windows Core Setup
- Hacky Fixes
- Corrects error: File mode specification error: (error Invalid image type ‘svg’) (not used)
- Keep transparency when toggling to full-screen in Emacs 29+
- Transparency in term (
emacs -nw) - Org LaTeX Preview
- Setting Org-figures width
- Set certain file extensions to read only buffer
- Set certain file extensions to display line numbers
- Startup and Tabs
- Recreation
- gptel
System Dependent Variables
Hopefully only need to change these to get setup on a new machine.
(defconst jmn-config-location "~/dotfiles/emacs.org" "Location of literate org file used to automaitically tangle to init.el") (let ((gtd-path '((gnu/linux . "~/Documents/gtd/") (windows-nt . "c:/Users/nehlsj/OneDrive/Documents/gtd/")))) (defconst jmn-gtd-directory (alist-get system-type gtd-path) "Location of gtd org files: projects, inbox, next, whip, journal, and habits")) (defconst jmn-connected-systems '("lat" "dsk" "xps") "Systems which should download packages. Others get the 'pure' configuration.") (defconst jmn-connected-extras t "Flag of weather to use the purely astetic packages or not on connected system") (defconst jmn-pureplus-systems '("lat" "testbed") "Systems which use the pure setup with the plus packages") (defconst jmn-dark-mode t "Do we want Emacs in a dark mode? Note: no dark-mode for windows as of now") (defconst jmn-font-height-alist '(("xps" . 110) ("dsk" . 110) ("lat" . 115)) "Set text-hight for each machine-- default will be 100")
Packages and Management
Auto-tangle to init file
;; Automatically tangle our Emacs.org config file when we save it (defun efs/org-babel-tangle-config () (when (string-equal (buffer-file-name) (expand-file-name jmn-config-location)) ;; Dynamic scoping to the rescue (let ((org-confirm-babel-evaluate nil)) (org-babel-tangle)))) (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'efs/org-babel-tangle-config)))
Package management
Archives: elpa is default, melpa is community.
- Use-package is macro that is used like a package manager. Use-Package Documentation
- Update all packages with
M-x package-upgrade-all
(if (member system-name jmn-connected-systems) (defconst jmn-pure nil "Indicating if we are pure or using packages") (if (member system-name jmn-pureplus-systems) (defconst jmn-pure "plus" "Indicating we are using pure config with plus packages") (defconst jmn-pure t "Indicating if we are pure, not using any packages"))) ;; flag (defconst jmn-term (not (display-graphic-p (selected-frame))) "Indicating if emacs is being run within a terminal or not") (defun jmn-connect-to-repositories () (require 'package) (setq package-archives '(("melpa" . "https://melpa.org/packages/") ("elpa" . "https://elpa.gnu.org/packages/"))) (if (version< emacs-version "29") (progn (setq package-check-signature nil) ;; bugfix: keys are not installed (setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3"))) ;; to load melpa (package-initialize) (unless package-archive-contents (package-refresh-contents)) (unless (package-installed-p 'use-package) (package-install 'use-package));; Initialize use-package on non-Linux platforms (require 'use-package) (setq use-package-always-ensure t) ; no need for :ensure t for each package. (setq use-package-verbose t)) ; log configure/loading messages in *Messages* (if jmn-pure (defmacro use-package (&rest _)) ;; define use-package macro to do nothing (jmn-connect-to-repositories)) ;; connect to repos and use use-package macros to config below
TODO Pure-plus
Code above is for pure (offline) and non-pure (online). The below is for a pure = 'plus', when we include a few packages.
(defun jmn-install-plus-packages() (interactive) (jmn-connect-to-repositories) ;;install for all versions (dolist (pluslist '(which-key undo-tree ws-butler prescient ivy ivy-rich ivy-prescient counsel htmlize evil-nerd-commenter)) (package-install pluslist 1)) ;; install if version 27 and above (if (version<= "27" emacs-version) (progn ;; For emacs 28 ;; magit requires ver >= 2.24 which is greater than built in version ;; Warnings buffer gives the following advice ;; TODO -- need it install seq-2.24 by hand in package-list-packages (setq package-install-upgrade-built-in t) (dolist (pluslist '(seq magit markdown-mode)) (package-install pluslist 1)) (unload-feature 'seq t) (require 'seq))))
If it fails here, we need to add the packages to ~/.emacs.d/elpa
(if (string= jmn-pure "plus") ;; turn on all of the plus modes (progn (package-initialize) (require 'prescient) (dolist (pluslist '(which-key-mode undo-tree-mode ws-butler-mode prescient-persist-mode ivy-mode ivy-rich-mode ivy-prescient-mode counsel-mode)) (funcall pluslist 1)) ;; evil nerd commenter (global-set-key (kbd "C-;") 'evilnc-comment-or-uncomment-lines)))
TODO can the above do list be replaced with (package-initialize)?
General Emacs
UI Configurations
Basic
;;;; Basic ;;;; (setq inhibit-startup-message t) ; inhibit startup message (tool-bar-mode -1) ; remove toolbar (menu-bar-mode -1) ; Disable the menu bar (scroll-bar-mode -1) ; remove side scrollbar (tooltip-mode -1) ; Disable tooltips (set-fringe-mode 6) ; Give some breathing room (setq visible-bell t) ; Set up the visible bell (save-place-mode 1) ; Open file where last visited (setq Buffer-menu-name-width 35) ; give name more room (setq-default indicate-empty-lines t) ; indicate long lines (defalias 'yes-or-no-p 'y-or-n-p) ; Make =yes or no= prompts shorter (column-number-mode 1) ; show column number in modeline (winner-mode 1) ; redo and undo window changes (if (version<= "28" emacs-version) (repeat-mode 1)) ; multi-key sequences can be repeated ;; hooks ;; This modifies too much and makes git/diffs difficult-- need to find better solution ;; (if jmn-pure ;; (add-hook 'before-save-hook 'whitespace-cleanup)); non-pure uses ws-butler (unless (eq system-type 'windows-nt) (add-hook 'text-mode-hook 'flyspell-mode)) ; enable spellcheck on text mode ;; The following help syncing (global-auto-revert-mode 1) ; refresh buffer if changed on disk (setq auto-revert-use-notify nil) ; don't notify? (setq auto-revert-verbose nil) ; ;; Mouse (setq mouse-yank-at-point t) ;; yank at cursor not click location ;; By default Emacs prefers `.elc' to `.el' in all cases, `load-prefer-newer's ;; alway prefers the last-edited file, preventing this problem. (setq load-prefer-newer t) ;; Buffer Menu (add-hook 'Buffer-menu-mode-hook 'hl-line-mode) (add-hook 'bookmark-bmenu-mode-hook 'hl-line-mode)
Backup files
Save backups in .emacs.d.
(setq backup-directory-alist '( ("." . "~/.emacs.d/filebackups")))
Transparency
Set transparency
(defun transparency (value) "Sets the transparency of the frame window. 0=transparent/100=opaque" (interactive "nTransparency Value 0 - 100 opaque:") (if (version<= "29" emacs-version) (set-frame-parameter nil 'alpha-background value) (set-frame-parameter (selected-frame) 'alpha value)))
Scrolling
;;;; Scrolling ;;;; ;; Fully redraw the display before it processes queued input events. (setq redisplay-dont-pause t) ;; Number of lines of continuity to retain when scrolling by full screens (setq next-screen-context-lines 2) ;; golden ration pkg will replaced this if loaded ;; only 'jump' when moving this far off the screen (setq scroll-conservatively 100) (setq scroll-step 1) ;; Keyboard scroll one line at a time (setq mouse-wheel-progressive-speed nil) ;; Don't accelerate scrolling (setq mouse-wheel-follow-mouse t) ;; Scroll window under mouse (setq fast-but-imprecise-scrolling t) ;; No (setq less) lag while scrolling lots. (setq auto-window-vscroll nil) ;; Cursor move faster (setq pixel-scroll-precision-mode 1) ;; pixel based scrolling
- Fast Scroll
To ensure scrolling is fast in Emacs, disable non-essential things while the window is being scrolled:
(use-package fast-scroll :defer 2 :config (add-hook 'fast-scroll-start-hook (lambda () (flycheck-mode -1))) (add-hook 'fast-scroll-end-hook (lambda () (flycheck-mode 1))) (fast-scroll-config) (fast-scroll-mode 1))
Undo-tree
C-x uvisualizes undo history as a tree for easy navigationC-_undoM-_redo Archive: elpa
(use-package undo-tree :defer 2 :config (global-undo-tree-mode 1) (setq undo-tree-auto-save-history nil)) ;; don't save ~undo-tree~ file
Modeline
NOTE: The first time you load your configuration on a new machine, you’ll need to run M-x all-the-icons-install-fonts so that mode line icons display correctly. (Fixed?)
;;;; Modeline ;;;; (if jmn-connected-extras (use-package all-the-icons :defer 1 :init (when (and (not (member "all-the-icons" (font-family-list))) ;; autoinstall fonts (window-system)) (all-the-icons-install-fonts t)))) (use-package doom-modeline :init (doom-modeline-mode 1) :custom ((doom-modeline-height 10) (doom-modeline-vcs-max-length 20))) ;; default is 12
Auto-clean white space
Archive: melpa
;;;; Cleanup whitespace only on lines I touched ;;;; (use-package ws-butler :defer 4 :hook ((text-mode . ws-butler-mode) (prog-mode . ws-butler-mode)))
Keybindings
- Eventually I will assume
repeat-modeis builtin and remove theC-obindings to'other-window- repeat mode is built in starting in Emacs 28
;; general improvements (global-set-key (kbd "<escape>") 'keyboard-escape-quit) (global-set-key (kbd "C-x C-b") 'buffer-menu) ;; open buffer menue in current buffer (global-set-key (kbd "C-x C-k") 'kill-current-buffer) ;; "C-x k" asks which buffer (global-set-key (kbd "C-o") 'other-window) ;; default is "C-x o" (global-set-key (kbd "M-o") 'previous-multiframe-window) (global-set-key (kbd "C-c C-c") 'eval-buffer) (global-set-key (kbd "C-c C-r") 'eval-region) ;; make font bigger/smaller. (global-set-key (kbd "C-=") 'text-scale-increase) (global-set-key (kbd "C--") 'text-scale-decrease) (global-set-key (kbd "C-0") 'text-scale-adjust) ;; f1 is a leader key for help ;; f2 is a leader key for 2 columns ;; f3 is kmacro-start-macro-or-insert-counter -- start recording a macro ;; f4 ends the macro recording ;; f5-f10 are clear by default ;; f11 is toggle full screen ;; f12 is clear by default ;; See recentfiles (global-set-key (kbd "<f5>") 'compile) ;; See recentfiles (global-set-key (kbd "<f6>") 'recentf-open-files) ;; writing/editing (global-set-key (kbd "<f9>") 'ispell-word) (global-set-key (kbd "<f10>") 'dictionary-lookup-definition) ;; Buffer-menu-mode (define-key Buffer-menu-mode-map (kbd "C-o") 'other-window) (define-key Buffer-menu-mode-map (kbd "M-o") 'previous-multiframe-window) ;; "o" opens in another buffer and moves focus ;; "C-M-o" opens in another buffer and keeps focus in the Buffer-menu (define-key Buffer-menu-mode-map (kbd "C-M-o") 'Buffer-menu-switch-other-window) ;; xref (with-eval-after-load 'xref (define-key xref--xref-buffer-mode-map (kbd "C-o") 'other-window) (define-key xref--xref-buffer-mode-map (kbd "o") 'xref-show-location-at-point)) ;; bookmark-bmenue (with-eval-after-load 'bookmark (define-key bookmark-bmenu-mode-map (kbd "C-o") 'other-window) (define-key bookmark-bmenu-mode-map (kbd "M-o") 'previous-multiframe-window) (define-key bookmark-bmenu-mode-map (kbd "C-M-o") 'bookmark-bmenu-switch-other-window)) ;; compilation-modes (defun jmn-compilation-keybindings() (define-key compilation-mode-map (kbd "C-o") 'other-window) (define-key compilation-mode-map (kbd "C-M-o") 'compilation-display-error)) (add-hook 'compilation-mode-hook 'jmn-compilation-keybindings) ;; grep-mode (defun jmn-grep-keybindings() (define-key grep-mode-map (kbd "o") 'compilation-display-error) (define-key grep-mode-map (kbd "C-o") 'other-window)) (add-hook 'grep-mode-hook #'jmn-grep-keybindings) ;; adjust windows with keybindings (global-set-key (kbd "C-<up>") 'enlarge-window) (global-set-key (kbd "C-<down>") 'shrink-window) (global-set-key (kbd "C-<right>") 'enlarge-window-horizontally) (global-set-key (kbd "C-<left>") 'shrink-window-horizontally) ;; non-org C-c <blank> bindings (global-set-key (kbd "C-c r") 'revert-buffer) (global-set-key (kbd "C-c =") 'vc-diff) ;; also bound to "C-x v ="
Dired
More to do at here: dired-open
- "W" will open file in native environment (including another Emacs)
- "(" toggle file info
- M-x du shows the size of the files in the buffer (toggle for human readable)
;;;; Dired ;;;; (add-hook 'dired-mode-hook 'dired-hide-details-mode) ;; hide default -- '(' to toggle (add-hook 'dired-mode-hook 'hl-line-mode) (with-eval-after-load 'dired (require 'dired-x) ;; may need to be (load "dired-x" for old versions (setq dired-auto-revert-buffer t) ;; auto-revert dired when revisiting (setq dired-vc-rename-file t) ;; renamed files are under version control ;; good for my persional machine ;; (setq dired-listing-switches "-agho --group-directories-first" ) ;; good as a user of (setq dired-listing-switches "-alh --group-directories-first" ) (setq find-ls-option '("-print0 | xargs -0 ls -agho" . "")) (setq dired-dwim-target t) ;; guess other dired directory for copy and rename (setq wdired-allow-to-change-permissions t) (define-key dired-mode-map (kbd "C-o") 'other-window) (setq dired-guess-shell-alist-user '( ("\\.png\\'" "shotwell") ("\\.jpg\\'" "shotwell") ("\\.jpeg\\'" "shotwell") ("\\.mp4\\'" "vlc") ("\\.avi\\'" "vlc") ("\\.iso\\'" "vlc") ("\\.webm\\'" "vlc") ("\\.mkv\\'" "vlc") ("\\.odt\\'" "libreoffice") ("\\.docx\\'" "libreoffice") ("\\.mp3\\'" "rhythmbox") ("\\.html\\'" "firefox") ("\\.epub\\'" "ebook-viewer") ("\\.pdf\\'" "evince") ("\\.ipynb\\'" "code") ("\\.py\\'" "python") ("\\.sh\\'" "bash"))) ;;;; maybe use again in the future -- does not align with pure emacs ;; (if (version<= "28" emacs-version) ;; (setf dired-kill-when-opening-new-dired-buffer t)) ) ;; use a single dired session ;; needed for emacs version < 28 ;; (use-package dired-single ;; :after dired ;; :defer t ;; :hook (dired-mode . ;; (lambda () (define-key dired-mode-map [remap dired-find-file] ;; 'dired-single-buffer) ;; (define-key dired-mode-map ;; [remap dired-mouse-find-file-other-window] ;; 'dired-single-buffer-mouse) ;; (define-key dired-mode-map [remap dired-up-directory] ;; 'dired-single-up-directory)))) (if jmn-connected-extras (use-package all-the-icons-dired :after dired :defer t :hook (dired-mode . all-the-icons-dired-mode)))
Proced
;;;; Proced ;;;; (defun proced-settings () (proced-toggle-auto-update 5)) ;; auto update every 4 seconds (add-hook 'proced-mode-hook 'proced-settings)
Native Compilation
Suppress compilation warnings
;;;; Native comp ;;;; (setq native-comp-async-report-warnings-errors nil)
TODO Goto last change
Check with other environments to settle on "C-;" or "M-;" – the other us used for evil-nerd comment
- we cleared "C-;" from Flyspell above
(use-package goto-last-change :ensure t :bind ("C-c g" . goto-last-change))
Input Buffer, Directory Search
Ivy, Ivy-Rich, and Counsel
Ivy displays vertical completions of input buffer.
- When we want the text accepted over the suggest completion use "C-M-j" which executes (ivy-immediate-done) source
(use-package ivy :after counsel :defer t :config (ivy-mode 1) ;; remove ^ on the inputbuffer (setq ivy-initial-inputs-alist nil))
Ivy-Rich
Ivy-rich provides information to display in input buffer to counsel.
(use-package ivy-rich :after counsel :init (ivy-rich-mode 1))
Ivy-prescient
prescient.el provides some helpful behavior for sorting Ivy completion candidates based on how recently or frequently you select them. This can be especially helpful when using M-x to run commands that you don’t have bound to a key but still need to access occasionally.
(use-package ivy-prescient :after counsel :custom (ivy-prescient-enable-filtering nil) :config ;; Uncomment the following line to have sorting remembered across sessions! (prescient-persist-mode 1) (ivy-prescient-mode 1))
Counsel
Counsel displays ivy-rich info along with suggestions in input buffer.
M-oallows access to help in input buffer. Archive: elpa, melpa
(use-package counsel :defer t :bind (("M-x" . counsel-M-x) ; displays ivy-rich info in minibuffer ("C-x C-f" . counsel-find-file) :map minibuffer-local-map ("C-r" . 'counsel-minibuffer-history) ))
Helpful and Which-key
Helpful
Better version of help. We remap normal help keys to Helpful's versions. Archive: melpa
(use-package helpful :defer 3 :commands (helpful-callable helpful-variavle helpful-command helpful-key) :custom (counsel-describe-function-function #'helpful-callable) (counsel-describe-variable-function #'helpful-variable) :bind ([remap describe-function] . counsel-describe-function) ([remap describe-command] . helpful-command) ([remap describe-variable] . counsel-describe-variable) ([remap describe-key] . helpful-key))
Which-key
Archive: elpa, melpa
(use-package which-key :defer 1 :config(which-key-mode) (setq which-key-idle-delay 0.8))
Font size
(defun jmn-set-font-height(value) (interactive "nFont height (default is 100): ") (set-face-attribute 'default nil :height value)) (jmn-set-font-height (alist-get (system-name) jmn-font-height-alist 100 nil 'string=)) ;; default is 100 (setq text-scale-mode-step 1.05)
General Helper Function
Quickly load init
Defined earlier in the init so it will load even if there is an error later in the config
(defun jmn-load-init () (interactive) (if (version<= "27" emacs-version) (load "~/.emacs.d/init.el") (load "~/.emacs")))
jmn-vscode-current-buffer-file-at-point
(defun jmn-vscode-current-buffer-file-at-point () (interactive) (start-process-shell-command "code" nil (concat "code --goto " (buffer-file-name) ":" (number-to-string (line-number-at-pos)) ":" ;; +1 who knows why (number-to-string (+ 1 (current-column)))))) (defun jmn-vscode-current-project-root () (interactive) (start-process-shell-command "code" nil (concat "code -r " (project-root (project-current t))))) (defun jmn-vscode-current-buffer-in-project-root () (interactive) (start-process-shell-command "code" nil (concat "code -r " (project-root (project-current t)) " --goto " (buffer-file-name) ":" (number-to-string (line-number-at-pos)) ":" ;; +1 who knows why (number-to-string (+ 1 (current-column)))))) (define-key global-map (kbd "<f12>") 'jmn-vscode-current-buffer-in-project-root)
jmn-remove-M-1-9-from-mode-map
Clear up to allow the tab-bar keybindings.
(defun jmn-remove-M-1-9-from-mode-map (modemap) "remove 'M-[d]' keybinding from a mode-map" (dolist (num '("1" "2" "3" "4" "5" "6" "7" "8" "9")) (define-key modemap (kbd (concat "M-" num)) nil)))
Remove use-package s-expressions
(defun remove-function-sexps (functionName) "Remove all sexps with the input car in the current buffer." (save-excursion (goto-char (point-min)) ;; break up the string so it is not replaced here (while (re-search-forward (concat "(" functionName) nil t) (backward-sexp) (backward-char) (kill-sexp)))) (defun remove-if-var-sexps (varName) "Remove all sexps which start with 'if input' in the current buffer." (save-excursion (goto-char (point-min)) ;; break up the string so it is not replaced here (while (re-search-forward (concat "(if " varName) nil t) (backward-sexp) (backward-sexp) (backward-char) (kill-sexp)))) (defun jmn-purify-my-config-and-save () "Create a 'pure' configuration file '~/.emacs.d/pure_init.el' by removing impure configuration sexps." (interactive) (find-file "~/.emacs.d/init.el") (remove-function-sexps "use-package") (remove-if-var-sexps "jmn-connected-extras") (set-visited-file-name "~/.emacs.d/pure_init.el") (save-buffer) (kill-current-buffer))
Emacs in the terminal
(if (and jmn-term (version<= "29" emacs-version)) (progn (xterm-mouse-mode 1) (setopt mode-line-end-spaces nil) ;; Only matters for jmn-pure, doom-modeline is uneffected (set-display-table-slot standard-display-table 'vertical-border (make-glyph-code ?│))))
MISC
Async-shell-command
;; Suppress Async Shell Command buffers (add-to-list 'display-buffer-alist '("*Async Shell Command*" display-buffer-no-window (nil))) ;; Could use this instead ;; (setq async-shell-command-display-buffer nil) ;; Only have one Async Shell Command buffer and it holds most recent output (setq async-shell-command-buffer 'rename-buffer)
General Development
Indentation
Guess the indentation offset and 'indent-tabs-mode' from the file using internal heuristics.
(use-package dtrt-indent :hook (prog-mode . (lambda () (dtrt-indent-mode 1))))
Prog-mode
;;Prog-mode (add-hook 'prog-mode-hook 'display-line-numbers-mode) (add-hook 'prog-mode-hook 'visual-line-mode) (add-hook 'prog-mode-hook 'hs-minor-mode) ;; hide show, use C-c @ prefix (unless (eq system-type 'windows-nt) (add-hook 'prog-mode-hook 'flyspell-prog-mode)) ;; flyspell-comments
Parens/delimiters
(show-paren-mode 1) ; Highlight parentheses pairs.
TODO Rainbow Delimiters
Need to test the org-mode hook Archive: melpa
(use-package rainbow-delimiters :defer t :hook ((prog-mode . rainbow-delimiters-mode) (org-mode . (lambda () (rainbow-delimiters-mode 0)))))
Smartparens
Auto-creates closing parenthesis and bar and, smartly, writes it over if it is typed. Archive: melpa
(use-package smartparens :hook (prog-mode . smartparens-mode))
Magit
Magit Documentation Archive: melpa
(use-package magit :commands (magit-status) :custom (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) ;; moved here incase magit installed on a pure machine ;; replace original keybinding? (with-eval-after-load 'magit (add-hook 'magit-status-mode-hook (lambda () (define-key magit-mode-map (kbd "C-<tab>") nil))) (jmn-remove-M-1-9-from-mode-map magit-mode-map))
TODO Git-Gutter
[ ]replace with diff-hl mode?
Git-gutter-fringe displays git-gutter in the fringe
(use-package git-gutter :hook ((prog-mode . git-gutter-mode) ;; (text-mode . git-gutter-mode) ;; effects org-ellipsis ) :config (setq git-gutter:update-interval 0.02)) (use-package git-gutter-fringe :after git-gutter :config (set-face-background 'git-gutter-fr:deleted (face-background 'default)) (set-face-foreground 'git-gutter-fr:deleted "red"))
Highlight-indent-guide
(if jmn-connected-extras (use-package highlight-indent-guides :defer 2 :hook prog-mode :config (setq highlight-indent-guides-method 'fill) (setq highlight-indent-guides-auto-odd-face-perc -7) (setq highlight-indent-guides-auto-even-face-perc 7)))
Company-Mode
Currently company-mode gets called by lsp-mode by default, providing the auto-complete box that lsp presents it's suggestions in.
(use-package company :ensure t :hook (eglot-managed-mode . company-mode) :custom (company-minimum-prefix-length 1) (company-idle-delay 0.5))
company-box-mode
Brings up a another box with information about the highlighted recommended item in the company/lsp box.
(use-package company-box :after company :hook (company-mode . company-box-mode))
company-prescient
Help in sorting the completion results.
(use-package company-prescient :after company :config (company-prescient-mode +1))
Treemacs
(use-package treemacs :ensure t :defer t :bind (("C-c t" . treemacs )) :config (treemacs-project-follow-mode t) ;; open root of selected file in treemacs (setq treemacs-width 30))
Eglot
Combines with flymake, eldoc, company-mode, and xref to make an IDE experience.
- can search in a company completion box!
- Flymake shows underlines: errors in red, warnings in blue
- "C-h ." provides eldoc info at the point
Function/keybinding learning area:
- eglot
- eglot find declaration
- eglot find definition
- eglot format buffer or region
- eglot rename
- xref (uses eglot for the backend)
- xrf-find-defintions "M-." –return back with "M-,"
[ ]uses tags so replace?
- xrf-find-references "M-?"
- xrf-find-defintions "M-." –return back with "M-,"
(if jmn-connected-extras (use-package eglot :defer 1 :ensure-system-package ((bash-language-server . "sudo dnf install -y nodejs-bash-language-server") (pyright . "pip install pyright") (clangd . "sudo dnf install -y clang-tools-extra") (texlab . "cargo install --git https://github.com/latex-lsp/texlab --locked --tag v5.22.0") ;; ensure texlab is added to bash PATH ) :hook ((sh-mode . eglot-ensure) (python-mode . eglot-ensure) (c-mode . eglot-ensure) (c++-mode . eglot-ensure) (haskell-mode . eglot-ensure) (LaTeX-mode . eglot-ensure)) :config ;; make shorter ones later? ;; use "M-." for xref-find-definitions ;; use "M-?" for xref-find-references ;; use "M-g n" and "M-g p" to go to next and previous location ;; use ... for xref-pop-marker-stack (define-prefix-command 'eglot-prefix) (global-set-key (kbd "C-x e") 'eglot-prefix) (define-key eglot-prefix (kbd "r") 'eglot-rename) (define-key eglot-prefix (kbd "o") 'eglot-code-action-organize-imports) (define-key eglot-prefix (kbd "h") 'eldoc) (define-key eglot-prefix (kbd "d") 'eglot-find-declaration) (define-key eglot-prefix (kbd "a") 'eglot-format-buffer) (define-key eglot-prefix (kbd "n") 'flymake-goto-next-error) (define-key eglot-prefix (kbd "p") 'flymake-goto-prev-error) (define-key eglot-prefix (kbd "b") 'flymake-show-buffer-diagnostics)))
Breadcrumb
Add breadcrumbs to the top of buffers. Works great with Eglot.
(use-package breadcrumb :ensure t :config (breadcrumb-mode))
CMake
Lsp-mode requires the language server on the system:
pip install cmake-language-server.
CMake-mode
Archive: melpa
(use-package cmake-mode :defer t :ensure-system-package ((cmake . "sudo dnf install -y cmake")) :mode ("CMakeLists\\.txt\\'" "\\.cmake\\'")) (use-package cmake-font-lock :ensure t :after cmake-mode :config (cmake-font-lock-activate))
TODO CMake project
In the source directory containing CMakeLists.txt run M-x cmake-project-configure-project.
As a preference, use the /bin/ option to keep the cmake files out of the source directory.
After this, the compile automatically holds the correct command.
Archive: melpa
(use-package cmake-project :defer 2 ;; :hook ((c++-mode . cmake-project-mode ) ;; (c-mode . cmake-project-mode)) )
Yasnippet
Archive: elpa, melpa
(if jmn-connected-extras (use-package yasnippet :defer 1 :config (yas-global-mode 1)) (use-package yasnippet-snippets :after yas-minor-mode)) ;; load basic snippets from melpa
TODO Flyspell
C-, flyspell-goto-next-error
C-. flyspell-auto-correct-word
;; free up C-; for evil-nerd-commenter (with-eval-after-load 'flyspell (define-key flyspell-mode-map (kbd "C-;") nil)) ;; (progn ;; (define-key flyspell-mode-map (kbd "C-;") nil) ;; (define-key flyspell-mode-map (kbd "M-;") flyspell-auto-correct-previous-word)))
Evil nerd commenter
Archive: melpa
(use-package evil-nerd-commenter :bind ("C-;". evilnc-comment-or-uncomment-lines))
Tree Sitter Highlighting
Archive: melpa
(use-package tree-sitter-langs :hook ((sh-mode . tree-sitter-hl-mode) (python-mode . tree-sitter-hl-mode) (c-mode . tree-sitter-hl-mode) (c++-mode . tree-sitter-hl-mode)))
Ripgrep
Archive: melpa
(use-package ripgrep :defer 2 :ensure-system-package ((rg . "sudo dnf install -y ripgrep")))
YAML
Archive: melpa
(use-package yaml-mode :defer t)
TOML
(use-package toml-mode :defer t)
Docker
Archive: melpa
(use-package dockerfile-mode :defer t)
TODO Compilation mode in async output
Note: not used or tangled
(defadvice compile (before ad-compile-smart activate) "Advises `compile' so it sets the argument COMINT to t." (ad-set-arg 1 t)) (add-hook 'shell-mode-hook 'compilation-shell-minor-mode)
Devdocs
To install documentation, use M-x evdocs-install
(use-package devdocs :defer 2 :bind ("C-h D" . 'devdocs-lookup))
Pure Dev Tools
smerge
(defun jmn-smerge-accept-all-lower() "Accept all lower changes below the cursor point" (interactive) (while (not (smerge-next)) (smerge-keep-lower))) (defun jmn-smerge-accept-all-upper() "Accept all upper changes below the cursor point" (interactive) (while (not (smerge-next)) (smerge-keep-upper))) (with-eval-after-load 'smerge (define-key smerge-mode-map (kbd "C-c ^ L") 'jmn-smerge-accept-all-lower) (define-key smerge-mode-map (kbd "C-c ^ U") 'jmn-smerge-accept-all-upper))
Tab completion
Gives of tab completion in:
[X]python-mode[X]emacs-lisp-mode[X]shell-script mode (bash)
With this setup, TAB - which is usually bound to indent-for-tab-command - first tries to adjust the indentation according to the mode's settings, but if the indentation is already correct, completion is triggered. This is usually the desired behavior, and IMHO works better than third-party plugins like smart-tab. reference
I believe this is replacing what company-mode does for us.
(defun jmn-tab-complete-mode () "My tab complete config" (setq tab-always-indent 'complete) ;;complete if indented (add-to-list 'completion-styles 'initials t)) ;; turning it on everywhere and only turning company mode on for prog-mode ;;;; if this stayes it will just be moved up to under the 'General Emacs' (jmn-tab-complete-mode)
As of 28.1 there is tab-first-completion. Could add a setup for it above which depends on Emacs version.
vc-mode
(if jmn-pure (global-set-key (kbd "C-c g") (lambda () (interactive) (vc-dir (file-name-directory (buffer-file-name)))))) (defun jmn-vc-commit () "My command to show the vc-diff along with the commit input" (interactive) (vc-next-action (buffer-file-name)) (previous-multiframe-window) (vc-diff) (previous-multiframe-window) (switch-to-buffer"*vc-log*") ;; (set-window-text-height (selected-window) 4) ;; (kill-buffer "*log-edit-files*") ) (with-eval-after-load 'vc-dir (define-key vc-dir-mode-map (kbd "C-o") 'other-window) (define-key vc-dir-mode-map (kbd "C-M-o") 'vc-dir-display-file) (define-key vc-dir-mode-map (kbd "c") 'jmn-vc-commit))
Languages
Emacs-lisp
Use C-c ' to view elisp babel blocks in their own file to get completion in company-mode.
- added flycheck-mode-hook in it's use-package config.
(add-hook 'emacs-lisp-mode-hook 'display-line-numbers-mode) (add-hook 'emacs-lisp-mode-hook 'visual-line-mode)
Bash
- debuggers are available
(defun my-sh-mode-hook-fn() (setq sh-basic-offset 2 sh-indentation 2)) ;; defaults is 4 (add-hook 'sh-mode-hook #'my-sh-mode-hook-fn) (use-package sh-script :defer t :config (setq sh-basic-offset 2 sh-indentation 2)) ;; defaults are 4
Python
Pyvenv
Archive: melpa
(use-package pyvenv :ensure t :defer t :diminish :config (setenv "WORKON_HOME" "/home/ape/.conda/envs") ; Show python venv name in modeline (setq pyvenv-mode-line-indicator '(pyvenv-virtual-env-name ("[venv:" pyvenv-virtual-env-name "] "))) (pyvenv-mode t))
After package installation, you should have M-x pyvenv-workon command with a list of your virtual environments.
The only lack of this is that you need to restart LSP workspace at least once when you change venv by pyvenv-workon command.
So the flow should be like this:
M-x pyvenv-workon <your-venv> # or conda environment?
M-x lsp-restart-workspace # eglot's corresponding command?
After changing venv all installed packages from venv should be visible for LSP server.
Python-mode
For lsp, have pyright installed pip install pyright
- python-mode
(with-eval-after-load 'python ;; if emacs is not run from a terminal, we need to add the PYTHONPATH set in .bashrc (unless (getenv "PYTHONPATH") (setenv "PYTHONPATH" (shell-command-to-string "$SHELL --login -c 'echo -n $PYTHONPATH'"))) ;; allow completion (setq python-shell-completion-native-enable 1) ;; keybindings (define-key python-mode-map (kbd "C-RET") 'python-shell-send-statement) ;; use ipython for interpreter if it exists (if (executable-find "ipython") (progn (setq python-shell-interpreter "ipython") (setq python-shell-interpreter-args "-i --simple-prompt"))))
Hook
(defun my-python-mode-hook-fn () (with-eval-after-load 'devdocs (setq-local devdocs-current-docs '("python~3.12")))) (add-hook 'python-mode-hook #'my-python-mode-hook-fn)
C/C++
Compilation Buffer
(setq compilation-scroll-output t) ;;*Compilation* buffer scroll with the output.
The following keeps the compilation buffer if there are warnings or errors, and buries it otherwise (after 1 second). source
(defun bury-compile-buffer-if-successful (buffer string) "Bury a compilation buffer if succeeded without warnings " (when (and (buffer-live-p buffer) (string-match "compilation" (buffer-name buffer)) (string-match "finished" string) (not (with-current-buffer buffer (goto-char (point-min)) (search-forward "warning" nil t)))) (run-with-timer 1 nil (lambda (buf) (bury-buffer buf) (switch-to-prev-buffer (get-buffer-window buf) 'kill)) buffer))) (add-hook 'compilation-finish-functions 'bury-compile-buffer-if-successful)
Hook
Currently lsp-mode works with clangd backend without any initial setup.
company-clang needs clang installed on the system.
;;settings (setq-default c-basic-offset 2) ;; gdb (with-eval-after-load 'gdb-mi (setq gdb-many-windows t gdb-show-main t)) (advice-add 'gdb :after (lambda (&rest r) (tool-bar-mode 1))) ;; mode (defun my-c++-mode-hook-fn () (with-eval-after-load 'devdocs (setq-local devdocs-current-docs '("cpp")))) (defun my-c-mode-hook-fn () (with-eval-after-load 'devdocs (setq-local devdocs-current-docs '("c")))) (add-hook #'c-mode-hook #'my-c-mode-hook-fn) (add-hook #'c++-mode-hook #'my-c++-mode-hook-fn)
Octave
(add-to-list 'auto-mode-alist '("\\.m$" . octave-mode))
Markdown
Use markdown-preview-mode to view in browser.
(use-package markdown-mode :defer t :hook ((markdown-mode-hook . flyspell-mode) (markdown-mode-hook . visual-line-mode))) (use-package markdown-preview-mode :defer t)
TODO Haskell
1) Install GHCup
Installs the following:
- ghcup - The Haskell toolchain installer
- ghc - The Glasgow Haskell Compiler
- cabal - The Cabal build tool for managing Haskell software
- stack - A cross-platform program for developing Haskell projects (similar to cabal)
- hls - (optional) A language server for developers to integrate with their editor/IDE
(use-package haskell-mode :hook (haskell-mode . interactive-haskell-mode) ;; For GHCi integration ) ;; (use-package lsp-haskell) ;; Enable haskell-mode and lsp-mode automatically for Haskell files (add-hook 'haskell-mode-hook #'eglot-ensure) (add-hook 'haskell-mode-hook #'interactive-haskell-mode) ; For GHCi integration (use-package flymake-hlint)
Org-Mode
Notes on completion: use C-c C-l to insert a path link and get completion.
- alternatively company-mode will complete in the buffer, but will get in the way in the org-blocks.
Mode setup
(defun jmn/org-mode-setup () (unless (or jmn-term (version<= emacs-version "26.1")) (org-indent-mode)) (variable-pitch-mode 1) (visual-line-mode 1) ;; fix issue where it matches > with partentheses -- may break blocks with <> (modify-syntax-entry ?< ".") (modify-syntax-entry ?> ".") )
Fonts
(defun jmn/org-font-setup () (unless jmn-term ;; Replace list hyphen with dot (font-lock-add-keywords 'org-mode '(("^ *\\([-]\\) " (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))) ;; Set faces for heading levels (let ((jmn-org-hfont-alist '((gnu/linux . "Cantarell") (windows-nt . unspecified)))) (dolist (face '((org-level-1 . 1.2) (org-level-2 . 1.1) (org-level-3 . 1.1) (org-level-4 . 1.1) (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 (alist-get system-type jmn-org-hfont-alist) :weight 'regular :height (cdr face)))) ;; Ensure that anything that should be fixed-pitch in Org files appears that way ;; (set-face-attribute 'org-block nil :foreground nil :inherit 'fixed-pitch) ;;warning (set-face-attribute 'org-block nil :foreground 'unspecified' :inherit 'fixed-pitch) (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch)) (set-face-attribute 'org-table 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))
Start
(add-hook 'org-mode-hook 'jmn/org-mode-setup) (with-eval-after-load 'org (jmn/org-font-setup) (unless (or jmn-term jmn-pure) (progn (setq org-ellipsis " ▾") (set-face-underline 'org-ellipsis nil))) (setq org-hide-emphasis-markers t org-src-fontify-natively t org-fontify-quote-and-verse-blocks t org-src-tab-acts-natively t org-edit-src-content-indentation 2 ;; I undo this somewhere 4tangling org-hide-block-startup nil org-src-preserve-indentation nil org-startup-folded 'content org-cycle-separator-lines 2 org-capture-bookmark nil org-list-indent-offset 1 org-image-actual-width nil ;; fix to allow picture resizing org-return-follows-link t org-use-speed-commands t org-use-property-inheritance t ;; preperties to affect nested sections org-export-babel-evaluate nil ;; don't run src blocks on export org-agenda-tags-column (alist-get (system-name) '(("xps" . -85) ("dsk" . -90)) 'auto nil 'string=)))
Bullets
Archive: melpa
(unless (or jmn-term (not jmn-connected-extras)) (use-package org-bullets :hook (org-mode . org-bullets-mode) :custom (org-bullets-bullet-list '("◉" "○" "●" "○" "●" "○" "●"))))
Center column and line wrapping
Archive: melpa
(defun jmn/org-mode-visual-fill () (setq visual-fill-column-width 120 visual-fill-column-center-text t) (visual-fill-column-mode 1)) (use-package visual-fill-column :hook (org-mode . jmn/org-mode-visual-fill))
Org-babel
Either start a source block with <[template] or C-c C-, to select from org-select.
Notes: Use # -- org-src-preserve-indentation: t; -- when doing tangle/detangle with python
(with-eval-after-load 'org (org-babel-do-load-languages 'org-babel-load-languages (append org-babel-load-languages '((shell . t) (python . t) (makefile . t) (latex . t) (C . t))))) (setq org-confirm-babel-evaluate nil) (with-eval-after-load 'org (if (version<= "27" emacs-version) (progn (require 'org-tempo) ;; needed for <sh to complete on new systems -- works without on v 26.1 (add-to-list 'org-structure-template-alist '("la" . "src latex")) (add-to-list 'org-structure-template-alist '("m" . "src makefile")) (add-to-list 'org-structure-template-alist '("js" . "src js")) (add-to-list 'org-structure-template-alist '("sh" . "src shell")) (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) (add-to-list 'org-structure-template-alist '("py" . "src python :results output")) (add-to-list 'org-structure-template-alist '("pyim" . "src python :results file :var f=strNameWithDoubleQuotes import matplotlib.pyplot as plt plt.savefig(f) f")) (add-to-list 'org-structure-template-alist '("cpp" . "src C++ :includes <iostream>")) (add-to-list 'org-structure-template-alist '("cppnm" . "src C++ :main no"))) (progn (add-to-list 'org-structure-template-alist '("m" "#+BEGIN_SRC makefile ? #+END_SRC")) (add-to-list 'org-structure-template-alist '("js" "#+BEGIN_SRC js ? #+END_SRC")) (add-to-list 'org-structure-template-alist '("sh" "#+BEGIN_SRC shell ? #+END_SRC")) (add-to-list 'org-structure-template-alist '("el" "#+BEGIN_SRC emacs-lisp ? #+END_SRC")) (add-to-list 'org-structure-template-alist '("py" "#+BEGIN_SRC python ? #+END_SRC")) (add-to-list 'org-structure-template-alist '("cpp" "#+BEGIN_SRC C++ :includes <iostream> ? #+END_SRC")) (add-to-list 'org-structure-template-alist '("cppnm" "#+BEGIN_SRC C++ :main no ? #+END_SRC")))))
Inline latex
Note: I had to install texlive dependencies for latex framents to work. I found what needed to be installed by running pdflatex on the generated tex file in /tmp/ created by org.
sudo dnf install texlive-scheme-full- texlive-ulem
Set in-line LaTeX's relative font size
(with-eval-after-load 'org (defconst jmn-latex-scale 1.1 "scaling factor for latex fragments") (setq org-format-latex-options (plist-put org-format-latex-options :scale jmn-latex-scale)))
In-line LaTeX size when buffer scale is changed
Create a function to align the size of displayed latex framents with overall org-mode font size.
(defun update-org-latex-fragments () (org-latex-preview '(64)) (plist-put org-format-latex-options :scale (+ jmn-latex-scale (* 0.3 text-scale-mode-amount))) (org-latex-preview '(16))) (add-hook 'text-scale-mode-hook 'update-org-latex-fragments)
org-fragtog
Automatically toggle between displaying and editing LaTeX depending on the cursor's position.
(unless jmn-pure (use-package org-fragtog :hook (org-mode . org-fragtog-mode)))
Keybindings
(global-set-key (kbd "C-c x") #'org-html-export-to-html) (global-set-key (kbd "C-c s") #'org-store-link) (global-set-key (kbd "C-c i") #'org-insert-link) (global-set-key (kbd "C-c c") #'org-capture)
HTML
htmlize
For syntax highlighting in export html, we want htmlize version > 1.34
(use-package htmlize :ensure t :defer t)
Save to HTML on save
This org file converts to html on save, via the file's local variables. See the end of the file.
Here we designate the auto convert to html on save as safe so we are not prompted to designate it safe on startup the first time.
;; initialize if not already (if (not (bound-and-true-p jmn-org-files-to-html-on-save)) (setq jmn-org-files-to-html-on-save nil)) (defun jmn-org-export-html-on-save-list() (when (member (buffer-file-name) jmn-org-files-to-html-on-save) (org-html-export-to-html))) (add-hook 'after-save-hook #'jmn-org-export-html-on-save-list) (defun jmn-export-to-html-on-save() (interactive) (add-to-list 'jmn-org-files-to-html-on-save (buffer-file-name))) (add-to-list 'safe-local-variable-values '(eval jmn-export-to-html-on-save))
(add-to-list 'safe-local-variable-values `(eval add-hook 'after-save-hook #'org-html-export-to-html))
Make Read The Org setup file safe
Make the setup file safe for non-pure machines.
(if (and (version<= "29" emacs-version) (not jmn-pure)) (with-eval-after-load 'org (add-to-list 'org-safe-remote-resources "\\`https://fniessen\\.github\\.io/org-html-themes/org/html-theme-readtheorg\\.setup\\'")))
Agenda and GTD
General
Following the tutorial here.
;; Org Agenda (setq org-agenda-window-setup 'other-window) ;; other good option: reorganize-frame ;; Exited with ‘q’ or ‘x’ and the old state is restored. (setq org-agenda-restore-windows-after-quit 1) (setq org-agenda-span 'day) ;; SOMEDAY itmes are ommitted from GTD interface on purpose (setq org-todo-keywords '((sequence "TODO(t)" "NEXT(n)" "HOLD(h)" "|" "DONE(d)" "IGNORE(i)"))) (require 'find-lisp) ;; may not be needed"\\.\\(org\\|org_archived\\)$" ; use "\.org$" or "\\.\\(org\\|org_archived\\)$" exclude or include archives (setq org-agenda-files (find-lisp-find-files jmn-gtd-directory ".*\\.\\(org\\|org_archive\\)$")) ;; "\\.\\(org\\|org_archive\\)$")) ;; level/maxlevel = order in hierarchy (setq org-refile-targets '(("projects.org" :maxlevel . 2) ("someday.org" :maxlevel . 1) ("whip.org" :level . 1) ("next.org" :level . 0))) ;; https://github.com/syl20bnr/spacemacs/issues/3094 (setq org-refile-use-outline-path 'file org-outline-path-complete-in-steps nil) (setq org-refile-allow-creating-parent-nodes 'confirm) (setq org-agenda-prefix-format '((agenda . " %i %-10:c%t [%e]% s ") (todo . " %i %-10:c [%-4e] ") (tags . " %i %-12:c"))) (setq org-deadline-warning-days 30) (setq org-agenda-start-with-log-mode t) ;; allows us to see closed in calendar (setq org-log-done 'time) ;; creates CLOSED time tag (setq org-log-into-drawer t) ;; creates a LOGBOOK drawer for notes (setq org-agenda-use-time-grid nil) ;; no grid at top of agenda (setq org-agenda-custom-commands '(("d" "Dashboard" ((agenda "" ((org-deadline-warning-days 30))) (todo "NEXT" ((org-agenda-overriding-header "Next Un-Scheduled Tasks"))) (todo "TODO" ((org-agenda-overriding-header "Active Un-Scheduled Tasks"))))) (" " "Agenda" ((agenda "" ((org-agenda-span 'day) (org-deadline-warning-days 7))) (todo "TODO" ((org-agenda-overriding-header "To Refile") (org-agenda-files (list (concat jmn-gtd-directory "inbox.org"))))) (todo "NEXT" ((org-agenda-overriding-header "In Progress") (org-agenda-files (list (concat jmn-gtd-directory "projects.org") (concat jmn-gtd-directory "next.org") (concat jmn-gtd-directory "inbox.org"))))) (todo "TODO" ((org-agenda-overriding-header "Projects") (org-agenda-files (list (concat jmn-gtd-directory "projects.org"))))) (todo "TODO" ((org-agenda-overriding-header "One-off Tasks") (org-agenda-files (list (concat jmn-gtd-directory "next.org")))) (org-agenda-skip-function '(org-agenda-skip-entry-if 'deadline 'scheduled))) (todo "HOLD" ((org-agenda-overriding-header "HOLD") (org-agenda-files (list (concat jmn-gtd-directory "projects.org") (concat jmn-gtd-directory "next.org") (concat jmn-gtd-directory "inbox.org"))))) )))) (defun jmn-someday() "Quick access to someday.org (no links in agenda)" (interactive) (find-file (concat jmn-gtd-directory "someday.org"))) (setq org-agenda-todo-ignore-scheduled 'all) ;; cant get it to work for deadlines
hook
(add-hook 'org-agenda-mode-hook 'hl-line-mode)
Habits
File holding habits must be added to org-agenda-files above
- habits must have the
:STYLE: habitproperty
;; org habit;; (with-eval-after-load 'org (add-to-list 'org-modules 'org-habit)) ;;(require 'org-habit) (with-eval-after-load 'org-habit (setq org-habit-graph-column (alist-get (system-name) '(("xps" . 56) ("dsk" . 52)) 50 nil 'string=))) ;; default is 40
Capture Templates
Capture templates (The Org Manual)
C-c c i: add an entry to the inboxC-c c w: add an entry to the whip- Creates a time stamp for now, need to add time for when I'd like to be reminded,
C-c . C-c C-c: adds tags to a heading
- Creates a time stamp for now, need to add time for when I'd like to be reminded,
(setq org-capture-templates `(("t" "Todo [inbox]" entry (file ,(concat jmn-gtd-directory "inbox.org")) "* TODO %i%?" :empty-lines 1) ("T" "Todo Today [inbox]" entry (file ,(concat jmn-gtd-directory "inbox.org")) "* TODO %?\nDEADLINE: %t" :empty-lines 1) ("l" "Linked Todo [inbox]" entry (file ,(concat jmn-gtd-directory "inbox.org")) "* TODO %i%? \n %a" :empty-lines 1) ("s" "Schedule" entry (file+headline ,(concat jmn-gtd-directory "whip.org") "Whip") "* %i%? \n %U %^t" :empty-lines 1) ("j" "Journal" entry (file+datetree ,(concat jmn-gtd-directory "journal.org")) "* %?\nEntered on %U\n %i\n %a" :empty-lines 1)))
Archive
(defun org-archive-done-tasks-tree () "Archive all DONE tasks in the current org tree" (interactive) (org-map-entries (lambda () (org-archive-subtree) (setq org-map-continue-from (org-element-property :begin (org-element-at-point)))) "/DONE" 'tree)) (defun org-archive-done-tasks-file () "Archive all DONE tasks in the current org file" (interactive) (org-map-entries (lambda () (org-archive-subtree) (setq org-map-continue-from (org-element-property :begin (org-element-at-point)))) "/DONE" 'file))
Process Inbox Item
https://github.com/jethrokuan/.emacs.d/blob/master/init.el
;; could set in the inbox header instead (where tags are set) (customize-set-variable 'org-global-properties '(("Effort_ALL" . "0:05 0:15 0:30 1:00 2:00 4:00"))) (defun jmn/org-agenda-process-inbox-item () "Process a single item in the org-agenda." (interactive) (org-with-wide-buffer ; what does this do? ;; (org-agenda-set-tags) ; may want in the future (org-agenda-priority) (org-agenda-set-effort) (org-agenda-refile nil nil t))) (global-set-key (kbd "C-c p") 'jmn/org-agenda-process-inbox-item)
Advice
(defmacro func-ignore (fnc) "Return function that ignores its arguments and invokes FNC." `(lambda (&rest _rest) (funcall ,fnc))) (advice-add 'org-archive-done-tasks-tree :after (func-ignore #'org-save-all-org-buffers)) (advice-add 'org-archive-done-tasks-file :after (func-ignore #'org-save-all-org-buffers)) (advice-add 'org-refile :after (func-ignore #'org-save-all-org-buffers)) (advice-add 'org-deadline :after (func-ignore #'org-save-all-org-buffers)) (advice-add 'org-schedule :after (func-ignore #'org-save-all-org-buffers)) (advice-add 'org-store-log-note :after (func-ignore #'org-save-all-org-buffers)) (advice-add 'org-todo :after (func-ignore #'org-save-all-org-buffers)) ;; if agenda is already open, update it with new capture;; work? (advice-add 'org-capture-finalize :after (func-ignore #'org-agenda-redo-all)) ;; ;; (advice-add 'org-capture-finalize ;; ;; :after (func-ignore #'org-agenda-redo-all))
Keybindings
C-c C-s: scheduled timestampC-c C-d: deadline timestampC-c C-w: refile actionable/project items from inbox to appropriate area.C-x C-s: org-save-all-org-buffersC-c C-x e: org-set-efforto: open agenda item in other window –after my change+,-,,: increase, decrease, and set priorityShift-right: advance the todo stateS-<down>: org-agenda-priority-downS-<left>: org-agenda-do-date-earlierS-<right>: org-agenda-do-date-laterS-<up>: org-agenda-priority-up
(defun jmn-agenda (&optional arg) (interactive "P") (org-agenda arg " ")) (global-set-key (kbd "C-c a") 'jmn-agenda) (with-eval-after-load 'org-agenda (define-key org-agenda-keymap (kbd "o") 'org-agenda-goto)) ;; more like dired
Terminals
term-mode
- Slower than vterm at printing large amounts of information.
- For more than one terminal, you must M-x rename-uniquely the terminal.
- C-c prefix for term commands
Line-mode vs char-mode selection shows on the modeline: C-c C-k -> char-mode C-c C-j -> line-mode
Keybindings
Just some changes to make it feel more like the other modes.
- I don't really use the
M-pnor theM-n, but they could be nice.
(with-eval-after-load 'term (define-key term-raw-map (kbd "C-o") 'other-window) (define-key term-raw-map (kbd "M-o") 'previous-multiframe-window) ;; access prev commandsin line mode, though line and char-mode rings are separate (define-key term-raw-map (kbd "M-p") 'term-send-up) (define-key term-raw-map (kbd "M-n") 'term-send-down) ;; add "C-x" as escape character and use it for keybindings (let (term-escape-char) (term-set-escape-char ?\C-x)) ; set "C-x" as an escape character (define-key term-raw-map (kbd "C-x C-k") 'kill-current-buffer) (define-key term-raw-map (kbd "C-c C-k") 'nil)) ; no only used to change from char to line mode
Better term-mode colors
Archive: melpa
(use-package eterm-256color :hook (term-mode . eterm-256color-mode))
Version 26.1
(if (version<= emacs-version "29" ) (setq explicit-shell-file-name "/bin/bash"))
vterm
Faster terminal due to being compiled. Default is a better mode than term-mode; it's like a Char-mode but with ability to access function list with M-x. vterm Documentation
- For more than one terminal, you must M-x rename-uniquely the terminal.
- C-c prefix for term commands
- C-c C-c = send C-c to the terminal (kill running command)
Extra installs needed: For some reason :ensure-system-package did not work here so it is done explicitly in the :init Need to install: cmake, libtool
(use-package vterm :ensure t :ensure-system-package ((cmake . "sudo dnf install -y cmake") (libtool . "sudo dnf install -y libtool" )) ;; compilation :defer t :bind (("C-`". vterm) ;; gets overwriteent by vterm-toggle (:map vterm-mode-map ("C-o" . other-window))) :config (jmn-remove-M-1-9-from-mode-map vterm-mode-map) (defun vterm-send-escape () "Sends `ESC` to the libvterm." (interactive) (vterm-send-key "<escape>") ) (setq vterm-max-scrollback 10000) :init (let ((package "cmake")) (unless (executable-find package) (async-shell-command (concat "sudo dnf install -y " package)))) (let ((package "libtool")) (unless (executable-find package) (async-shell-command (concat "sudo dnf install -y " package))))) (use-package vterm-toggle :after vterm :config (setq vterm-toggle-fullscreen-p nil) (global-set-key (kbd "C-`") 'vterm-toggle) (add-to-list 'display-buffer-alist '((lambda(bufname _) (with-current-buffer bufname (equal major-mode 'vterm-mode))) (display-buffer-reuse-window display-buffer-at-bottom) ;;(display-buffer-reuse-window display-buffer-in-direction) ;;display-buffer-in-direction/direction/dedicated is added in emacs27 ;;(direction . bottom) ;;(dedicated . t) ;dedicated is supported in emacs27 (reusable-frames . visible) (window-height . 0.3))))
Theme and Frame
To modify a theme it is helpful to use:
list-faces-displayto show the fonts used showing an example of how they lookdescribe-faceto show the font under the cursor
Setup and helpers
(setq custom-safe-themes t) ;; don't ask if theme is safe (add-to-list 'custom-theme-load-path "~/.emacs.d/themes/") (defun jmn-disable-all-themes() (interactive) (while custom-enabled-themes (disable-theme (car custom-enabled-themes))))
Gruvbox and Modifications
(use-package gruvbox-theme)
Modify Themes
- General Org
(deftheme jmn-gruvbox-general-org "Altering all the gruvbox themes-- load after loading the gruvbox theme") ;; changes which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("NEXT" . ,(face-foreground font-lock-function-name-face)) ("HOLD" . ,(face-foreground font-lock-builtin-face))))) ;; changes which will be undone when disabling the theme (custom-theme-set-faces 'jmn-gruvbox-general-org `(org-priority ((t (:foreground ,(face-foreground 'font-lock-constant-face))))) `(org-block-begin-line ((t (:inherit font-lock-comment-face :background ,(face-background 'default))))) `(org-block-end-line ((t (:inherit font-lock-comment-face :background ,(face-background 'default)))))) (provide-theme 'jmn-gruvbox-general-org)
- Dark
- Hard
(deftheme jmn-gruvbox-dark-hard "Altering the gruvbox-dark-hard theme-- load after loading the gruvbox theme") (let ((done-color "gray35")) ;; changes which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("NEXT" . ,(face-foreground font-lock-function-name-face)) ("HOLD" . ,(face-foreground font-lock-builtin-face)) ("DONE" . done-color) ("IGNORE" . done-color)))) ;; changes which will be undone when disabling the theme (custom-theme-set-faces 'jmn-gruvbox-dark-hard ;; Basics `(mode-line-inactive ((t (:background "gray22" :extend t)))) `(mode-line-active ((t (:background "gray35" :extend t)))) `(line-number ((t :background ,(face-attribute 'default :background)))) `(fringe ((t :background ,(face-attribute 'default :background)))) ;; org `(org-agenda-done ((t (:foreground ,done-color)))) `(org-headline-done ((t (:foreground ,done-color)))) `(org-done ((t (:foreground ,done-color)))) `(org-block ((t (:background "gray8" :extend t)))))) (provide-theme 'jmn-gruvbox-dark-hard)
- Hardest
(deftheme jmn-gruvbox-dark-hardest "Altering the gruvbox-dark-hard theme-- load after loading the gruvbox theme") (let ((done-color "gray35")) ;; changes which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("NEXT" . ,(face-foreground font-lock-function-name-face)) ("HOLD" . ,(face-foreground font-lock-builtin-face)) ("DONE" . done-color) ("IGNORE" . done-color)))) ;; changes which will be undone when disabling the theme (custom-theme-set-faces 'jmn-gruvbox-dark-hardest ;; Basics `(default ((t (:background "gray11" :extend t)))) `(link ((t (:foreground "#83a598" :extend t)))) ;;'tree-sitter-hl-face inherits it `(line-number ((t :background "gray11" :extend t ))) `(fringe ((t :background "gray11" :extend t ))) ;; treesitter `(tree-sitter-hl-face:variable ((t :foreground "#FFA500" :extend t))) `(tree-sitter-hl-face:variable.parameter ((t :foreground ,(face-attribute 'default :foreground)))) `(tree-sitter-hl-face:label ((t :foreground "#d65d0e" :extend t))) ;; org `(org-agenda-done ((t (:foreground ,done-color)))) `(org-headline-done ((t (:foreground ,done-color)))) `(org-done ((t (:foreground ,done-color)))) `(org-block ((t (:background "gray7" :extend t)))))) (provide-theme 'jmn-gruvbox-dark-hardest)
- Medium
(deftheme jmn-gruvbox-dark-medium "Altering the gruvbox-dark-medium theme-- load after loading the gruvbox theme") (let ((done-color "gray35")) ;; changes which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("NEXT" . ,(face-foreground font-lock-function-name-face)) ("HOLD" . ,(face-foreground font-lock-builtin-face)) ("DONE" . done-color) ("IGNORE" . done-color)))) ;; changes which will be undone when disabling the theme (custom-theme-set-faces 'jmn-gruvbox-dark-medium ;; Basics ;; `(default ((t (:foreground "moccasin" :extend t)))) `(line-number ((t :background ,(face-attribute 'default :background)))) `(font-lock-comment-face ((t (:foreground "#98be65" :extend t)))) ;; org `(org-agenda-done ((t (:foreground ,done-color)))) `(org-headline-done ((t (:foreground ,done-color)))) `(org-done ((t (:foreground ,done-color)))))) (provide-theme 'jmn-gruvbox-dark-medium)
- Hard
- Light
- Hard
(deftheme jmn-gruvbox-light-hard "Altering the gruvbox-light-hard theme-- load after loading the gruvbox theme") (let ((done-color "Navajowhite3")) ;; changes which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("NEXT" . ,(face-foreground font-lock-function-name-face)) ("HOLD" . ,(face-foreground font-lock-builtin-face)) ("DONE" . done-color) ("IGNORE" . done-color)))) ;; changes which will be undone when disabling the theme (custom-theme-set-faces 'jmn-gruvbox-light-hard ;; org `(org-agenda-done ((t (:foreground ,done-color)))) `(org-headline-done ((t (:foreground ,done-color)))) `(org-done ((t (:foreground ,done-color)))) `(org-block ((t (:background "#fbf1c7" :extend t)))))) (provide-theme 'jmn-gruvbox-light-hard)
- Medium
(deftheme jmn-gruvbox-light-medium "Altering the gruvbox-light-medium theme-- load after loading the gruvbox theme") (let ((done-color "Navajowhite3")) ;; changes which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("NEXT" . ,(face-foreground font-lock-function-name-face)) ("HOLD" . ,(face-foreground font-lock-builtin-face)) ("DONE" . done-color) ("IGNORE" . done-color)))) ;; changes which will be undone when disabling the theme (custom-theme-set-faces 'jmn-gruvbox-light-medium ;; org `(org-agenda-done ((t (:foreground ,done-color)))) `(org-headline-done ((t (:foreground ,done-color)))) `(org-done ((t (:foreground ,done-color)))))) (provide-theme 'jmn-gruvbox-light-medium)
- Soft
(deftheme jmn-gruvbox-light-soft "Altering the gruvbox-light-soft theme-- load after loading the gruvbox theme") (let ((done-color "Navajowhite3")) ;; changes which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("NEXT" . ,(face-foreground font-lock-function-name-face)) ("HOLD" . ,(face-foreground font-lock-builtin-face)) ("DONE" . done-color) ("IGNORE" . done-color)))) ;; changes which will be undone when disabling the theme (custom-theme-set-faces 'jmn-gruvbox-light-soft ;; org `(org-agenda-done ((t (:foreground ,done-color)))) `(org-headline-done ((t (:foreground ,done-color)))) `(org-done ((t (:foreground ,done-color)))) `(org-block ((t (:background "#ebdbb2" :extend t)))))) (provide-theme 'jmn-gruvbox-light-soft)
- Hard
Loading functions
(defun jmn-load-gruvbox-dark-medium () "Theme for a medium dark time" (interactive) (jmn-disable-all-themes) (load-theme 'gruvbox-dark-medium ) (load-theme 'jmn-gruvbox-general-org) (load-theme 'jmn-gruvbox-dark-medium)) (defun jmn-load-gruvbox-dark-hard () "Theme for dark time" (interactive) (jmn-disable-all-themes) (load-theme 'gruvbox-dark-hard ) (load-theme 'jmn-gruvbox-general-org) (load-theme 'jmn-gruvbox-dark-hard)) (defun jmn-load-gruvbox-dark-hardest() "Theme for very darkest of times" (interactive) (jmn-disable-all-themes) (load-theme 'gruvbox-dark-hard ) (load-theme 'jmn-gruvbox-general-org) (load-theme 'jmn-gruvbox-dark-hardest)) (defun jmn-load-gruvbox-light-medium() "Theme for light time" (interactive) (jmn-disable-all-themes) (load-theme 'gruvbox-light-medium ) (load-theme 'jmn-gruvbox-general-org) (load-theme 'jmn-gruvbox-light-medium)) (defun jmn-load-gruvbox-light-hard() "Theme for very light time" (interactive) (jmn-disable-all-themes) (load-theme 'gruvbox-light-hard ) (load-theme 'jmn-gruvbox-general-org) (load-theme 'jmn-gruvbox-light-hard)) (defun jmn-load-gruvbox-light-soft() "Theme for very light time" (interactive) (jmn-disable-all-themes) (load-theme 'gruvbox-light-soft ) (load-theme 'jmn-gruvbox-general-org) (load-theme 'jmn-gruvbox-light-soft))
Pure Themes
Modifying Themes
- Light
(deftheme jmn-light "Altering the default theme-- load after loading the default theme") ;; variables which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("TODO" . "Red1") ("NEXT" . "orange") ("HOLD" . "Black") ("IGNORE" . "gray60")))) (custom-theme-set-faces 'jmn-light ;; Org-mode `(org-block ((t (:background "gray93" :extend t)))) ;; Tab bar '(tab-bar ((t (:inherit org-default :extend t)))) `(tab-bar-tab ((t (:background "darkseagreen2")))) '(tab-bar-tab-inactive ((t (:inherit org-default :extend t))))) (provide-theme 'jmn-light)
- Wombat
(deftheme jmn-wombat "Altering the wombat theme-- load after loading the wombat theme") ;; variables which will be permanent (with-eval-after-load 'org (setq org-todo-keyword-faces `(("TODO" . "Pink") ("NEXT" . "gold2") ("HOLD" . "orange3") ("IGNORE" . "#99968b")))) (custom-theme-set-faces 'jmn-wombat ;; Basics `(mode-line ((t (:background "gray44" :extend t)))) ;; Org-mode `(org-block ((t (:background "gray10" :extend t)))) `(org-level-7 ((t (:background "MediumPurple1" :extend t)))) ;; Tab bar '(tab-bar ((t (:inherit org-default :extend t)))) '(tab-bar-tab ((t (:inherit mode-line :weight bold :box nil :extend t)))) '(tab-bar-tab-inactive ((t (:inherit org-default :extend t))))) (provide-theme 'jmn-wombat)
Loading functions
(defun jmn-load-pure-light-theme() (interactive) (jmn-disable-all-themes) (load-theme 'jmn-light)) (defun jmn-load-pure-dark-theme() (interactive) (jmn-disable-all-themes) (load-theme 'wombat) (load-theme 'jmn-wombat))
Startup Theme switches
(if jmn-dark-mode (if (eq system-type 'gnu/linux) ;; dark theme looks bad on windows (if jmn-pure (jmn-load-pure-dark-theme) ;; dark, linux, pure (jmn-load-gruvbox-dark-hardest)) (load-theme 'jmn-light)) ;; dark on windows (show light) (load-theme 'jmn-light)) ;; non-dark
Frame Height
(if (window-system) (set-frame-height (selected-frame) 53))
Shell Backend and Windows Core Setup
TODO Linux
This allows aliases set in .bashrc can then be used when running shells
It also does not causes a print of errors which stops the use of getenv
(if (eq system-type 'gnu/linux) (setq shell-command-switch "-ic")) ;; add -i so it loads .bashrc (aliases!)
Windows
Major changes for windows. Small changes also exist in the rest of the config.
(cond ((eq system-type 'windows-nt) ;;set font (when (member "Consolas" (font-family-list)) (set-frame-font "Consolas" t t)) (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) ;; needed? (add-hook 'term-mode-hook 'ansi-color-for-comint-mode-on) ;; needed? ;; (setq explicit-shell-file-name "c:/Program Files/Git/bin/bash.exe") ;; gitbash (setq explicit-shell-file-name "c:/Program Files/Emacs/libexec/emacs/27.2/x86_64-w64-mingw32/cmdproxy.exe") ;; Emacs recommended (setq shell-file-name explicit-shell-file-name) ;; give emacs access to gnu coreutils, though should already be in =path= (add-to-list 'exec-path "c:/Program Files/Git/") ;; git-bash, git-cmd (add-to-list 'exec-path "c:/Program Files/Git/bin") ;; bash (add-to-list 'exec-path "c:/Program Files/Git/usr/bin") ;; coreutils (diff, ls, etc.) (add-to-list 'exec-path "c:/Program Files/Python312") ;; python-- not working ;; likey no octave, so read only matlab files (add-hook 'octave-mode-hook 'read-only-mode) ;; external ls for directories first support (dired) -- may not be needed with above (setq ls-lisp-use-insert-directory-program t) ;; use external ls (setq inserft-directory-program "c:/Program Files/Git/user/bin/ls.exe") ;; ls loc ))
Hacky Fixes
Corrects error: File mode specification error: (error Invalid image type ‘svg’) (not used)
(setq image-types '(svg png gif tiff jpeg xpm xbm pbm))
Keep transparency when toggling to full-screen in Emacs 29+
Was needed at one point– keeping just in case it is need in the future.
(if (version<= "29" emacs-version) (progn (defun toggle-full-screen-with-transparency () "Toggle full screen and adjust frame transparency." (interactive) (let ((current-alpha (frame-parameter nil 'alpha-background))) (transparency 100) (toggle-frame-fullscreen) (sit-for 0.7) (transparency current-alpha) )) ;; (global-unset-key (kbd "<f11>")) ;; (global-set-key (kbd "<f11>") 'toggle-full-screen-with-transparency) ))
Transparency in term (emacs -nw)
source: https://github.com/syl20bnr/spacemacs/issues/7262
(defun jmn-set-background-unspecified () "Set background of buffer and line numbers to unspecified" (interactive) (set-face-background 'default "unspecified-bg" (selected-frame)) (set-face-background 'line-number "unspecified-bg")) (if jmn-term (add-hook 'window-setup-hook 'jmn-set-background-unspecified))
Org LaTeX Preview
For unknown reasons I must change ("dvipng -D %D -T tight -o %O %f") to ("dvipng -D %D -T tight -o %O %F") to preview LaTeX in org-mode. All of the code below is used only to make this one small change.
(setq org-preview-latex-process-alist '((dvipng :programs ("latex" "dvipng") :description "dvi > png" :message "you need to install the programs: latex and dvipng." :image-input-type "dvi" :image-output-type "png" :image-size-adjust (1.0 . 1.0) :latex-compiler ("latex -interaction nonstopmode -output-directory %o %f") :image-converter ("dvipng -D %D -T tight -o %O %F") :transparent-image-converter ("dvipng -D %D -T tight -bg Transparent -o %O %f")) (dvisvgm :programs ("latex" "dvisvgm") :description "dvi > svg" :message "you need to install the programs: latex and dvisvgm." :image-input-type "dvi" :image-output-type "svg" :image-size-adjust (1.7 . 1.5) :latex-compiler ("latex -interaction nonstopmode -output-directory %o %f") :image-converter ("dvisvgm %f --no-fonts --exact-bbox --scale=%S --output=%O")) (imagemagick :programs ("latex" "convert") :description "pdf > png" :message "you need to install the programs: latex and imagemagick." :image-input-type "pdf" :image-output-type "png" :image-size-adjust (1.0 . 1.0) :latex-compiler ("pdflatex -interaction nonstopmode -output-directory %o %f") :image-converter ("convert -density %D -trim -antialias %f -quality 100 %O"))))
Setting Org-figures width
- Won't work with
#+ATTR_ORG :width 600 - This will set it globally for the time being
(setq org-image-actual-width 600)
Set certain file extensions to read only buffer
(defun jmn-set-files-read-only () "Set buffers to read only if have one of the extensions hard coded in the function" (dolist (extension'("dat" "out")) (if (string-match extension (car (last (split-string (buffer-name) "\\.")))) (read-only-mode 1)))) (add-hook 'find-file-hook 'jmn-set-files-read-only)
Set certain file extensions to display line numbers
(defun jmn-set-files-display-line-numbers () "Set buffers to read only if have one of the extensions hard coded in the function" (dolist (extension'("txt")) (if (string-match extension (car (last (split-string (buffer-name) "\\.")))) (display-line-numbers-mode 1)))) (add-hook 'find-file-hook 'jmn-set-files-display-line-numbers)
Startup and Tabs
Recentf
Recentf is needed for recent files on the dashboard.
(recentf-mode 1) ;; needed for recent files in dashboard (setq recentf-max-menu-items 25) ;; max number of entries ;; (run-at-time nil (* 5 60) 'recentf-save-list) ;; save recent files periodically ;; Exclude the following files from the recents list (add-to-list 'recentf-exclude "~/.emacs.d/recentf") (add-to-list 'recentf-exclude (concat jmn-gtd-directory "inbox.org")) (add-to-list 'recentf-exclude (concat jmn-gtd-directory "next.org")) (add-to-list 'recentf-exclude (concat jmn-gtd-directory "whip.org")) (add-to-list 'recentf-exclude (concat jmn-gtd-directory "someday.org")) (add-to-list 'recentf-exclude (concat jmn-gtd-directory "journal.org")) (add-to-list 'recentf-exclude (concat jmn-gtd-directory "habits.org")) (add-to-list 'recentf-exclude (concat (file-name-directory jmn-config-location) "emacs.html")) (if (or jmn-pure (not jmn-connected-extras)) (progn ;; display recent files on startup ;; (add-hook 'after-init-hook (lambda () (recentf-open-files))) ;; display projects.org on startup (add-hook 'after-init-hook (lambda () (find-file (concat jmn-gtd-directory "projects.org")))) ;; make display recent files the dashboard command (global-set-key (kbd "C-c d") 'recentf-open-files)))
Tabs
(if (version<= "27" emacs-version) (progn (setq tab-bar-close-button-show nil ; remove close button tab-bar-show 1 ; only show tab bar if #tabs>1 tab-bar-select-tab-modifiers '(meta) ; Alt-i switch to the tab numbered i tab-bar-tab-hints t) ; show a number on each tabs (tab-bar-mode 1) (tab-bar-close-other-tabs) ; ensures (tab-bar-mode 1) works on older systems (defun jmn-create-my-tabs() "Create my default tabs" (interactive) (tab-close-other) (delete-other-windows) ;; TAB 1 (tab-bar-rename-tab "gtd") (find-file (concat jmn-gtd-directory "projects.org")) (jmn-agenda) ;; TAB 2 (tab-bar-new-tab) (tab-bar-rename-tab "workspace") (dired "/home/ape/Programming/projects/radar/radar-signal-processing") (unless jmn-pure (magit-status)) ;; ;; TAB ;; (tab-bar-new-tab) ;; (if jmn-pure ;; (progn ;; (term "/bin/bash") ;; (tab-bar-rename-tab "term")) ;; (progn ;; (vterm) ;; (tab-bar-rename-tab "vterm"))) ;; (delete-other-windows) ;; TAB N (tab-bar-new-tab) (tab-bar-rename-tab "config") (find-file jmn-config-location) (unless jmn-pure (magit-status)) (tab-bar-select-tab 2))))
Dashboard
Dash board for initial startup of emacs. github link
- For the icons to display correctly, I needed to execute
all-of-the-icons-install-fonts.
(if jmn-connected-extras (progn (defun my-dashboard-hook() "Needed to define these after hook for some reason" (define-key dashboard-mode-map (kbd "n") 'dashboard-next-line) (define-key dashboard-mode-map (kbd "p") 'dashboard-previous-line)) (use-package dashboard :ensure t :init (dashboard-setup-startup-hook) :bind ("C-c d" . dashboard-open) :hook ((dashboard-mode . hl-line-mode) (dashboard-mode . my-dashboard-hook)) :config (setq dashboard-banner-logo-title "Habits, not goals.") (setq dashboard-startup-banner 2) ;; (nil . no-banner) ([1-5] . plain-text banners) (setq dashboard-center-content 1) (setq dashboard-show-shortcuts 1) ;; show the single-character shortcuts (setq dashboard-items '((recents . 5) (bookmarks . 5) (projects . 5) (agenda . 5) (registers . 5))) (setcdr (assoc 'projects dashboard-item-shortcuts) "j") (setq dashboard-set-heading-icons t) (setq dashboard-set-file-icons t) (setq dashboard-projects-backend 'project-el) (dashboard-modify-heading-icons '((recents . "file-text"))) (setq dashboard-set-footer nil) (setq dashboard-startupify-list '(dashboard-insert-banner dashboard-insert-newline dashboard-insert-banner-title dashboard-insert-newline dashboard-insert-init-info dashboard-insert-items dashboard-insert-newline ;;dashboard-insert-footer )))))
Recreation
Hacker News Reader
(unless jmn-pure (use-package hnreader))
gptel
To highlight the LLM response, use gptel-highlight-mode
- requires transient – shipped in emacs in 29.1
;; Helper function to read from authinfo.gpg (defun my-get-api-key (host) (let ((entry (car (auth-source-search :host host)))) (when entry (funcall (plist-get entry :secret))))) ;; Configure gptel to use the keys (use-package gptel :defer t :ensure t :config (global-set-key(kbd "C-c RET") 'gptel-send) (setq gptel-default-mode 'org-mode) (gptel-make-gemini "Gemini" :key (my-get-api-key "generativelanguage.googleapis.com") :stream t) (setq gptel-model 'gemini-2.5-pro gptel-backend (gptel-make-gemini "Gemini" :key (my-get-api-key "generativelanguage.googleapis.com") :stream t)) ) (use-package gptel-agent)