Emacs Setup for macOS and GNU/Linux
Table of Contents
This file is a literate program for my emacs configuration. It details how to get started with my setup on macOS and GNU/Linux, which includes:
- Installing emacs with GUI and web browsing support
- Automatic reloading and html creation for the config
- Support for conda virtual environments, including on virtual machines
- LaTeX setup with synctex
- Eglot as an LSP client for python
This file is also exported as a Github pages site here. The repo is here.
1. Base Installation
This section goes over the base installation procedure for vanilla emacs and LaTeX.
1.1. macOS
First, install command line developer tools and homebrew if it is not already installed.
xcode-select --install /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
At this point, brew should be installed, but it may not be added to your path yet. You should run the following two commands to add it to your PATH or follow the instructions that are at the end of the homebrew installation.
(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile eval "$(/opt/homebrew/bin/brew shellenv)"
Next, install emacs-plus. Check the link for more compilation options in case you need different features.
brew tap d12frosted/emacs-plus brew install emacs-plus@30 --with-ctags --with-xwidgets --with-imagemagick --with-native-comp --with-poll --with-modern-alecive-flatwoken-icon
At this step, I also recommend installing basictex for pdflatex support.
brew install --cask basictex eval "$(/usr/libexec/path_helper)"
To install packages during compilation failures, please refer to CTAN and install packages using tlmgr.
sudo tlmgr update --self sudo tlmgr install wrapfig capt-of ulem etoolbox listings
1.2. GNU/Linux
Before installing emacs, first install some dependencies using your package manager. In particular, we need imagemagick for pdf/image support and libgccjit for native compilation. Below I have instructions for pacman, the Arch package manager:
sudo pacman -S imagemagick libgccjit
I recommend building emacs from source to take advantage of all the features of emacs, like xwidgets, imagemagick, and native compilation support. Instructions from the official emacs git repo.
cd ~ git clone https://git.savannah.gnu.org/git/emacs.git cd emacs ./autogen.sh ./configure --with-xwidgets --with-imagemagick --with-native-compilation make -j sudo make install
If webkit does not work, you may need to set export WEBKIT_DISABLE_COMPOSITING_MODE=1
in your ~/.bashrc
to load webpages instead of showing a white screen.
At this step, I also recommend installing a minimal version of TeX live following these instructions:
cd /tmp wget https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz zcat < install-tl-unx.tar.gz | tar xf - cd install-tl-* sudo perl ./install-tl --no-interaction --scheme=basic
You must add texlive to the path by editing your .bashrc file in the home directory by running the following command (assuming you are using the bash shell):
sudo bash -c '(echo; echo "export PATH=\$PATH:/usr/local/texlive/2024/bin/x86_64-linux") >> /etc/profile'
To allow the user to run texlive commands (like tlmgr and pdflatex), run sudo chown -R [username] /usr/local/texlive
which gives ownership to your user.
To install packages during compilation failures, please refer to CTAN and install packages using tlmgr.
tlmgr update --self tlmgr install wrapfig capt-of
2. Conda Setup
To install conda, I used homebrew's miniconda cask for macos:
brew install --cask miniconda conda init "$(basename "${SHELL}")"
On GNU/Linux, I used mambaforge directly:
wget "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh" bash Miniforge3-$(uname)-$(uname -m).sh
After installing conda, remember to close and re-open your terminal. When you re-open it, you should be able to see
(base)
before your command line prompt, which confirms that miniconda is active.I would also recommend creating a test environment in madrona, as follows:
conda create -n testenv python=3.10
You will be able to activate and deactive this on the terminal, and integrate this environment (along with new and existing conda environments) into emacs.r
To use virtual environments, first ensure that there is a symbolic link from the directory to the ~/.virtualenvs directory. Since I installed miniconda through homebrew, I needed to run the following script first for macos.
ln -s /opt/homebrew/Caskroom/miniconda/base/envs ~/.virtualenvs
On GNU/Linux, you can link mambaforge directly instead:
ln -s ~/miniforge3/envs ~/.virtualenvs
3. Install this Config
If you have existing configuration files, I strongly recommend creating a backup of your .emacs.d directory. For instance, I just called mv ~/.emacs.d ~/emacs_old
to save my old configuration.
Next, clone this repo and set up symbolic links so changes to this repo are reflected in the emacs init file.
git clone https://github.com/bsarkar321/emacs_setup cd emacs_setup mkdir ~/.emacs.d ln -s "$(pwd)"/early-init.el ~/.emacs.d/early-init.el ln -s "$(pwd)"/init.el ~/.emacs.d/init.el
After this point, your emacs should be fully set up using my configuration! You can launch emacs and open this file from the terminal by calling emacs README.org
. Note that packages will be installed the first time you set up, and the config may not be fully loaded. At this point, it is normal to see many compilation messages and warnings. However, if you close emacs and open it up again, you should see my full setup loaded.
When opening
README.org
you may see the following warning:The local variables list in README.org or .dir-locals.el contains values that may not be safe (*). Do you want to apply it? You can type y -- to apply the local variables list. n -- to ignore the local variables list. ! -- to apply the local variables list, and permanently mark these values (*) as safe (in the future, they will be set automatically.) i -- to ignore the local variables list, and permanently mark these values (*) as ignored * eval : (add-hook 'after-save-hook (lambda nil (when (y-or-n-p "Tangle?") (org-babel-tangle) (load-file user-init-file) (org-html-export-to-html))) nil t)This is a safety feature to prevent arbitrary code execution in emacs. If you click "y" or "!" you will enable the feature of this file to automatically reload the configuration whenever you save.
4. Tips for Using Emacs
[WIP]
The rest of this file directly contains the code for the early-init and init files. You can edit this document directly, and the changes will be applied upon saving in emacs (if you accept the question that pop up in the minibuffer).
5. Early Init
This early init uses some tricks from Doom Emacs to reduce startup time. It also changes the default frame at startup, which is faster than changing it after the frame is initialized. Specifically:
- tool-bar-lines (the top bar with gui icons) is disabled
- vertical-scroll-bars are disabled
- the title bar is transparent (has same color as rest of emacs)
- The width and height are half the screen by default
1: ;;; early-init.el --- Early initialization 2: 3: ;;; Commentary: 4: ;; 5: ;; Using early-init for speed. 6: ;; 7: 8: ;;; Code: 9: 10: (setq gc-cons-threshold most-positive-fixnum 11: gc-cons-percentage 0.6) 12: 13: (add-hook 'emacs-startup-hook 14: (lambda () 15: (setq gc-cons-threshold 16777216 16: gc-cons-percentage 0.1))) 17: 18: (defun doom-defer-garbage-collection-h () 19: "Defer gc." 20: (setq gc-cons-threshold most-positive-fixnum)) 21: 22: (defun doom-restore-garbage-collection-h () 23: "Restore gc." 24: (run-at-time 25: 1 nil (lambda () (setq gc-cons-threshold 16777216)))) 26: 27: (add-hook 'minibuffer-setup-hook #'doom-defer-garbage-collection-h) 28: (add-hook 'minibuffer-exit-hook #'doom-restore-garbage-collection-h) 29: 30: ;; package-initialize already in init.el 31: (setq package-enable-at-startup nil) 32: 33: ;; Inhibit resizing frame 34: (setq frame-inhibit-implied-resize t) 35: 36: ;; Disable before actual init 37: (push '(tool-bar-lines . 0) default-frame-alist) 38: (push '(vertical-scroll-bars) default-frame-alist) 39: (when (featurep 'ns) 40: (push '(ns-transparent-titlebar . t) default-frame-alist)) 41: (push '(width . 0.5) default-frame-alist) 42: (push '(height . 0.5) default-frame-alist) 43: 44: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 45: ;;; early-init.el ends here
6. Init
The code below gets constructed into the init.el, where most of the customization lies.
1: ;; .emacs.d/init.el --- Init for Emacs 2: 3: ;;; Commentary: 4: 5: ;; Lightweight Emacs config file to make Emacs look like atom 6: ;; while having tramp/python/c++/latex support. 7: 8: ;;; Code: 9: 10: ;; This is only here to resolve flymake complaints 11: (eval-when-compile 12: (defvar xwwp-search-prefix) 13: (defvar org-image-actual-width) 14: (defvar org-support-shift-select) 15: (defvar org-latex-listings) 16: (defvar org-src-fontify-natively) 17: (defvar org-file-apps) 18: (defvar TeX-auto-save) 19: (defvar TeX-parse-self) 20: (defvar TeX-view-program-selection) 21: (defvar TeX-source-correlate-start-server) 22: (defvar TeX-source-correlate-method) 23: (defvar TeX-source-correlate-mode) 24: (defvar reftex-plug-into-AUCTeX) 25: (defvar reftex-bibliography-commands) 26: 27: (defvar markdown-command) 28: (defvar LaTeX-mode-map) 29: (defvar corfu-map) 30: (defvar corfu-popupinfo-delay) 31: (defvar tramp-use-ssh-controlmaster-options) 32: (defvar tramp-verbose) 33: 34: (declare-function pdf-loader-install nil) 35: (declare-function TeX-revert-document-buffer nil) 36: (declare-function pyvenv-mode nil) 37: (declare-function pyvenv-workon-home nil) 38: (declare-function global-corfu-mode nil) 39: (declare-function corfu-popupinfo-mode nil) 40: ) 41:
6.1. Package Support
Here I define that melpa should be added to the package archives, which has a larger repository of user-created packages.
42: ;; =================================== 43: ;; MELPA Package Support 44: ;; =================================== 45: ;; Enables basic packing support 46: (require 'package) 47: 48: (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) 49: 50: (package-initialize) 51: 52: (when (not package-archive-contents) (package-refresh-contents)) 53: 54: (defvar my-packages 55: '(atom-one-dark-theme ;; melpa 56: corfu 57: jupyter ;; melpa 58: htmlize 59: magit 60: markdown-mode 61: pdf-tools 62: pyvenv ;; melpa 63: use-package 64: xwwp ;; melpa 65: processing-mode ;; melpa 66: )) 67: 68: ;; Iterate on packages and install missing ones 69: (dolist (pkg my-packages) 70: (unless (package-installed-p pkg) 71: (package-install pkg))) 72:
6.2. Basic Customization
Adding basic customization options, like loading the theme and setting a custom-file so it does not conflict with this init file.
73: ;; =================================== 74: ;; Basic Customization 75: ;; =================================== 76: 77: (load-theme 'atom-one-dark t) 78: 79: (setq inhibit-startup-message t) ;; Hide the startup message 80: (setq column-number-mode t) ;; Show column number in mode-line 81: (global-superword-mode t) ;; Superword for all buffers 82: (delete-selection-mode t) ;; Delete when typing over selection 83: (setq split-height-threshold nil) ;; Do not split by height by default 84: (setq split-width-threshold 0) ;; Split by width by default 85: (electric-pair-mode t) ;; Default electric pairs (opening parentheses create closing) 86: (setq use-short-answers t) ;; Use y/n instead of yes or no 87: (setq make-backup-files nil) ;; Do not save the backup files ~filename 88: 89: (windmove-default-keybindings 'meta);; Use option key with arrows to switch which window is active 90: 91: ;; separate custom.el so users can set preferences separately 92: (defconst custom-file (expand-file-name "custom.el" user-emacs-directory)) 93: (load custom-file t) 94:
6.3. macOS Support
Enables some mac-specific customization, including full screen with command-control-f, and commenting/uncommenting regions of code with command-/.
I also use command-option-<arrow-keys> to change the size of the focused window.
95: ;; =================================== 96: ;; macOS Default Keys 97: ;; =================================== 98: (setq mac-option-modifier 'meta 99: mac-command-modifier 'super 100: mac-right-option-modifier 'meta) 101: 102: (when (string= system-type "darwin") (defvar dired-use-ls-dired nil)) 103: 104: (defun comment-or-uncomment-region-or-line () 105: "Comments the region or the current line if there's no active region." 106: (interactive) 107: (let (beg end) 108: (if (region-active-p) 109: (setq beg (region-beginning) end (region-end)) 110: (setq beg (line-beginning-position) end (line-end-position))) 111: (comment-or-uncomment-region beg end))) 112: 113: (global-set-key (kbd "s-Z") 'undo-redo) 114: (global-set-key (kbd "s-/") 'comment-or-uncomment-region-or-line) 115: (global-set-key (kbd "C-s-f") 'toggle-frame-fullscreen) 116: 117: (global-set-key (kbd "M-s-<left>") 'shrink-window-horizontally) 118: (global-set-key (kbd "M-s-<right>") 'enlarge-window-horizontally) 119: (global-set-key (kbd "M-s-<up>") 'shrink-window) 120: (global-set-key (kbd "M-s-<down>") 'enlarge-window) 121:
6.4. Xwidgets Convenience functions
Use xwwp to have a browser within emacs.
Note: it is currently a big buggy, especially when multiple windows are created. However it works great for previewing html or testing out websites.
122: ;; =================================== 123: ;; xwwp setup 124: ;; =================================== 125: (use-package xwwp) 126: (setq xwwp-search-prefix "https://duckduckgo.com/?q=") 127:
6.5. Writing
Enable line numbers, word wrap, and spell checking for text modes.
128: ;; =================================== 129: ;; Writing Modes 130: ;; =================================== 131: (defun human-text-on () 132: "Turn on human text options." 133: (turn-on-visual-line-mode) 134: (display-line-numbers-mode) 135: ) 136: 137: ;; Txt support 138: (add-hook 'text-mode-hook #'human-text-on) 139:
6.5.1. Org Mode
Writing for org mode documents, like this configuration file! Enables opening web links within emacs, along with some other customization options to make org mode easier for me to work with.
140: ;; Org support 141: (setq org-image-actual-width 500) 142: (add-hook 'org-mode-hook #'human-text-on) 143: (setq org-support-shift-select t) 144: (setq org-latex-src-block-backend 'listings) 145: 146: (use-package htmlize) 147: (setq org-src-fontify-natively t) 148: (setq browse-url-browser-function 'xwidget-webkit-browse-url) 149: (setq org-file-apps 150: '((auto-mode . emacs) 151: ("\\.x?html?\\'" . (lambda (file link) (xwidget-webkit-browse-url (concat "file://" link)))) 152: ("\\.mp4\\'" . "vlc \"%s\""))) 153: 154: (org-babel-do-load-languages 'org-babel-load-languages 155: '( 156: (python . t) 157: (shell . t) 158: )) 159:
6.5.2. Markdown Mode
Write markdown documents, common for project README files.
160: ;; Markdown support 161: (use-package markdown-mode 162: :ensure t 163: :mode ("README\\.md\\'" . gfm-mode) 164: :init (setq markdown-command "multimarkdown")) 165:
6.5.3. LaTeX
Write LaTeX documents with support for previewing and syncing (like double clicking on overleaf previews).
166: ;; Latex support 167: (pdf-loader-install) 168: (add-hook 'pdf-view-mode-hook 'pdf-view-dark-minor-mode) 169: 170: (add-hook 'eww-mode-hook 'pdf-tools-install) 171: 172: (use-package tex 173: :ensure auctex) 174: 175: (add-hook 'LaTeX-mode-hook 176: (lambda() 177: (turn-on-reftex) 178: (flyspell-mode) 179: (setq TeX-auto-save t) 180: (setq TeX-parse-self t) 181: (setq TeX-view-program-selection '((output-pdf "PDF Tools")) 182: TeX-source-correlate-start-server t) 183: (setq TeX-source-correlate-method 'synctex) 184: 185: (setq TeX-source-correlate-mode t) 186: (setq-default TeX-master nil) 187: (global-set-key (kbd "C-c C-g") 'pdf-sync-forward-search) 188: (setq reftex-plug-into-AUCTeX t) 189: (setq reftex-bibliography-commands '("bibliography" "nobibliography" "addbibresource")) 190: (define-key LaTeX-mode-map (kbd "$") 'self-insert-command) 191: ) 192: ) 193: 194: (add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer) 195:
6.6. Programming
Work with programming modes, even in remote systems using TRAMP.
196: ;; =================================== 197: ;; Programming Modes 198: ;; =================================== 199: (add-hook 'prog-mode-hook 'display-line-numbers-mode) ;; Show line numbers for programming languages 200: 201: (use-package corfu 202: :custom 203: ;; (corfu-cycle t) ;; Enable cycling for `corfu-next/previous' 204: (corfu-auto t) ;; Enable auto completion 205: ;; (corfu-separator ?\s) ;; Orderless field separator 206: ;; (corfu-quit-at-boundary nil) ;; Never quit at completion boundary 207: ;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match 208: ;; (corfu-preview-current nil) ;; Disable current candidate preview 209: ;; (corfu-preselect 'prompt) ;; Preselect the prompt 210: ;; (corfu-on-exact-match nil) ;; Configure handling of exact matches 211: ;; (corfu-scroll-margin 5) ;; Use scroll margin 212: 213: :bind 214: (:map corfu-map 215: ;; Option 1: Unbind RET completely 216: ("RET" . nil)) 217: :init 218: (global-corfu-mode)) 219: 220: (use-package corfu-popupinfo 221: :init 222: (corfu-popupinfo-mode) 223: (setq corfu-popupinfo-delay '(1.0 . 0.1))) 224: 225: (use-package emacs 226: :init 227: (setq completion-cycle-threshold 3)) 228:
6.6.1. Elisp Support
Elisp syntax checking for emacs configuration files.
229: (add-hook 'emacs-lisp-mode-hook 'flymake-mode) 230:
6.6.2. Python Support
Python with eglot as an LSP. Note that you may need to pip install a language server after activating a virtual environment.
231: ;; Python with eglot 232: ;; (add-hook 'python-mode-hook 'eglot-ensure) 233: (setq-default eglot-workspace-configuration 234: '(:pylsp (:skip_token_initialization t 235: :plugins (:ruff (:enabled t 236: :formatEnabled t) 237: :pylsp_mypy (:enabled t))) 238: )) 239:
6.6.3. Tramp + Conda
Connecting virtual environments on local and remote systems.
240: ;; Conda and TRAMP setup 241: 242: (pyvenv-mode 1) 243: 244: (defun tramp-conda-setup() 245: "Set up conda for tramp." 246: (when default-directory (if (file-remote-p default-directory) 247: (setenv "WORKON_HOME" (concat (file-remote-p default-directory) "~/.virtualenvs")) 248: (setenv "WORKON_HOME" "~/.virtualenvs")))) 249: 250: (advice-add #'pyvenv-workon-home :before #'tramp-conda-setup) 251: 252: (setq tramp-use-ssh-controlmaster-options nil) 253: (setq exec-path (append exec-path '("/afs/.ir/users/b/i/bidiptas/bin"))) 254: (setq tramp-verbose 6) 255:
6.6.4. C/C++/CUDA
Add support for CUDA and C/C++. When using cmake remember to do cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1
so the lsp has enough information to avoid incorrect errors.
256: (add-to-list 'auto-mode-alist '("\\.cu\\'" . c++-mode)) 257: (add-hook 'c++-mode-hook 'eglot-ensure) 258:
6.6.5. Processing (Art)
Add support for Processing files (Java)
259: (setq processing-location "/usr/local/bin/processing-java") 260: (setq processing-application-dir "/Applications/Processing.app") 261: (setq processing-sketchbook-dir "~/Documents/Processing") 262:
6.7. Wrap up
263: ;; emacs -eval "(message (emacs-init-time))" -Q 264: (message (emacs-init-time)) 265: 266: (provide 'init) 267: ;;; init.el ends here
7. Acknowledgements
Big thanks to:
- literatemacs for demonstrating the use of org for the user init
- org-html-themes for providing export functionality to a pretty html theme
- Charl Botha's stackoverflow answer to have separate custom.el
- Emacs Wiki and the emacs manual for understanding miscellaneous emacs/elisp topics.
- Overleaf latex examples for syntax highlighting.
- Various other forums and resources on emacs configurations.1
8. License
Copyright (C) 2023 Bidipta Sarkar
Author: Bidipta Sarkar
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
Footnotes:
I know my LaTeX support was largely based on some website, but I can't find it anymore. If anyone knows where to find it, I'll edit this list to add that link.