NICEMACS
Table of Contents
- Nicemacs v2
- Preamble
- STUFF 1
- Evil
- Appearance
- Which-key
- Diff-ing files
- Window management
- Shells
- Dired
- Buffers, files, and dired
- STUFF 2
- Yasnippet
- STUFF 3
- Magit
- Emacs lisp
- Emacs Speaks Statistics (ESS)
- MATLAB EXCLUDED
- RealGUD debugging
- Python
- Scheme/Racket EXCLUDED
- LaTeX/BibTeX
- Markdown
- Org-mode
- STUFF 8
- Copilot
- Rust
- STUFF 9
- GNU Emacs
Nicemacs v2
Preamble
;;; Nicemacs.v2 -*- lexical-binding: t -*- ;;; ================================================================== ;; ;; ███╗ ██╗██╗ ██████╗███████╗███╗ ███╗ █████╗ ██████╗███████╗ ;; ████╗ ██║██║██╔════╝██╔════╝████╗ ████║██╔══██╗██╔════╝██╔════╝ ;; ██╔██╗ ██║██║██║ █████╗ ██╔████╔██║███████║██║ ███████╗ ;; ██║╚██╗██║██║██║ ██╔══╝ ██║╚██╔╝██║██╔══██║██║ ╚════██║ ;; ██║ ╚████║██║╚██████╗███████╗██║ ╚═╝ ██║██║ ██║╚██████╗███████║ ;; ╚═╝ ╚═══╝╚═╝ ╚═════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚══════╝ ;; ;; To update your packages carry out the following steps: ;; ;; 1. M-x list-packages ;; 2. Press `r' to refresh ;; 3. Press `U' to mark upgradable packages ;; 4. Press `x' to execute the upgrades ;; ;; ;; Maybe just: don't neglect the Elisp manual. I've read it _far_ ;; more than the regular Emacs manual, and it's surprisingly fun. ;; Seeing Emacs as an interactive lisp machine to be programmed ;; rather than an editor to be configured makes many things easier. ;; ;; ~ Tim Vaughan (2023) ;; ;; Packages used ;; ------------- ;; ;; - `cl-lib' ;; - `copilot' ;; - `dired' ;; - `editorconfig' EditorConfig Emacs Plugin ;; - `ess' Emacs Speaks Statistics ;; - `evil' Extensible Vi layer for Emacs. ;; - `evil-collection' A set of keybindings for Evil mode ;; - `evil-leader' let there be <leader> ;; - `evil-mc' ;; - `evil-mc-extras' Extra functionality for evil-mc ;; - `evil-surround' ;; - `flyspell' ;; - `hl-todo' Highlight TODO and similar keywords ;; - `htmlize' Convert buffer text and decorations to HTML. ;; - `ligature' Ligature support for Emacs. ;; - `lorem-ipsum' Insert dummy pseudo Latin text ;; - `magit' A Git porcelain inside Emacs. ;; - `markdown-mode' Major mode for Markdown-formatted text ;; - `multiple-cursors' Multiple cursors for Emacs. ;; - `pyvenv' Python virtual environment interface ;; - `quarto-mode' A (poly)mode for https://quarto.org ;; - `rainbow-mode' Colorize color names in buffers ;; - `realgud' A front-end for interacting debuggers ;; - `s' The long lost Emacs string manipulation library. ;; - `unfill' Do the opposite of fill-paragraph or fill-region ;; - `which-key' Display available keybindings in popup ;; - `writegood-mode' Polish up poor writing on the fly ;; - `yasnippet' Yet another snippet extension for Emacs ;; - `yasnippet-snippets' Collection of yasnippet snippets ;; ;; Changelog ;; --------- ;; ;; - 2024-07 ;; + Use `openwith' so that `dired' will open PDFs with Okular on ;; click rather than the emacs PDF viewer. ;; ;; - 2024-05 ;; + Add binding of SPC-m-s-s to evaluate R source blocks in ;; org-mode. (This is C-c C-c by default.) ;; + Add some ESS keybindings to `markdown-mode' so they are available when ;; writing Rmarkdown. ;; + Bug fix where ESS couldn't find the directory where the ESS-R ;; files are. This is now fixed by looking up a plausible ;; directory and setting `ess-etc-directory' to that. ;; ;; - 2024-03 ;; + Use `org-agenda-start-with-log-mode' to show the log mode items ;; in the agenda. ;; + `.Rmd' files should also open in `markdown-mode'. ;; + Use the `:exclude' pattern to be a bit more selective with the ;; files that get copied by `org-publish' (i.e. do not ;; accidentally copy a whole Python virtual environment.) ;; ;; - 2024-02 ;; + Tweak `revert-without-query' to make it easier to use PNG files ;; ;; - 2024-01 ;; + Add `yaml-mode'. ;; + Add `snakemake-mode' for Snakemake in Python. ;; + Introduce a new org-mode todo state: SEMINAR ;; + Update publishing functionality. ;; + Add `python' to the list of languages used by Babel. ;; ;; - 2023-12 ;; + Abbreviate the eshell prompt in a nice way. ;; + Include emoji keybinding amount yasnippet bindings since they ;; play a similar role. ;; ;; - 2023-11 ;; + Refactor window selection. ;; + Configure size of latex previews in org-mode. ;; + Clean up snippet configuration. ;; ;; - 2023-10 ;; + Add a scrartcl class to `org-latex-classes' as nicer org-mode ;; PDF export option. ;; ;; - 2023-09 ;; + Use `evil-window-X' functions as a simpler alternative to ;; `winum'. ;; + Use `IBuffer' to manage buffers. ;; + Use `avy' to jump to lines in a buffer using a character. ;; ;; - 2023-08 ;; + Use `indent-guide' to visualise indentation in `python-mode'. ;; + Use `org-agenda-window-setup' to open agenda in a new frame. ;; + Use `org-log-done' to record when tasks where completed. ;; + Upgrade to Emacs 29.1 and enable smooth scrolling. ;; ;; - 2023-07 ;; + Re-organised the themeing and started Leuven. ;; + Isolate theme configuration so it is easier to edit. ;; + Set up debugging with `realgud' (for Python). ;; + Improve window management. ;; + Set up a major mode for MATLAB. ;; + Introduce a new org-mode todo states. ;; + Avoid annoying warning from `git' by setting `GIT_PAGER' to ;; `cat'. ;; ;; - 2023-06 ;; + Include the `cdf' function for easier eshell navigation. ;; + Include keys for ESS devtools integration. ;; + Include wrapper around `pp-emacs-lisp-code'. ;; + Add some configuration for `nxml-mode'. ;; + Start using `polymode' (and friends) so I can write R with from ;; within `org-mode'. ;; + Configure the `fill-column' to use a clearer face. ;; ;; - 2023-05 ;; + Use the `use-package' macro. ;; + Use the `calfw' package for a calendar view of my agenda ;; + Remove racket/scheme pacakge ;; + Include option to accept AI suggestions line by line. ;; + Include a linter function for R (using `formatR'). ;; + Use the `unfill' package for better paragraph un/filling. ;; + Use the `lorem-ipsum' package for convenient dummy text. ;; + Include python configuration. ;; ;; - 2023-04 ;; + Set up an org-mode file for documentation with tangling and ;; detangling. ;; + Use `S <x>` in visual mode to surround the region in <x>. ;; + Use `SPC b s <x>` to open a scratch buffer in mode<x> ;; + Edit `message-buffer-file-name' so it works in `dired'. ;; + Extend `before-save-hook' to avoid accidental trailing ;; whitespace. ;; + Use JetBrains Mono as the font with ligatures. ;; ;;; ==================================================================
STUFF 1
(require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (eval-when-compile (require 'use-package)) (require 'bind-key) (setq user-full-name "Alexander E. Zarebski") (defvar nice-journal-directory "~/Documents/journal/" "The directory for nicemacs journal files.") (defvar nice-notes-directory "~/public-site/org/notes" "The directory for nicemacs notes files.") (defvar nice-website-directory "~/aezarebski.github.io/" "The directory for my website.") (defvar nice-resources-dir "~/Documents/nicemacs/resources" "The path to the nicemacs resources directory on this machine.") (defvar nice-nicemacs-directory "~/Documents/nicemacs" "The path to the nicemacs directory on this machine.") (defvar nice-snippet-directory "~/.emacs.d/snippets" "The path to the whipper snipper directory on this machine.") (use-package cl-lib :ensure t)
Evil
Setting the scroll-margin
to 2 will start scrolling when the point is one line
from the top or bottom of the window and setting scroll-conservatively
to a
value greater than 100 means that it will keep the point in place while
scrolling (which gives a smoother scroll).
;; Be evil ;; ------- ;; ;; Evil surroundings ;; ;; 1. Enter visual mode and select the text as the region. ;; 2. Press `S'. ;; 3. Type the symbol to surround it (note, if it is part of a opening ;; and closing pair, the opening includes a space and the closing ;; does not.) ;; (setq evil-want-keybinding nil) (use-package evil :ensure t :init (evil-mode 1)) (use-package evil-leader :ensure t :config (evil-leader-mode 1) (global-evil-leader-mode 1) (evil-leader/set-key "t s" 'evil-surround-mode) (evil-leader/set-leader "<SPC>") (evil-leader/set-key "<SPC>" 'execute-extended-command)) (use-package evil-collection :ensure t :config (evil-collection-init)) (use-package evil-surround :ensure t :config (global-evil-surround-mode 1)) (use-package avy :ensure t :config (evil-leader/set-key "J" 'avy-goto-line))
Appearance
Fonts
;; Fonts ;; ----- ;; ;; To install JetBrains Mono, or any other font, follow these steps: ;; ;; 1. Download and extract the font, you should have a "ttf" directory ;; containing the font files. ;; 2. Create a font directory if you don't already have one ;; $ mkdir -p ~/.local/share/fonts ;; 3. Copy the font files to the font directory: ;; $ cp path/to/extracted/ttf/*.ttf ~/.local/share/fonts ;; 4. Update the font cache: ;; $ fc-cache -f -v ;; (set-frame-font "JetBrains Mono" nil t) (ligature-set-ligatures 'prog-mode '("|>" "<-" "<<-" "==" "!=" ">=" "<=")) (global-ligature-mode nil) (defun toggle-ligatures () "Toggle ligatures on and off." (interactive) (if (bound-and-true-p global-ligature-mode) (global-ligature-mode -1) (global-ligature-mode 1))) (evil-leader/set-key "t l" 'toggle-ligatures)
General
;; Look stunning ;; ------------- ;; ;; `pixel-scroll-precision-mode' means you can have smooth scrolling ;; if you have a compatible mouse. ;; (tool-bar-mode -1) ; remove the tool bar (pixel-scroll-precision-mode 1) (setq pixel-dead-time 0) (setq scroll-margin 2 scroll-conservatively 101 scroll-preserve-screen-position 1) (setq-default scroll-bar-width 10) (setq-default left-fringe-width 10) (setq-default right-fringe-width 10) ;; I dislike trailing whitespace creeping into my files so the ;; following will make it visible and automatically remove it upon ;; saving. NOTE setting `show-trailing-whitespace' globally leads to ;; some things being highlighted in other buffers such as `calendar' ;; where they should not be hightlight. Doing it with ;; `nice-show-trailing-whitespace' ensures it is set locally as ;; appropriate. (defun nice-show-trailing-whitespace () "Enable trailing whitespace highlighting only when editing a file." (setq show-trailing-whitespace (buffer-file-name))) (add-hook 'find-file-hook 'nice-show-trailing-whitespace) (add-hook 'before-save-hook 'delete-trailing-whitespace) (use-package hl-todo :ensure t :config (global-hl-todo-mode) (global-hl-line-mode t)) (defun boxed-face (colour &optional background line-width) "Create a face with a specified foreground COLOUR and optional BACKGROUND. If LINE-WIDTH is not specified, it defaults to 1. This face will be bold and boxed with the same colour as the foreground." (let ((width (or line-width 1))) `((t (:foreground ,colour :weight bold :background ,background :box (:line-width ,width :color ,colour)))))) (setq hl-todo-keyword-faces `(("TODO" . ,(boxed-face "red" "#ffc8c8")) ("FIXME" . ,(boxed-face "magenta")) ("NOTE" . ,(boxed-face "cyan")) ("DONE" . ,(boxed-face "blue" "#E6ECFF")))) (setq fill-column 70) (defun nice-toggle-fill-column-indicator () "Toggle display of the fill column indicator. When active, the indicator is set to a vertical line. It also turns on `display-fill-column-indicator-mode' if it's not already active, and turns it off if it is." (interactive) (display-fill-column-indicator-mode 'toggle) (when display-fill-column-indicator-mode (setq display-fill-column-indicator-character ?\u2502) (set-face-attribute 'fill-column-indicator nil :foreground "magenta" :weight 'bold))) (evil-leader/set-key "t f" 'nice-toggle-fill-column-indicator)
Theme: Leuven
(setq nice-light-theme 'leuven nice-dark-theme 'leuven-dark) (load-theme nice-light-theme t) (defun nice-toggle-theme () "Toggle between my light and dark themes." (interactive) (if (eq (car custom-enabled-themes) nice-light-theme) (progn (disable-theme nice-light-theme) (load-theme nice-dark-theme t)) (progn (disable-theme nice-dark-theme) (load-theme nice-light-theme t)))) (evil-leader/set-key "t t" 'nice-toggle-theme)
Theme: Solarized EXCLUDED
(setq nice-colours-alist '((strong-warning . "red") (weak-warning . "magenta") (weak-note . "cyan") (strong-note . "blue") (light-theme-comment-background . "#e4ecda") (light-theme-comment-foreground . "#207e7b") (light-theme-shadow-background . "#eee8d5") (light-theme-shadow-foreground . "#93a1a1") (dark-theme-comment-background . "#207e7b") (dark-theme-comment-foreground . "#e4ecda") (dark-theme-shadow-background . "#202c2a") (dark-theme-shadow-foreground . "#254d48"))) (defun nice-colour (colour) "Return the colour associated with the symbol COLOUR." (cdr (assoc colour nice-colours-alist))) (set-face-attribute 'hl-line nil :background (nice-color 'light-theme-shadow-background) (add-to-list `custom-theme-load-path "~/.emacs.d/themes/") (load-theme 'solarized-light-high-contrast t) (defun nice-set-theme (theme comment-bg comment-fg shadow-bg shadow-fg) (load-theme theme t) (let ((comment-face `((t (:background ,comment-bg :foreground ,comment-fg :slant normal))))) (setq font-lock-comment-delimiter-face comment-face) (setq font-lock-comment-face comment-face)) (set-face-background 'mode-line comment-bg) (set-face-foreground 'mode-line comment-fg) (set-face-background 'mode-line-inactive shadow-bg) (set-face-foreground 'mode-line-inactive shadow-fg)) (defun nice-toggle-themes () "Toggle between two themes: solarized-light-high-contrast and solarized-dark-high-contrast and adjust the comment face to one that is visible in both." (interactive) (if (eq (car custom-enabled-themes) 'solarized-light-high-contrast) (progn (disable-theme 'solarized-light-high-contrast) (nice-set-theme 'solarized-dark-high-contrast (nice-colour 'dark-theme-comment-background) (nice-colour 'dark-theme-comment-foreground) (nice-colour 'dark-theme-shadow-background) (nice-colour 'dark-theme-shadow-foreground))) (progn (disable-theme 'solarized-dark-high-contrast) (nice-set-theme 'solarized-light-high-contrast (nice-colour 'light-theme-comment-background) (nice-colour 'light-theme-comment-foreground) (nice-colour 'light-theme-shadow-background) (nice-colour 'light-theme-shadow-foreground))))) (evil-leader/set-key "t t" 'nice-toggle-themes)
Other
;; Rainbow-mode will highlight strings indicating colours, ;; e.g. hexcodes in their corresponding colour. (use-package rainbow-mode :ensure t :hook ((emacs-lisp-mode . rainbow-mode) (ess-mode . rainbow-mode))) (setq inhibit-splash-screen t) (evil-leader/set-key "z j" 'text-scale-decrease "z k" 'text-scale-increase) ;; Be sensible ;; ----------- (use-package unfill :ensure t :bind ("M-q" . unfill-toggle)) (evil-leader/set-key "q r" 'restart-emacs "q q" 'save-buffers-kill-emacs) ;; Frame related commands will have keys starting with `F'. (evil-leader/set-key "F f" 'toggle-frame-fullscreen) (defun nice-pop-out-window () "Pop the current window out into a new frame. If there is only a single window then do nothing because it is already in its own frame." (interactive) (unless (one-window-p) (let ((current-buffer (current-buffer))) (delete-window) (display-buffer-pop-up-frame current-buffer nil)))) (evil-leader/set-key "F p" 'nice-pop-out-window)
Which-key
Get information on partial keys to help you remember/discover functionality.
;; The which-key package is a great way to be reminded of what keys ;; are available from the start of a key sequence. (use-package which-key :ensure t :config (which-key-mode) (setq which-key-idle-delay 0.3)) (setq key-description-pairs '(("SPC a" . "Agenda (org-mode)") ("SPC b" . "Buffers/Babel") ("SPC c" . "Cursors") ("SPC c" . "Delete") ("SPC f" . "Files/Dired") ("SPC F" . "Frame") ("SPC g" . "Git (magit)") ("SPC g c" . "Commits") ("SPC H" . "HELP!!!") ("SPC m" . "Major") ("SPC m v" . "EnVironment") ("SPC m d" . "devtools (ESS)") ("SPC m s" . "REPL (prog)/Sort (dired)") ("SPC m c" . "Code lint/format") ("SPC q" . "Quit/Exit") ("SPC s" . "Shell/Search") ("SPC S" . "Spelling") ("SPC t" . "Toggles") ("SPC v" . "Visitors") ("SPC v b" . "Bibtex") ("SPC v f" . "Files") ("SPC v d" . "Directories") ("SPC w" . "Windows") ("SPC y" . "Yasnippet") ("SPC z" . "Zoom (without a mouse)"))) (dolist (pair key-description-pairs) (which-key-add-key-based-replacements (car pair) (cdr pair)))
Diff-ing files
Meld provides a convenient GUI based method for assessing the differences between files.
;; Diffing files with meld ;; ----------------------- ;; ;; + f m a - will diff the aspell dictionary ;; + f m i - will diff the emacs init ;; + f m m - will prompt for two files to diff ;; (defmacro nice-meld-files (name fa fb key) "Generate function named nice-meld-NAME which opens meld diff for files FA and FB using SPC f m KEY." `(progn (defun ,(intern (format "nice-meld-%s" name)) () (interactive) (async-shell-command ,(format "meld %s %s &" fa fb))) (evil-leader/set-key ,(concat "f m " key) (intern ,(format "nice-meld-%s" name))))) (nice-meld-files "init" "~/.emacs.d/init.el" "~/Documents/nicemacs/nicemacs-v2.el" "i") (nice-meld-files "aspell" "~/.aspell.en.pws" "~/Documents/nicemacs/resources/aspell.en.pws" "a") (defun nice-meld () "Prompt for two files and show the difference between them using `meld`." (interactive) (let ((file1 (read-file-name "First file: ")) (file2 (read-file-name "Second file: "))) (shell-command (format "meld %s %s &" file1 file2)))) (evil-leader/set-key "f m m" 'nice-meld)
Window management
Number based solution from winum
EXCLUDED
;; The `winum' package facilitates switching between windows using ;; numbers which appear in the bottom left hand of the window, at the ;; start of the mode-line. (use-package winum :ensure t :config (winum-mode) (setq winum-format " %s ")) (set-face-attribute 'winum-face nil :foreground "black" :background "gold" :weight 'bold :underline nil :height 1.1) (evil-leader/set-key "0" 'winum-select-window-0 "1" 'winum-select-window-1 "2" 'winum-select-window-2 "3" 'winum-select-window-3 "4" 'winum-select-window-4 "5" 'winum-select-window-5 "w a" 'nice-balance-windows-alt "w b" 'balance-windows "w n s" 'nice-swap-buffers) (defun nice-swap-buffers () "Swap buffers between two windows specified by their numbers. Prompt for two window numbers and swap the buffers displayed in those windows. Window numbers are assigned by the `winum' package." (interactive) (let* ((win1 (winum-get-window-by-number (read-number "First window number: "))) (win2 (winum-get-window-by-number (read-number "Second window number: "))) (buffer1 (and win1 (window-buffer win1))) (buffer2 (and win2 (window-buffer win2)))) (when (and buffer1 buffer2) (set-window-buffer win1 buffer2) (set-window-buffer win2 buffer1))))
Evil window management
(defmacro define-nice-window-move (name move-func) `(defun ,name () (interactive) (,move-func 1) (let ((ov (make-overlay (point-min) (point-max)))) (overlay-put ov 'window (selected-window)) (overlay-put ov 'face '(:background "magenta")) (sit-for 0.1) (delete-overlay ov)))) (define-nice-window-move nice-window-up evil-window-up) (define-nice-window-move nice-window-down evil-window-down) (define-nice-window-move nice-window-left evil-window-left) (define-nice-window-move nice-window-right evil-window-right) (evil-leader/set-key "k" 'nice-window-up "j" 'nice-window-down "h" 'nice-window-left "l" 'nice-window-right "w a" 'nice-balance-windows-alt "w b" 'balance-windows "w s" 'split-window-below "w v" 'split-window-right "w L" 'evil-window-move-far-right "w H" 'evil-window-move-far-left "w J" 'evil-window-move-very-bottom "w K" 'evil-window-move-very-top) (defun nice-balance-windows-alt () "Balance windows such that the current window receives a certain amount of the of the frame's width and height." (interactive) (balance-windows) (let* ((proportion 0.7) (frame-width (frame-width)) (frame-height (frame-height)) (desired-width (floor (* proportion frame-width))) (desired-height (floor (* proportion frame-height)))) (enlarge-window-horizontally (- desired-width (window-width))) (enlarge-window (- desired-height (window-height)))))
Shells
;; Shell stuff ;; ----------- ;; (defun nice-eshell () "Open an existing or new eshell buffer in a vertical split." (interactive) (let ((eshell-buffer (get-buffer "*eshell*")) (width (/ (frame-width) 2))) (split-window-horizontally) (other-window 1) (window-resize nil (- width (window-width)) t) (if eshell-buffer (switch-to-buffer eshell-buffer) (eshell)))) (defun nice-eshell-prompt () (let* ((directory (abbreviate-file-name (eshell/pwd))) (parent (file-name-directory directory)) (name (file-name-nondirectory directory)) (base-prompt (concat (if parent (concat "... " (file-name-nondirectory (directory-file-name parent)) "/") "") name " $ ")) (trimmed-prompt (if (> (length base-prompt) 50) (concat "[...] " (substring base-prompt (- (length base-prompt) 44))) base-prompt))) (if (string-match-p "~" trimmed-prompt) (replace-regexp-in-string "^\\.\\.\\. " "" trimmed-prompt) trimmed-prompt))) (setq eshell-prompt-function 'nice-eshell-prompt) (setq eshell-cmpl-ignore-case t) (evil-leader/set-key "s e" 'eshell "s b" (lambda () (interactive) (ansi-term "/bin/bash")) "s i" 'ielm "s r" 'R "'" 'nice-eshell) (defun cdf (filepath) "Change the current directory in Eshell to the directory of FILEPATH." (let ((dir (file-name-directory filepath))) (when (file-directory-p dir) (eshell/cd dir)))) (defun nice-eshell-mode-setup () (setenv "TERM" "dumb") (setenv "GIT_PAGER" "cat")) (add-hook 'eshell-mode-hook 'nice-eshell-mode-setup)
Dired
Setting the dired-dwim-target
variable to t
means that dired will search for
an appropriate directory to start from when you copy a file via dired. I usually
have both directories in adjacent windows when moving files between them, so
this is more convenient.
;; Dired ;; ----- ;; ;; - R :: mv ;; - C :: cp ;; - + :: mkdir ;; - - :: cd ../ ;; - m :: mark a file ;; - u :: unmark a file ;; - d :: flag file for deletion ;; - x :: execute deletion ;; (use-package dired :bind (:map dired-mode-map ("-" . dired-up-directory)) :config (setq dired-listing-switches "-alh") (setq dired-dwim-target t) (evil-leader/set-key-for-mode 'dired-mode "m s" 'dired-sort-toggle-or-edit))
Note that there is no :ensure t
here. This is because the dired
package is
installed by default and is not no the package repositories, so if you have
:ensure t
it will throw a warning saying it is not installed in the expected
way. Just removing :ensure t
fixes it though.
By default you will always be prompted if you want to revert a file if you
already are visiting it and it has changed on the file system since you last
looked. This is a bit annoying when you are working on figures. The following
modication of revert-without-query
ensures no confirmation is required when
opening PNGs.
(add-to-list 'revert-without-query "\\.png$") (use-package openwith :ensure t :config (setq openwith-associations (list (list (openwith-make-extension-regexp '("pdf")) "okular" '(file)))) (openwith-mode t))
The use of the openwith
package above means that when you click on a
PDF in dired, it will open with Okular, rather than in the DocViewer
in Emacs.
Searching
The following advice from the emacs manual may be useful if you are trying to locate some files.
To search for files with names matching a wildcard pattern use
M-x find-name-dired
. It reads arguments DIRECTORY and PATTERN, and chooses all the files in DIRECTORY or its subdirectories whose individual names match PATTERN.
There is also the grep
command for searching within files and the
find
command for searching based on the filename.
Buffers, files, and dired
You can get a list of all the current buffers with ibuffer
. Important keys for
Ibuffer include
d
to mark for killing andx
to run those kills,g r
to refresh the listing,o <thing>
to sort by:o v
timeo m
modeo a
name (alphbetical)o i
to invert the ordering.
- and
u
to unmark buffers.
;; Buffer stuff ;; ------------ (evil-leader/set-key "b r" 'revert-buffer "b l" 'ibuffer) (defface ibuffer-modified-buffer '((t (:foreground "white" :weight bold :background "red"))) "Face used for highlighting unsaved buffers in IBuffer.") ;; Declare that IBuffer should use the `ibuffer-modified-buffer' face ;; for modified buffers so that they stand out. (add-hook 'ibuffer-mode-hook (lambda () (ibuffer-auto-mode 1) (ibuffer-switch-to-saved-filter-groups "default") (add-to-list 'ibuffer-fontification-alist '(0 (buffer-modified-p) 'ibuffer-modified-buffer)))) ;; File stuff ;; ---------- (evil-leader/set-key "f f" 'find-file "f l" 'find-file-literally "f t" 'nice-touch-file "f F" 'find-file-other-frame "f s" 'save-buffer "f d" 'nice-dired "b b" 'switch-to-buffer "d b" 'kill-buffer "d w" 'delete-window "d F" 'delete-frame "F d" 'delete-frame) (defun nice-dired () "Open dired for the current buffer's directory if it corresponds to a file, the working directory of the shell if the current buffer is a shell, or the home directory otherwise." (interactive) (let* ((buffer-mode (with-current-buffer (current-buffer) major-mode)) (dir (cond ((buffer-file-name) (file-name-directory (buffer-file-name))) ((or (eq buffer-mode 'term-mode) (eq buffer-mode 'eshell-mode) (eq buffer-mode 'inferior-ess-r-mode)) (with-current-buffer (if (eq buffer-mode 'inferior-ess-r-mode) (process-buffer (ess-get-process ess-current-process-name)) (current-buffer)) (file-name-directory default-directory))) (t (expand-file-name "~/"))))) (dired dir))) (defun nice-touch-file () "In the current dired buffer touch a new file with a name retreived from the prompt." (interactive) (if (not (eq major-mode 'dired-mode)) (error "Not in dired mode")) (let ((filename (read-string "Filename: "))) (shell-command (format "touch %s" filename)) (revert-buffer))) (defmacro nice-scratch-buffer (mode key) "Create a nice-scratch-buffer function for MODE and bind it to KEY." (let ((func-name (intern (format "nice-scratch-buffer-%s" (symbol-name mode)))) (docstring (format "Open the scratch buffer and set the major mode to `%s'." mode))) `(progn (defun ,func-name () ,docstring (interactive) (switch-to-buffer "*scratch*") (,mode)) (evil-leader/set-key ,key ',func-name)))) (nice-scratch-buffer text-mode "b s t") (nice-scratch-buffer org-mode "b s o") (nice-scratch-buffer emacs-lisp-mode "b s e")
STUFF 2
;; Consult the oracle ;; ------------------ (evil-leader/set-key "H s" 'apropos "H d b" 'message-buffer-file-name "H d f" 'describe-function "H d m" 'describe-mode "H d p" 'describe-package "H d k" 'describe-key "H d v" 'describe-variable) (defun message-buffer-file-name () "Print the full path of the current buffer's file or directory to the minibuffer and store this on the kill ring." (interactive) (let ((path (or buffer-file-name (and (eq major-mode 'dired-mode) (dired-current-directory))))) (when path (kill-new path) (message path)))) (defun message-link-at-point () "Print the full path of a link at the point so we know where this will take us." (interactive) (let* ((link (org-element-context)) (link-file-name (org-element-property :path link))) (when (eq (org-element-type link) 'link) (kill-new link-file-name) (message "%s" link-file-name)))) (evil-leader/set-key "H l m" 'message-link-at-point) ;; Learn from your past ;; -------------------- (defmacro nice-rgrep-directory (dname path pattern key) "Create a function that calls `rgrep' on the specified DIRECTORY and binds it to a KEY. DNAME is the name of the directory used to generate the function name. PATH is the path to the directory to be searched. KEY is the keybinding (as a string) to trigger the rgrep function." `(progn (defun ,(intern (format "nice-rgrep-%s" dname)) () ,(format "Search for a string in %s using rgrep." dname) (interactive) (rgrep (read-string "Search terms: ") ,pattern ,path)) (evil-leader/set-key ,(concat "s g " key) (intern ,(format "nice-rgrep-%s" dname))))) (nice-rgrep-directory "website" "~/public-site/org" "*" "w") (nice-rgrep-directory "notes" "~/public-site/org/notes" "*" "n") (nice-rgrep-directory "journal" "~/Documents/journal" "*.org" "j") (nice-rgrep-directory "reviews" "~/Documents/bibliography" "*" "r") (evil-leader/set-key "s g ." (lambda () (interactive) (rgrep (read-string "Search terms: ") "*"))) ;; Be virtuous and lead by example ;; =============================== (setq-default major-mode (lambda () (unless buffer-file-name (let ((buffer-file-name (buffer-name))) (set-auto-mode))))) (setq confirm-kill-emacs #'yes-or-no-p) (recentf-mode t) (setq read-buffer-completion-ignore-case t read-file-name-completion-ignore-case t completion-ignore-case t) ;; Be powerful with packages ;; ========================= ;; Obfuscate the text on the screen if there is no movement for 60 ;; seconds. (require 'zone) (zone-when-idle 0) (setq zone-programs [zone-pgm-whack-chars]) (evil-leader/set-key "z z" 'zone) ;; NXML ;; ---- ;; u - up to parent. ;; p - previous tag. ;; n - next tag. (evil-leader/set-key-for-mode 'nxml-mode "m u" 'nxml-backward-up-element "m p" 'nxml-backward-element "m n" 'forward-sexp)
Yasnippet
I have a collection of yasnippets here. To use these snippets clone that
repository into your .emacs.d/
under the name snippets
and use
yas-reload-all
(possibly after yas-recompile-all
although this can be slow).
;; Yasnippet ;; --------- ;; ;; See https://github.com/aezarebski/whipper-snipper ;; (use-package yasnippet :ensure t :config (yas-global-mode 1)) (defun nice-load-snippets () "Load the snippets in my snippet directory" (interactive) (let ((snippets-dir nice-snippet-directory)) (unless (file-exists-p snippets-dir) (make-directory snippets-dir)) (yas-load-directory snippets-dir))) (nice-load-snippets) (evil-leader/set-key "y i" 'yas-insert-snippet ; Insert a snippet "y n" 'yas-new-snippet ; Create a new snippet "y v" 'yas-visit-snippet-file ; Visit the snippet file for the current mode "y r" 'yas-reload-all ; Reload all snippets "y c" 'yas-compile-directory ; Compile all snippets "y l" 'nice-load-snippets ; Load your custom snippets "y g" 'nice-go-to-snippets-dir "y e" 'emoji-list) (defun nice-go-to-snippets-dir () "Open the snippets directory in dired." (interactive) (dired nice-snippet-directory))
STUFF 3
;; Multiple cursors ;; ---------------- ;; ;; Using mutiple cursors is a little bit tricky but here are some ;; simple steps you can try on the following example text. ;; ;; ``` ;; the cat sat on the mat ;; catch this ball said pat ;; the food was eaten by the cat ;; ``` ;; ;; 1. Select the an instance of "cat" with the cursor at the start ;; 2. Use the keys below, e.g. `SPC c n` to select occurrences ;; 3. Use `evil-insert' (`SPC c i`) to start editing. ;; 4. Exit using `mc/keyboard-quit' (`SPC c q`) (use-package multiple-cursors :ensure t) (use-package evil-mc :ensure t :config (global-evil-mc-mode 1)) (evil-leader/set-key "c n" 'mc/mark-next-like-this ; Mark next occurrence "c p" 'mc/mark-previous-like-this ; Mark previous occurrence "c N" 'mc/skip-to-next-like-this ; Skip and mark next occurrence "c P" 'mc/skip-to-previous-like-this ; Skip and mark previous occurrence "c u" 'mc/unmark-next-like-this ; Unmark next cursor "c U" 'mc/unmark-previous-like-this ; Unmark previous cursor "c i" 'evil-insert ; Drop into using the cursors "c q" 'mc/keyboard-quit ; Quit multiple-cursors mode )
Magit
Staging and unstaging multiple files
You can select multiple files to unstage in one go using the region. To do this, follow these steps:
- Navigate to the "Staged changes" section in the Magit status buffer.
- Move the cursor to the first file you want to unstage.
- Set the mark by pressing
C-SPC
(Control + Space). - Move the cursor to the last file you want to unstage. This will create a region that includes all the files you want to unstage.
- Press
u
to unstage all the files in the region.
You can also use the same method to stage multiple files in the
"Unstaged changes" section. Just follow the same steps, but press s
instead of u
in step 5 to stage the files in the region.
Configuration
;; Magit ;; ----- (use-package magit :ensure t :config (setq magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1) (setenv "SSH_AUTH_SOCK" "<ADD THE CORRECT PATH HERE>") (evil-leader/set-key "g s" 'nice/magit-status "g q" 'with-editor-cancel))
The following is meant to solve the problem where the window configuration is
lost by magit-status
. I haven't been able to get the bindings working within
magit-status
though, so you have to call nice/magit-quit
manually. It does
restore the configuration though which is nice.
(defvar nice/temp-window-configuration nil "Temporary variable to hold the window configuration.") (defun nice/magit-status () "Save the current window configuration and open Magit status." (interactive) (setq nice/temp-window-configuration (current-window-configuration)) (magit-status)) (defun nice/magit-quit () "Restore the window configuration from before opening Magit status." (interactive) (when nice/temp-window-configuration (set-window-configuration nice/temp-window-configuration) (setq nice/temp-window-configuration nil)))
In the use-package
command above we set the SSH_AUTH_SOCK
manually which
fixes some weird issue where git was not able to authenticate correctly. This
only happened on one machine and is probably machine specific so you'll need to
be careful to get the right value here.
(defmacro nice-canned-commit-message (fname cmessage key) "Define a canned commit message function with an Evil key binding. This macro takes in three arguments: - FNAME: A string that will be used to construct the function name. - CMESSAGE: A string that represents the canned commit message. - KEY: A string that represents the keybinding for the function using the Evil leader. The function created by this macro generates a commit message with a timestamp by concatenating the specified CMESSAGE string with the current day and time. The commit is created using `magit-commit-create', which is invoked with the `--edit` option to open the commit message in an editor. The function is bound to the Evil leader key sequence `g c KEY`, where `KEY` is the specified key string. Example usage: (nice-canned-commit-message \"my-canned-commit\" \"Fix some bugs\" \"c\")" `(progn (defun ,(intern (format "nccm-%s" fname)) () "Generate a canned commit message with a timestamp." (interactive) (let ((commit-message (format "%s %s" ,cmessage (downcase (format-time-string "%A %l:%M %p"))))) (magit-commit-create (list "--edit" (concat "-m \"" commit-message "\""))))) (evil-leader/set-key ,(concat "g c " key) (intern ,(format "nccm-%s" fname))))) (nice-canned-commit-message emacs "update emacs config" "e") (nice-canned-commit-message flashcards "flashcards" "f") (nice-canned-commit-message journal "update journal" "j") (nice-canned-commit-message notes "update notes" "n") (nice-canned-commit-message review "update reading list" "r") (nice-canned-commit-message website "update website" "w") (nice-canned-commit-message yasnippet "yasnippet" "y")
Emacs lisp
- Awesome Elisp sounds like it would be a good place to go to learn a bit more elisp.
The pp-sexp-to-kill-ring
function is there to help pretty print code. It uses
a new pretty printer function included in 29.1 and puts the pretty-printed
version of an S-expression on the kill ring.
;; Emacs Lisp ;; ---------- (setq pp-max-width 70) (setq pp-use-max-width t) (defun pp-sexp-to-kill-ring () "Pretty-print the S-expression under the cursor and add it to the kill ring." (interactive) (let ((sexp (read (thing-at-point 'sexp))) (temp-buffer (generate-new-buffer "*temp*"))) (with-current-buffer temp-buffer (pp-emacs-lisp-code sexp) (kill-new (buffer-string))) (kill-buffer temp-buffer))) (evil-leader/set-key-for-mode 'emacs-lisp-mode "m s c" 'eval-last-sexp "m s b" 'eval-buffer "m s r" 'eval-region "m c l" 'pp-sexp-to-kill-ring)
Emacs Speaks Statistics (ESS)
;; Emacs Speaks Statistics (ESS) ;; ----------------------------- (use-package ess :ensure t :init (setq ess-etc-directory (concat (car (directory-files "~/.emacs.d/elpa/" t "ess-[0-9]+")) "/etc/")) :mode ("\\.Rmd" . Rmd-mode) :config (setq ess-default-style 'DEFAULT ess-history-file nil) (evil-leader/set-key-for-mode 'ess-r-mode "m d t" 'ess-r-devtools-test-package "m d l" 'ess-r-devtools-load-package "m d b" 'ess-r-devtools-build "m d i" 'ess-r-devtools-install-package "m d c" 'ess-r-devtools-check-package "m d d" 'ess-r-devtools-document-package "m s b" 'ess-eval-buffer "m s r" 'ess-eval-region "m s c" 'ess-eval-region-or-line-visibly-and-step "m s s" 'ess-eval-region-or-function-or-paragraph-and-step "m c l" 'nice-code-lint-buffer-r "m c i" 'indent-region "m '" 'ess-switch-to-inferior-or-script-buffer)) (use-package quarto-mode :ensure t) (defun nice-code-lint-buffer-r () "Lint the current R buffer using lintr." (interactive) (ess-eval-linewise "library(lintr)\n") (ess-eval-linewise (format "print(lint(\"%s\"))\n" buffer-file-name)))
MATLAB EXCLUDED
;; MATLAB ;; ------ ;; ;; TODO There should be a variable for the `nice-packages' directory. ;; (use-package matlab-load :load-path "~/.emacs.d/nice-packages/matlab-emacs-src" :config (setq matlab-indent-function t) (setq matlab-shell-command "~/MATLAB/bin/matlab")) (evil-leader/set-key-for-mode 'matlab-mode "m s b" 'matlab-shell-save-and-go "m s r" 'matlab-shell-run-region "m '" 'matlab-show-matlab-shell-buffer)
RealGUD debugging
;; Debugging ;; --------- ;; ;; Commands ;; - `n' next line ;; - `s' step into expression ;; - `c' continue ;; - `l' list context ;; - `p' print variable ;; - `q' quit debugger ;; ;; Debug a Python script by ;; 1. adding `import pdb; pdb.set_trace()' ;; 2. running the script with `realgud:pdb' ;; (use-package realgud :ensure t :config (setq realgud:pdb-command-name "python -m pdb"))
Python
;; Python ;; ------ ;; ;; Use `pyvenv-activate' to activate a virtual environment. (use-package pyvenv :ensure t) (use-package python :ensure t :config (setq python-shell-interpreter "python3") (setq python-indent-offset 4)) (use-package snakemake-mode :ensure t) (use-package yaml-mode :ensure t) (use-package indent-guide :ensure t :hook (python-mode . indent-guide-mode) :config (setq indent-guide-char "|") (setq indent-guide-recursive t)) (evil-leader/set-key-for-mode 'python-mode "m v a" 'pyvenv-activate "m s b" 'python-shell-send-buffer "m s r" 'python-shell-send-region "m '" 'python-shell-switch-to-shell)
Scheme/Racket EXCLUDED
;; Scheme/Racket ;; ------------- ;; TODO Work out how to start a repl properly, running the key does ;; not seem to work, I need to run the command via M-x directly. (require 'racket-mode) (add-to-list 'auto-mode-alist '("\\.rkt\\'" . racket-mode)) (setq racket-program "/usr/bin/racket") (evil-leader/set-key-for-mode 'racket-mode "m h d" 'racket-describe-search "m s b" 'racket-run "m s r" 'racket-send-region "m s c" 'racket-send-last-sexp)
LaTeX/BibTeX
;; LaTeX/BibTeX ;; ------------ ;; TODO Configure this so that there is a good way to search the key ;; bibtex files, perhaps with a SQL type search ;; TODO Find a better way to search BIB files. (defun most-recent-file (files) "Return the most recent file from a list of FILES. FILES should be a list of file paths as strings." (when (and files (seq-every-p #'stringp files)) (cl-flet* ((file-mod-time (file) (nth 5 (file-attributes file))) (mod-time-less-p (a b) (time-less-p (file-mod-time b) (file-mod-time a)))) (car (sort files #'mod-time-less-p))))) (defun copy-file-with-bib-extension (file-path) "Create a copy of the file at FILE-PATH with a .bib extension." (let* ((file-name (file-name-nondirectory file-path)) (file-base-name (file-name-sans-extension file-name)) (new-file-name (concat file-base-name ".bib")) (new-file-path (concat (file-name-directory file-path) new-file-name))) (copy-file file-path new-file-path t) new-file-path)) (defun nice-visit-last-bib () "Visit the most recent BIB file in Downloads. If there is a TXT file that is younger than the last BIB file, send a message to indicate this." (interactive) (let* ((bib-files (directory-files "~/Downloads" t ".*bib" "ctime")) (most-recent-bib (most-recent-file bib-files)) (txt-files (directory-files "~/Downloads" t ".*txt" "ctime")) (most-recent-txt (most-recent-file txt-files))) (if most-recent-bib (if (and most-recent-txt (time-less-p (nth 5 (file-attributes most-recent-bib)) (nth 5 (file-attributes most-recent-txt)))) (progn (message (concat "A more recent .txt file exists: " most-recent-txt)) (find-file (copy-file-with-bib-extension most-recent-txt))) (find-file most-recent-bib)) (message "No bib files found in ~/Downloads/")))) (defun nice-ris2bib () "Convert the most recent RIS file in my downloads to a BIB file. Signal an error if there are no RIS files or if the conversion fails." (interactive "*") (let* ((all-ris-files (directory-files "~/Downloads" t ".*ris")) (ris-filepath (most-recent-file all-ris-files)) (target-bib "~/Downloads/new.bib") (ris2xml-command (format "ris2xml \"%s\" | xml2bib > %s" ris-filepath target-bib)) (command-result (shell-command ris2xml-command))) (unless ris-filepath (error "No RIS files found in the directory")) (unless (zerop command-result) (error "Conversion from RIS to BIB failed with error code: %s" command-result)))) (defun nice-bibtex-braces () "Wrap upper case letters with brackets for bibtex titles within the selected region." (interactive) (if (use-region-p) (let ((start (region-beginning)) (end (region-end)) (case-fold-search nil)) (save-excursion (goto-char start) (while (re-search-forward "\\([A-Z]+\\)" end t) (replace-match (format "{%s}" (match-string 0)) t)))) (message "No region selected."))) (defun nice-bibtex-guess-key () "Generate a new key for the current BibTeX entry based on author, year, and the first two words of the title." (interactive) (bibtex-beginning-of-entry) (let* ((entry (bibtex-parse-entry)) (author (downcase (replace-regexp-in-string "," "" (car (split-string (bibtex-text-in-field "author")))))) (year (bibtex-text-in-field "year")) (title (bibtex-text-in-field "title")) (first-two-words (when title (let ((split-title (split-string title))) (if (>= (length split-title) 2) (format "%s%s" (nth 0 split-title) (nth 1 split-title)) (car split-title)))))) (if (and author year first-two-words) (let ((newkey (format "%s%s%s" author year first-two-words))) (kill-new (replace-regexp-in-string "[{}]" "" newkey)) (evil-jump-item) (message "New key generated and copied to clipboard: %s" newkey)) (error "Author, Year or Title is missing in the current BibTeX entry.")))) (defun nice-browse-url-of-doi () "Open the DOI of the current bibtex entry in the web browser." (interactive) (save-excursion (bibtex-beginning-of-entry) (let ((doi (bibtex-autokey-get-field "doi"))) (if doi (browse-url (concat "https://doi.org/" doi)) (message "No DOI found for this entry"))))) (evil-leader/set-key "v b l" 'nice-visit-last-bib "v b d" 'nice-browse-url-of-doi "v b r" 'nice-ris2bib) (evil-leader/set-key-for-mode 'bibtex-mode "m b b" 'nice-bibtex-braces "m b f" 'bibtex-reformat "m b k" 'nice-bibtex-guess-key)
In the following we use with-eval-after-load
because otherwise the
org-latex-classes
variable may not have been instantiated.
(with-eval-after-load 'ox-latex (add-to-list 'org-latex-classes '("scrartcl" "\\documentclass{scrartcl}" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))))
Markdown
markdown-mode
is also useful for writing Rmarkdown, so there are some ESS
functions that sneak in here too.
;; Markdown-mode ;; ------------- (use-package markdown-mode :mode (("\\.md\\'" . markdown-mode) ("\\.Rmd\\'" . markdown-mode)) :config (evil-leader/set-key-for-mode 'markdown-mode "m s r" 'ess-eval-region "m '" 'ess-switch-to-inferior-or-script-buffer))
Org-mode
- There is a function
org-table-sort-lines
which sorts the rows of a table based on a column (1-indexed) with a variety of datatypes acceptable.
;; Org-Mode ;; ======== ;; NOTE It would be nice to have an additional command and key for ;; moving from level n+1 headers their parent level n header. ;; FIXME Work out why the configuration based approach does not work! (setq org-return-follows-link t) (evil-leader/set-key-for-mode 'org-mode "RET" 'org-open-at-point) (defun nice-org-mode-hook () "Set up org-mode specific keybindings." (local-set-key (kbd "<tab>") #'org-cycle)) (add-hook 'org-mode-hook #'nice-org-mode-hook)
Writing natural language
;; Write well ;; ---------- ;; TODO Configure the =dictionary= command so that it works off of a ;; local copy of Webster's (setq sentence-end-double-space nil) (use-package flyspell :config (setq ispell-program-name "aspell") (setq ispell-personal-dictionary "~/.aspell.en.pws") (set-face-attribute 'flyspell-duplicate nil :underline nil :foreground "white" :background "red") (set-face-attribute 'flyspell-incorrect nil :underline nil :foreground "white" :background "red")) (use-package lorem-ipsum) (defun nice-diff-dictionaries () "Run ediff on the current ispell-personal-dictionary and the backup dictionary." (interactive) (let ((backup-dictionary (concat nice-resources-dir "/aspell.en.pws"))) (ediff-files ispell-personal-dictionary backup-dictionary))) (evil-leader/set-key "t S" 'flyspell-mode ; toggle flyspell on/off. "S b" 'flyspell-buffer "S n" 'flyspell-goto-next-error "S r" 'flyspell-region "S c" 'flyspell-correct-word-before-point "S d" 'nice-diff-dictionaries) (use-package writegood-mode) (setq words-to-add '("many" "various" "very" "quite" "somewhat" "several" "extremely" "exceedingly" "fairly" "rather" "remarkably" "few" "surprisingly" "mostly" "largely" "almost" "nearly" "in which" "generally" "virtually" "essentially" "often" "substantially" "significantly" "considerably" "typically" "widely" "really" "actually" "basically" "certainly" "possibly" "probably" "arguably" "likely" "apparently" "clearly" "naturally" "obviously" "seemingly" "surely" "somewhat" "allegedly" "supposedly" "purportedly" "perhaps" "maybe" "kind of" "sort of" "potentially" "ultimately" "respectively")) (cl-loop for word in words-to-add unless (member word writegood-weasel-words) do (add-to-list 'writegood-weasel-words word)) (evil-leader/set-key "t w" 'writegood-mode) ;; Formatting text ;; --------------- ;; ;; Some useful functions for writing in natural language. ;; ;; - nice-org-wrapped-lines ;; - nice-org-single-long-line ;; - nice-org-each-sentence-new-line ;; (defun nice-org-wrapped-lines () "Formats the current paragraph to have wrapped lines at 70" (interactive) (setq fill-column 70) (fill-paragraph) (message "Wrapped lines at 70 characters.")) (defun nice-org-single-long-line () "Formats the current paragraph into a single long line." (interactive) (save-excursion (let ((start (progn (backward-paragraph 1) (point))) (end (progn (forward-paragraph 1) (point)))) (goto-char start) (while (re-search-forward "[ \t]*\n[ \t]*" end t) (replace-match " ")))) (message "Single long line.")) (defun nice-org-each-sentence-new-line () "Puts each sentence of the current paragraph on a new line." (interactive) (save-excursion (let ((end (save-excursion (forward-paragraph) (point))) (beg (save-excursion (backward-paragraph) (point)))) (goto-char beg) (while (< (point) end) (forward-sentence) ;; Insert newline at the end of a sentence, unless it's the last one. (unless (or (= (point) end) (eobp)) (insert "\n"))))) (message "Each sentence on a new line."))
LaTeX preview
The following adjusts the size of the latex preview in org-mode. See the binding
for org-latex-preview
below.
(setq org-format-latex-options (plist-put org-format-latex-options :scale 2.0))
Agenda and calendar (org-mode)
- I have had some weird warning messages from
org-persist
about there being difficulty reading some org-mode related data from the cache: "Emacs reader failed to read data in …". I was able to resolve this by closing emacs, deleting the cache files, and then it worked perfectly when I restarted emacs. - You can get a list of all available colours to use in keyword faces below with
the
list-colors-disply
command as described in the section below.
;; Org-agenda ;; ---------- ;; ;; - `n/p' to move up and down lines. ;; - `v-d' will show the day view. ;; - `v-w' the week view. ;; - `v-m' the month view. ;; - `v-SPC' resets the view. ;; - `.' goes to today. ;; - `j' will /jump/ to a date (selected via calendar). ;; - `t' will cycle through TODO/DONE ;; - `S-<left/right>' moves the scheduled date backwards/forwards ;; - `r' rebuilds the agenda view ;; - `s' in agenda view will save the current org files. ;; (setq org-agenda-start-day "-14d" org-agenda-span 30 org-agenda-start-on-weekday nil org-agenda-start-with-log-mode t org-agenda-window-setup 'other-frame org-log-done 'time org-log-schedule 'time) (setq org-todo-keywords '((sequence "TODO" "DONE") (sequence "MEETING" "|" "DONE") (sequence "SEMINAR" "|" "DONE") (sequence "RESEARCH" "|" "DONE") (sequence "ADMIN" "|" "DONE") (sequence "DEADLINE" "|" "DONE") (sequence "TEACHING" "|" "DONE") (sequence "SOCIAL" "|" "DONE"))) (setq org-todo-keyword-faces `(("MEETING" . ,(boxed-face "magenta")) ("SEMINAR" . ,(boxed-face "magenta")) ("RESEARCH" . ,(boxed-face "dark green" "light green")) ("DEADLINE" . ,(boxed-face "red" "white")) ("ADMIN" . ,(boxed-face "red" "white")) ("TEACHING" . ,(boxed-face "magenta")) ("SOCIAL" . ,(boxed-face "blue" "#E6ECFF")))) (defun nice-org-agenda-goto-today-advice-after (&rest _args) "Adjust the window after calling `org-agenda-goto-today'." (recenter-top-bottom 4)) (advice-add 'org-agenda-goto-today :after #'nice-org-agenda-goto-today-advice-after) (evil-leader/set-key-for-mode 'org-mode "a s" 'org-schedule) (evil-leader/set-key "a a" 'org-agenda-list)
Agenda and calendar (calfw) EXCLUDED
;; Calendar view ;; ;; This provides a more classical view of the agenda as a calendar. ;; (use-package calfw :ensure t :config (use-package calfw-org)) (evil-leader/set-key "a a" 'org-agenda-list "a c" 'cfw:open-org-calendar)
Literate programming
;; Literate programming (use-package polymode :ensure t :mode ("\\.org$" . poly-org-mode) :config (add-to-list 'auto-mode-alist '("\\.org$" . poly-org-mode))) (use-package poly-R :ensure t :after polymode) (use-package poly-org :ensure t :after polymode) (org-babel-do-load-languages 'org-babel-load-languages '((R . t) (python . t))) (evil-leader/set-key-for-mode 'org-mode "b t" 'org-babel-tangle) (evil-leader/set-key-for-mode 'org-mode "b e" 'org-babel-execute-src-block) (defun nice-detangle-nicemacs-v2 () "Detangle the nicemacs-v2.el file." (interactive) (let ((nicemacs-v2-source (concat nice-nicemacs-directory "/nicemacs-v2.el"))) (org-babel-detangle nicemacs-v2-source))) (evil-leader/set-key-for-mode 'emacs-lisp-mode "b d" 'nice-detangle-nicemacs-v2) (setq org-image-actual-width 300) (evil-leader/set-key-for-mode 'org-mode "o t l" 'org-latex-preview "o t i" 'org-toggle-inline-images)
Website/Publishing
(defun nice-publish-homepage () "Copy my website homepage if it exists." (interactive) (let* ((notes-root "~/public-site/org/") (misc-root "~/public-site/org/misc/papers/") (local-notes (concat notes-root "index-notes.html")) (remote-notes (concat nice-website-directory "notes.html")) (local-mininyan (concat notes-root "mininyan.js")) (remote-mininyan (concat nice-website-directory "mininyan.js")) (local-landing (concat notes-root "index-academic.html")) (remote-landing (concat nice-website-directory "index.html")) (local-css (concat notes-root "microgram.css")) (remote-css (concat nice-website-directory "microgram.css")) (local-misc-index (concat misc-root "index.html")) (remote-misc-index (concat nice-website-directory "misc/papers/index.html")) (local-misc-data (concat misc-root "data.json")) (remote-misc-data (concat nice-website-directory "misc/papers/data.json")) (local-misc-script (concat misc-root "script.js")) (remote-misc-script (concat nice-website-directory "misc/papers/script.js"))) (when (file-exists-p local-notes) (copy-file local-notes remote-notes t) (message "Copied %s to %s" local-notes remote-notes)) (when (file-exists-p local-mininyan) (copy-file local-mininyan remote-mininyan t) (message "Copied %s to %s" local-mininyan remote-mininyan)) (when (file-exists-p local-landing) (copy-file local-landing remote-landing t) (message "Copied %s to %s" local-landing remote-landing)) (when (file-exists-p local-css) (copy-file local-css remote-css t) (message "Copied %s to %s" local-css remote-css)) (when (file-exists-p local-misc-index) (copy-file local-misc-index remote-misc-index t) (message "Copied %s to %s" local-misc-index remote-misc-index)) (when (file-exists-p local-misc-data) (copy-file local-misc-data remote-misc-data t) (message "Copied %s to %s" local-misc-data remote-misc-data)) (when (file-exists-p local-misc-script) (copy-file local-misc-script remote-misc-script t) (message "Copied %s to %s" local-misc-script remote-misc-script)))) ;; The following projects are available for publishing when the ;; `org-publish' command is given. (setq org-publish-project-alist `(("website-notes-org-files" :base-directory "~/public-site/org/notes/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/notes/" :publishing-function org-html-publish-to-html) ("website-teaching-org-files" :base-directory "~/public-site/org/teaching/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/teaching/" :publishing-function org-html-publish-to-html) ("website-teaching-static" :base-directory "~/public-site/org/teaching/" :base-extension "css\\|pdf" :publishing-directory "~/aezarebski.github.io/teaching/" :recursive t :publishing-function org-publish-attachment) ("website-lists-org-files" :base-directory "~/public-site/org/lists/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/lists/" :publishing-function org-html-publish-to-html) ("website-images-static" :base-directory "~/public-site/org/images/" :base-extension "png" :publishing-directory "~/aezarebski.github.io/images/" :publishing-function org-publish-attachment) ("website-misc-ggplot2-org-files" :base-directory "~/public-site/org/misc/ggplot2/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/ggplot2/" :publishing-function org-html-publish-to-html) ("website-misc-ggplot2-static" :base-directory "~/public-site/org/misc/ggplot2/" :base-extension "png\\|jpg\\|pdf" :publishing-directory "~/aezarebski.github.io/misc/ggplot2/" :publishing-function org-publish-attachment) ("website-misc-basegraphicsR-org-files" :base-directory "~/public-site/org/misc/basegraphicsR/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/basegraphicsR/" :publishing-function org-html-publish-to-html) ("website-misc-basegraphicsR-static" :base-directory "~/public-site/org/misc/basegraphicsR/" :base-extension "png\\|jpg\\|pdf" :publishing-directory "~/aezarebski.github.io/misc/basegraphicsR/" :publishing-function org-publish-attachment) ("website-misc-latex-org-files" :base-directory "~/public-site/org/misc/latex/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/latex/" :publishing-function org-html-publish-to-html) ("website-misc-latex-static" :base-directory "~/public-site/org/misc/latex/" :base-extension "png\\|jpg\\|pdf" :publishing-directory "~/aezarebski.github.io/misc/latex/" :publishing-function org-publish-attachment) ("website-misc-tikz-org-files" :base-directory "~/public-site/org/misc/tikz/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/tikz/" :publishing-function org-html-publish-to-html) ("website-misc-tikz-static" :base-directory "~/public-site/org/misc/tikz/" :base-extension "png\\|jpg\\|pdf" :publishing-directory "~/aezarebski.github.io/misc/tikz/" :publishing-function org-publish-attachment) ("website-misc-matplotlib-org-files" :base-directory "~/public-site/org/misc/matplotlib/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/matplotlib/" :publishing-function org-html-publish-to-html) ("website-misc-matplotlib-static" :base-directory "~/public-site/org/misc/matplotlib/" :base-extension "png\\|jpg\\|pdf" :publishing-directory "~/aezarebski.github.io/misc/matplotlib/" :publishing-function org-publish-attachment) ("website-misc-ml-org-files" :base-directory "~/public-site/org/misc/ml/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/ml/" :publishing-function org-html-publish-to-html) ("website-misc-ml-static" :base-directory "~/public-site/org/misc/ml/" :base-extension "webp\\|png\\|py" :recursive t :publishing-directory "~/aezarebski.github.io/misc/ml/" :publishing-function org-publish-attachment :exclude "venv/") ("website-misc-ml-diagrams-static" :base-directory "~/public-site/org/misc/ml/diagrams/" :base-extension "png" :publishing-directory "~/aezarebski.github.io/misc/ml/diagrams/" :publishing-function org-publish-attachment) ("website-misc-plotnine-org-files" :base-directory "~/public-site/org/misc/plotnine/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/plotnine/" :publishing-function org-html-publish-to-html) ("website-misc-plotnine-static" :base-directory "~/public-site/org/misc/plotnine/" :base-extension "png\\|jpg\\|pdf" :publishing-directory "~/aezarebski.github.io/misc/plotnine/" :publishing-function org-publish-attachment) ("website-misc-recipes" :base-directory "~/public-site/org/misc/recipes/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/recipes/" :publishing-function org-html-publish-to-html) ("website-misc-recipes-static" :base-directory "~/public-site/org/misc/recipes/" :base-extension "png\\|css" :publishing-directory "~/aezarebski.github.io/misc/recipes/" :recursive () :publishing-function org-publish-attachment) ("review2-org" :base-directory "~/Documents/bibliography/review2" :base-extension "org" :publishing-directory "~/aezarebski.github.io/notes/review2" :recursive () :publishing-function org-html-publish-to-html ) ("review2-static" :base-directory "~/Documents/bibliography/review2" :base-extension "css\\|png" :publishing-directory "~/aezarebski.github.io/notes/review2" :recursive t :publishing-function org-publish-attachment ) ("nicemacs-org-files" :base-directory "~/Documents/nicemacs/" :base-extension "org" :publishing-directory "~/aezarebski.github.io/misc/nicemacs/" :publishing-function org-html-publish-to-html) ("python" :components ("website-misc-matplotlib-org-files" "website-misc-matplotlib-static" "website-misc-plotnine-org-files" "website-misc-plotnine-static")) ("ml" :components ("website-misc-ml-org-files" "website-misc-ml-static" "website-misc-ml-diagrams-static")) ("R" :components ("website-misc-basegraphicsR-org-files" "website-misc-basegraphicsR-static" "website-misc-ggplot2-org-files" "website-misc-ggplot2-static")) ("review" :components ("review2-org" "review2-static")) ("latex" :components ("website-misc-latex-org-files" "website-misc-latex-static" "website-misc-tikz-org-files" "website-misc-tikz-static")) ("recipes" :components ("website-misc-recipes" "website-misc-recipes-static")) ("teaching" :components ("website-teaching-org-files" "website-teaching-static")) ("website" :components ("website-notes-org-files" "website-images-static" "website-lists-org-files" "ml" "nicemacs-org-files" "recipes" "review" "latex" "python" "R"))))
STUFF 8
;; Visitors ;; ======== (defmacro NVNF (fname pname file key) "Macro to define a function for visiting a notes file and set an Evil leader key binding. This macro takes in four arguments: - FNAME: A string that will be used to construct the function name. - PNAME: A string that will be used in the message displayed to the user. - FILE: A string that represents the name of the notes file. - KEY: A string that represents the keybinding for the function using the Evil leader. The function created by this macro opens the notes file specified by FILE in the directory specified by `nice-notes-directory'. The keybinding is set using the Evil leader, and is constructed using the specified KEY string. Example usage: (NVNF \"my-notes\" \"My Notes\" \"my-notes.org\" \"n\")" `(progn (defun ,(intern (format "nice-visit-%s" fname)) () "Visit a notes file." (interactive) (progn (message ,(format "Visiting %s" pname)) (find-file ,(concat nice-notes-directory "/" file)))) (evil-leader/set-key ,(concat "v n " key) (intern ,(format "nice-visit-%s" fname))))) (defmacro NVF (fname pname file key) `(progn (defun ,(intern (format "nice-visit-%s" fname)) () "Visit a file." (interactive) (progn (message ,(format "Visiting %s" pname)) (find-file ,file))) (evil-leader/set-key ,(concat "v f" key) (intern ,(format "nice-visit-%s" fname))))) (defmacro NVD (dname pname path key) "Macro to define a function for visiting a directory and set an Evil leader key binding. This macro takes in four arguments: - DNAME: A string that will be used to construct the function name. - PNAME: A string that will be used in the message displayed to the user. - PATH: A string that represents the path of the directory. - KEY: A string that represents the keybinding for the function using the Evil leader. The function created by this macro jumps to the directory specified by PATH using `dired-jump'. The keybinding is set using the Evil leader, and is constructed using the specified KEY string. Example usage: (NVD \"my-dir\" \"My Directory\" \"/path/to/directory\" \"d\")" `(progn (defun ,(intern (format "nice-visit-%s" dname)) () "Visit a directory." (interactive) (progn (message ,(format "Visiting %s" pname)) (dired-jump nil ,path) (revert-buffer))) (evil-leader/set-key ,(concat "v d " key) (intern ,(format "nice-visit-%s" dname))))) (NVF nicemacs2-source "Nicemacs v2 source" "~/Documents/nicemacs/nicemacs-v2.el" "e 3") (NVF nicemacs2-init "Nicemacs v2 init.el" "~/.emacs.d/init.el" "e 2") (NVF nicemacs-init "Nicemacs v1 nicemacs.el" "~/Documents/nicemacs/nicemacs.el" "e 1") (NVF nicemacs-org "Nicemacs v1 nicemacs.org" "~/Documents/nicemacs/nicemacs.org" "e 1") (NVF review-2 "Review 2" "~/Documents/bibliography/review2/review.org" "r 2") (NVF review-reading-list "Reading list" "~/Documents/bibliography/review2/reading-list.org" "r l") (NVF review-references "Bibtex references" "~/Documents/bibliography/references.bib" "r r") (NVNF academia-notes "Academia notes" "academic-journal-notes.org" "a") (NVNF beast-notes "BEAST2 notes" "beast2-notes.org" "b") (NVNF git-notes "Git notes" "git-notes.org" "g") (NVNF haskell-notes "Haskell notes" "haskell-notes.org" "h") (NVNF java-notes "Java notes" "java-notes.org" "j") (NVNF latex-notes "LaTeX notes" "latex-notes.org" "l") (NVNF mathematica-notes "Mathematica notes" "mathematica-notes.org" "m") (NVNF org-mode-notes "org-mode notes" "org-mode-notes.org" "o") (NVNF python-notes "Python notes" "python-notes.org" "p") (NVNF r-notes "R notes" "r-notes.org" "r") (NVNF ubuntu-notes "Ubuntu/Linux notes" "linux-notes.org" "u") (NVD emacs "Emacs" "~/.emacs.d/fake.org" "e") (NVD journal-dir "Journal Directory" "~/Documents/journal/fake.org" "j") (NVD library "Library" "~/Documents/library/fake.org" "l") (NVD manuscripts "Manuscripts" "~/Documents/manuscripts/fake.org" "m") (NVD music "Music" "~/Music/fake.org" "M") (NVD documents "Documents" "~/Documents/fake.org" "d") (NVD downloads "Downloads" "~/Downloads/fake.org" "D") (NVD professional "Professional" "~/Documents/professional/README.org" "p") (NVD projects "Projects" "~/projects/fake.org" "P") (NVD teaching "Teaching" "~/Documents/teaching/fake.org" "t") (NVD website-org "Website (org files)" "~/public-site/org/fake.org" "w") (NVD website-html "Website (HTML files)" "~/aezarebski.github.io/fake.org" "W") (NVD notes "My notes" "~/public-site/org/notes/fake.org" "n") (NVD yasnippet "Yasnippet" "~/.emacs.d/snippets/fake.org" "y") (setq org-agenda-files (list (concat nice-journal-directory "bike.org"))) (defun nice-visit-journal () "Opens the current journal file. If it does not yet exist, it makes a copy of the one from one week ago. This will also ensure that the current journal file is among the org agenda files and that a previous one is not." (interactive) (let* ((filepath-template (concat nice-journal-directory "journal-%s.org")) (curr-file (format filepath-template (format-time-string "%Y-%m"))) (prev-file (format filepath-template (format-time-string "%Y-%m" (time-subtract (current-time) (* 7 24 60 60)))))) (unless (file-exists-p curr-file) (message "Creating new journal file") (copy-file prev-file curr-file)) (message "Opening journal file") (when (member prev-file org-agenda-files) (setq org-agenda-files (remove prev-file org-agenda-files))) (unless (member curr-file org-agenda-files) (add-to-list 'org-agenda-files curr-file)) (find-file curr-file) (goto-char (point-min)) (recenter-top-bottom))) (evil-leader/set-key "v f j" 'nice-visit-journal)
Copilot
;; Copilot ;; ======= ;; ;; To install this you need to clone the repository and a couple of ;; dependencies yourself: s, editorconfig which are emacs packages and ;; node.js. ;; ;; To enable `copilot' on your buffer, use SPC t c. ;; (use-package copilot :defer 1 :config (evil-leader/set-key "t c" 'copilot-mode) (setq copilot-node-executable "~/.nvm/versions/node/v17.3.1/bin/node") ;; (setq copilot-node-executable "/usr/bin/node") :load-path "~/.emacs.d/copilot.el/") (defun nice-copilot-tab () "Accept the current suggestion provided by copilot." (interactive) (or (copilot-accept-completion) (indent-for-tab-command))) (with-eval-after-load 'copilot (evil-define-key 'insert copilot-mode-map (kbd "<tab>") #'nice-copilot-tab)) (defun nice-copilot-by-line () "Accept the current suggestion by line." (interactive) (or (copilot-accept-completion-by-line) (indent-for-tab-command))) (with-eval-after-load 'copilot (evil-define-key 'insert copilot-mode-map (kbd "C-<tab>") #'nice-copilot-by-line))
Rust
(use-package rust-mode :ensure t :mode "\\.rs\\'" :config ;; Enable rustfmt on save (setq rust-format-on-save t))
STUFF 9
;; Explore new worlds ;; ================== ;; TODO Work out how to browse gopher with =gopher.el=. ;; TODO Work out how to configure auth-source. ;; TODO Work out how to use mediawiki-mode to read and edit wikipedia. ;; TODO Explore running spotify through emacs ;; Customization ;; ============= ;; There be dragons here ;; ---------------------
GNU Emacs
The notes here are intended to deal exclusively with GNU emacs without the use of packages other than those that are provided with emacs.
Build you an Emacs
Get the source code from here with
# wget https://git.savannah.gnu.org/cgit/emacs.git/snapshot/emacs-VERSION.tar.gz wget https://ftp.gnu.org/gnu/emacs/emacs-VERSION.tar.xz tar -xf emacs-VERSION.tar.xz
Alternatively, you can get clone the emacs mirror from GitHub and check out the
emacs-28
branch (or whatever version you want).
Follow the instructions in the INSTALL
file to build emacs.
- This seems to just be
./configure
thenmake
thensudo make install
../configure --with-native-compilation --with-rsvg
.- If you cannot find the
configure
script, you may need to runautogen.sh
first.
- If you have spare compute you can use multiple jobs to speed up the
compilation with
make -j[N]
to useN
jobs during compilation
Notes
emacs-29.4
: same procedure as the previous version.emacs-29.2
: same procedure as the previous version.emacs-29.1
on the work laptop:./configure --with-json --with-rsvg --with-native-compilation --with-imagemagick CFLAGS
'-g3 -O3'=- When building from source on a completely fresh system I needed a lot of
basic packages:
build-essential autoconf texinfo libgnutls28-dev libjansson-dev
- When building from source on a completely fresh system I needed a lot of
basic packages:
emacs-29.0.60
on a new laptop:./configure --with-native-compilation --with-tree-sitter --without-x --with-pgtk
because it uses Wayland.emacs-29.0.60
configured with--with-native-compilation
, and--with-tree-sitter
. This took a bit of fiddling because it couldn't find the correct version of the JIT library which turned out to belibgccjit-11-dev
and I couldn't work out how to compile tree-sitter from source.emacs-28.2
emacs-28.1.90
configured with--with-native-compilation
and--with-rsvg
. Building this one seemed to take longer than normal.emacs-28.1
. I also installedlibgccjit
and used./configure --with-native-compilation
during the compilation, it does feel snappier.emacs-28.0.91
requestedmailutils
to be installed during configuration.emacs-28.0.60
requestedlibacl1-dev
andlibharfbuzz-dev
be installed during configuration. It does feel snappier. It told me that my current version of GTK+ leads to a bug but I couldn't figure out how to update GTK+ and it seemed to be an up to date version anyway.emacs-27.2
build and installs without issue.
Recording keyboard macros
- Start recording with
C-x (
(which callskmacro-start-macro
). - Stop recording with
C-x )
(which callskmacro-end-macro
). - Execute the recording with
C-x e
(which callskmacro-end-and-call-macro
).
If you want to save a macro for later use, you can get a emacs-lisp definition
of it with insert-kbd-macro
.
Buffer specific variables
Suppose you wanted to set the fill-column
for a specific file, add
the following to the end of the file to set it to 80 for this file.
% Local Variables: % fill-column: 80 % End:
Colours
The function list-colors-display
will open a new buffer displaying all the
defined colours and their names. This is particularly useful if you want to
configure faces.
Jargon
There is a glossary in the manuals, the nodes are Emacs > Glossary
. The regex
search entered with s
is very useful here.
TRAMP
TRAMP stands for "Transparent Remote (file) Access, Multiple Protocol". In
general, TRAMP connections use the following syntax:
/protocol:[user@]hostname[#port]:/path/to/file
. If you usually SSH into server
and you want to edit files there then the protocol
will be ssh
. If you omit
the protocol it will use the method named by the variable tramp-defaul-method
.
(Mickey Petersen recommends setting tramp-default-method
to ssh
for
convenience.) If you set up an ~/.ssh/config
file, TRAMP will be aware of
these hosts. Once you are visiting a file in this way, the standard emacs
functionality will work so ou can treat it like any other buffer.
Example
Suppose you had the ssh configuration shown below:
Host foobar HostName squanch.beep.boop User flappy
Then you could run find-file
with the following to access a file at
~/bing/bong/readme.org
:
/ssh:foobar:~/bing/bong/readme.org
And amazingly, tab-complete of paths should also work! If you give the path to a directory, this will open in dired.
Mastering Emacs
Here are some notes from reading Mastering Emacs.
Chapter 2
- "In Emacs, the buffer is the data structure."
- A window is a tiled portion of a frame.
- The modeline is the portion at the bottom of a window that displays information such as the name of the buffer displayed and the major mode.
- The minibuffer is the below the modeline and displays messages.
- The point is the current position of the cursor.
- The region is a selection of text which has the point at one end and the mark at the other. The region is visually displayed with the transient mark mode (TMM).
- killing is cutting text, yanking is pasting it, and saving to the kill ring is copying.
- font locking is syntax highlighting.
Chapter 3
- In order for a function to be executed by
M-x
, it needs to be made interactive. - apropos is a system to for discovery:
apropos
searches everything,apropos-command
searches commands,- and
apropos-documentation
searches documentation.
- The describe system is a collection of functions that allow you to obtain
information about known items:
describe-mode
,describe-function
,describe-variable
,- and
describe-key
.
Chapter 6
- There is the function
read-only-mode
which toggles read only mode, which replaces the obsoletetoggle-read-only
function.
Getting HELP
There are a couple of help menus that are useful to be able to access easily:
- GNU Emacs NEWS can be summoned with
view-emacs-news
. - Spacemacs documentation can be summoned with
helm-spacemacs-help-docs
. - GNU Emacs Manual can be summoned with
info-display-manual
. - Emacs Lisp Intro has a section on debugging.
Info navigation
The following are key-bindings for emacs mode (use \
to call
evil-execute-in-emacs-state
):
n
next nodep
previous node^
will move upRET
will follow a linkl
return to the last node visiteds
search with a regexf
find a node linked from hered
go to the root node