This repository lists my configuration for GNU Emacs, my primary editor. The install instructions and customizations should work on a GNU/Linux platform and are not extensively tested on Windows. Suggestions and pull requests are welcome.
The Emacs version on Ubuntu is outdated. There are a couple of PPAs [Emacs stable releases, Ubuntu Emacs Lisp] that we can use, but they do not include build flags that I need. So, I prefer to build from source [*Build GNU Emacs].
Add the following repository only if you are using Ubuntu 20.04.
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
# Install gcc-10 packages with the required support for libgccjit
sudo apt install -y gcc-10 g++-10 libgccjit0 libgccjit-10-dev libjansson4 libjansson-dev
Use the following instructions to configure and build GNU Emacs from the source (Ubuntu 20.04 or 22.04).
wget https://ftp.gnu.org/gnu/emacs/emacs-29.1.tar.xz
tar -xf emacs-29.1.tar.xz
# Use GCC 10 if you are on Ubuntu 20.04
export CC=/usr/bin/gcc-11 CXX=/usr/bin/g++-11
make distclean
./autogen.sh
./configure --with-cairo --with-modules --without-compress-install --with-x-toolkit=no --with-gnutls=ifavailable --without-gconf --without-xwidgets --without-toolkit-scroll-bars --without-xaw3d --without-gsettings --with-mailutils --with-native-compilation=aot --with-json=ifavailable --with-harfbuzz --with-imagemagick --with-jpeg --with-png --with-rsvg --with-tiff --with-wide-int --with-xft --with-xml2 --with-xpm --with-gif --with-threads --with-included-regex --with-zlib --without-sound --with-dbus --without-pop --with-dbus --with-tree-sitter=ifavailable CFLAGS="-O3 -mtune=native -march=native -fomit-frame-pointer -funroll-loops -floop-parallelize-all" prefix=/usr/local
# Use NATIVE_FULL_AOT=1 to native compile ahead-of-time all the elisp files included in the Emacs
# distribution instead of after startup
make -j"$(nproc)" NATIVE_FULL_AOT=1
sudo make install
Try the following if the build fails: make bootstrap
or rm lisp/loaddefs.el; make;
.
You can check whether “NATIVE__COMP” is part of the system-configuration-features
variable. Run the following to native compile all Elisp files under a directory (e.g., ~/.emacs.d
):
(native-compile-async "//home/swarnendu//.emacs.d/elpa" 'recursively)
Back up the contents of your .emacs.d
directory if it is not empty, and then check out the source.
git clone https://github.com/swarnendubiswas/dotemacs.git .emacs.d
modules
- Emacs modules divided across featuresextras
- third-party packages (may not be available from the package archives)snippets
- custom snippetsreferences
- documentation and help filesdir-locals-examples
- examples to show how to use directory-local variablesprojectile-examples
- projectile configuration files
The following are examples of a few customization options defined in init-config.el. Please check the file for more customization options.
sb/theme
– Set the desired theme from a bunch of themes (default ismodus-vivendi
)sb/modeline-theme
– Set the desired modeline theme (default ispowerline-nano
)sb/fill-column
– Column beyond which lines should not extend (default is 100)sb/minibuffer-completion
- Choose eitherivy
orvertico
for narrowing and selection (default isvertico
)sb/capf
- Choose eithercompany
orcorfu
for in-buffer completion at point (default iscompany
)sb/tab-bar-handler
- Choose eitherawesome-tab
orcentaur-tabs
for tabbed display (default iscentaur-tabs
)sb/project-handler
- Choose eitherproject.el
orprojectile
for handling projects (default isprojectile
)sb/lsp-provider
- Choose betweenlsp-mode
andeglot
(default islsp-mode
)sb/disable-package.el
- Disablepackage.el
and prefer thestraight.el
package manager.sb/python-langserver
- Choose betweenpylsp
andpyright
as the Python language server (default ispylsp
).sb/delete-trailing-whitespace-p
- Control whether trailing whitespace should be deleted
We enable LSP support for the more popular languages supported with either lsp-mode
or eglot
. You may need to install the necessary language servers separately to complement the packages. Use M-x lsp-install-server
or check setup-emacs.sh
.
npm install -save-dev @emacs-grammarly/grammarly-languageserver
LTEX_VER="16.0.0"
sudo apt-get install -y libslf4j-java liblog4j1.2-java
wget https://github.com/valentjn/ltex-ls/releases/download/${LTEX_VER}/ltex-ls-${LTEX_VER}-linux-x64.tar.gz
tar xf ltex-ls-${LTEX_VER}-linux-x64.tar.gz
JDT_VER="1.27.1"
wget https://github.com/eclipse/eclipse.jdt.ls/archive/refs/tags/v${JDT_VER}.tar.gz
tar xf v${JDT_VER}.tar.gz
cd eclipse.jdt.ls-${JDT_VER}
./mvnw clean verify -DskipTests=true
# Add "eclipse.jdt.ls-${JDT_VER}/org.eclipse.jdt.ls.product/target/repository/bin" to $PATH
# rm -rf eclipse.jdt.ls-${JDT_VER}
Support for LSP in GNU Emacs means you will usually not need to create tags separately. However, tags are still useful for languages that are not yet supported by lsp-mode
and to understand complicated project structures that a language server may not understand. I prefer Universal Ctags over GNU Global.
GNU Global has better database search support while Universal Ctags supports more languages. GNU Global can be built with support for Universal Ctags.
- https://github.com/rdbeni0/emacs.d/tree/main/ggtags
- Compiling GNU Global with universal-ctags support
- Tags for Emacs: Relationship between etags, ebrowse, cscope, GNU Global and exuberant ctags
- GTags for Python in Emacs
Use Universal Ctags (u-ctags
) with Citre
.
-R
– recursively scan for files-e
– use Emacs-compatible syntax--list-excludes
– check which patterns are excluded from processing--list-languages
– list supported languages--languages=Python
– include Python files
By default, Emacs expects a tag file by the name TAGS
in the current directory. Once the tag file is built, the following commands exercise the tag indexing feature.
M-x visit-tags-table <RET> FILE <RET>
– Select the tag fileFILE
to useM-. [TAG] <RET>
– Find the first definition ofTAG
. The default tag is the identifier under the cursor.M-*
– Pop back to where you invokedM-.
C-u M-.
– Find the next definition for the last tag
For more commands, see the Tags topic in the Emacs info document.
ctags -eR --exclude=*.py --exclude=*.json --exclude=*.js --exclude=build* --exclude=*.sh --exclude=*.xml --exclude=*.java --exclude=*.html --exclude=*.md --exclude=*.pbtxt --exclude=*.png --exclude=*.css --exclude=*.rst --exclude=bazel-* --exclude=doc --exclude=node_modules --exclude=.meteor --exclude='packages/*/.build/'
ctags -e -R [email protected] --languages=EmacsLisp .
ctags -eR -quiet=yes [email protected] .
ctags -eR --languages=Python
find . -name "*.tex" | ctags -e -quiet -L -
find src -name "*.py" | ctags -e -L -
find -L . -type f -iname "*.cpp" -o -iname "*.c" -o -iname "*.cc" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.cu" | ctags -e -L -
$ cat .ctagsignore
dir1
dir2
dir3
Use GNU Global with counsel-gtags
: gtags -cv --gtagslabel=new-ctags
find -L . -type f -iname "*.cpp" -o -iname "*.c" -o -iname "*.cc" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.py" ! -iname "*.cu" -o -iname "*.proto" | gtags -cv --gtagslabel=new-ctags -f -
find ./src -type f -iname "*.py" ! -iname "__init__.py" | gtags -cv --gtagslabel=new-ctags -f -
find . -type f -iname "*.tex" | gtags -vc --gtagslabel=new-ctags -f -
Enable server support either through init.el
or as a systemd
service. I prefer the systemd
approach. Create a file $HOME/.config/systemd/user/emacs.service
with the following content.
[Unit]
Description=GNU Emacs Daemon
[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon
ExecStop=/usr/bin/emacsclient --eval "(progn (setq kill-emacs-hook 'nil) (kill-emacs))"
Restart=always
[Install]
WantedBy=default.target
- Enable the unit to start at login:
systemctl --user enable emacs.service
- Disable the unit to start at login:
systemctl --user disable emacs.service
- Start the service for the current session:
systemctl --user start emacs.service
- Stop the service for the current session:
systemctl --user stop emacs.service
- Restart the service for the current session:
systemctl --user restart emacs.service
Create emacs.desktop
and emacsclient.desktop
files in $HOME/.local/share/applications
with the following content.
[Desktop Entry]
Name=GNU Emacs
GenericName=Text Editor
Comment=Edit text
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
Exec=/usr/local/bin/emacs
Icon=emacs
Type=Application
Terminal=false
Categories=Development;TextEditor;Utility;
StartupWMClass=Emacs
Keywords=Text;Editor;
[Desktop Entry]
Name=GNU Emacsclient
GenericName=Text Editor
Comment=Edit text
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
Exec=emacsclient -c -a "" -n -F "'(fullscreen . maximized)" %f
Icon=emacs
Type=Application
Terminal=false
Categories=Development;TextEditor;Utility;
StartupWMClass=Emacs
Keywords=Text;Editor;
I use LSP over Tramp intensively, and LSP+Tramp is sluggish and fails often. It seems difficult to properly set up language servers with Tramp support. Therefore, I prefer to use Emacs in a terminal that has a much better performance. It is important to set up support for 24-bit colors and proper keybindings in the terminal for a good experience. I use Alacritty which is easy to customize.
Using Terminal Emacs over Tramp for editing remote files obviates the need for a remote langsever.
Use the steps mentioned in the link Spacemacs Terminal to enable support for 24bit colors in the terminal.
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export TERM=xterm-24bit
Using export TERM=xterm-24bit
may lead to failures when accessing remote systems. In such cases, we can fall back to TERM=xterm-256color ssh -X <remote-path>
.
Start the Emacs daemon with emacs --daemon
. To run Emacsclient with a GUI, use emacsclient -c -a ""
, where -a ""
starts Emacs daemon and reattaches. To run Emacsclient in a terminal, use emacsclient -nw -q
or emacsclient -t -q -a ""
, where -t
starts the client in the terminal.
Add the following to your .bashrc
to use Emacsclient as your editor.
export ALTERNATE_EDITOR=""
export EDITOR="emacsclient -t" # $EDITOR opens in terminal
export VISUAL="emacsclient -c -a emacs" # $VISUAL opens in GUI mode
kill -s USR2 [pid]
killall -s USR2 emacs
pkill -USR2 emacs
Estimate the best possible startup time with emacs -q --eval
‘(message “%s” (emacs-init-time))’=.
There are a few choices to evaluate the performance of the configuration.
- Set
use-package-compute-statistics
and then invokeuse-package-report
- Use the package
benchmark-init
- Use the script
profile-dotemacs.el
as follows:emacs -Q -l $HOME/.emacs.d/extras/profile-dotemacs.el -f profile-dotemacs
- Advanced Techniques for Reducing Emacs Startup Time
- Flickering with
corfu-terminal-mode
- Disable pairing = before at the beginning of a word in
smartparens
- Enable
flycheck-mode
for Elisp configuration files - Load custom snippets with
yasnippet
- Disable prettifying of symbols on auto-completion in
LaTeX-mode