A modern, IDE-like Emacs configuration for software development. This setup provides features similar to VS Code but runs entirely in Emacs.
- Smart Code Completion: Like IntelliSense in VS Code
- Syntax Highlighting: Powered by tree-sitter (faster and more accurate)
- Project Navigation: File tree sidebar, fuzzy file search
- Git Integration: Visual Git interface (Magit)
- Auto-formatting: Your code formats automatically when you save
- Error Checking: See errors and warnings as you type
- Support for Multiple Languages: Python, JavaScript/TypeScript, Go, Rust, PHP, Swift, Scala, and more
You need macOS and Homebrew installed. If you don't have Homebrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"brew tap d12frosted/emacs-plus
brew install emacs-plus --HEAD --with-debug --with-xwidgets --with-dbus --with-mailutils --with-savchenkovaleriy-big-sur-curvy-3d-icon --with-ctags --with-imagemagickVerify the installation:
emacs --versionYou should see "GNU Emacs 30.2" or similar.
If you have an existing Emacs config, back it up first:
mv ~/.emacs.d ~/.emacs.d.backupClone and set up this configuration with the Gruvbox Dark Hard theme:
git clone git@github.com:J4VMC/emacs-modular.git ~/.emacs.dOr if you want to clone it with the Catppuccin Mocha theme:
git clone -b catppuccin git@github.com:J4VMC/emacs-modular.git ~/.emacs.dThese tools are needed for basic functionality:
# Libraries required by Emacs packages
brew install ripgrep fd git libgccjit libvterm imagemagickThat's it! The configuration is already set up to use it automatically.
Install tools only for languages you'll use. You can always come back and add more later.
# Install pyenv
brew install pyenv
# Add pyenv to fish shell
set -Ux PYENV_ROOT $HOME/.pyenv
echo 'pyenv init - fish | source' >> ~/.config/fish/config.fish
source ~/.config/fish/config.fish
# Install build dependencies
brew install openssl readline sqlite3 xz tcl-tk libb2 zstd zlib pkgconfig
# Install Python
pyenv install $(pyenv latest -k 3) && pyenv global $(pyenv latest 3)
# Install Pipx if not already installed
brew install pipx
# Install Python development tools
pipx install basedpyright ruff # Language server (autocomplete, go-to-definition)
# Add all of them to the path
fish_add_path ~/.local/bin
# Virtual environment manager
pipx install poetryTest it works:
which ruff # Should show a path# Install Node.js and npm
fisher install jorgebucaran/nvm.fish
nvm install lts
# Install JavaScript/TypeScript tools
npm install -g typescript # TypeScript compiler
npm install -g typescript-language-server # Language server
npm install -g prettier # Code formatter
npm install -g eslint # Linter
npm install -g vscode-langservers-extracted # ESLint Language server
npm install -g @tailwindcss/language-server # For Tailwind CSS supportTest it works:
which typescript-language-server # Should show a path# Install Go
brew install go
# Install Go development tools
go install golang.org/x/tools/gopls@latest # Language server
go install golang.org/x/tools/cmd/goimports@latest # Formatter
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest # Linter
# Add GOPATH to PATH
fish_add_path (go env GOPATH)/bin
**Test it works:**
```bash
ls (go env GOPATH)/bin/gopls # Should show a path like /Users/you/go/bin/gopls# Install Rust (this also installs cargo, rustc, etc.)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Follow the prompts, then restart your terminal or run:
source "$HOME/.cargo/env.fish"
# Install Rust development tools (these come with rustup)
rustup component add rust-analyzer # Language server
rustup component add rustfmt # Formatter
rustup component add clippy # LinterTest it works:
which rust-analyzer # Should show a path in ~/.cargo/bin# Install PHP
brew install php
# Install Composer (PHP package manager)
brew install composer
# Install PHP development tools
npm install -g intelephense # Language server
composer global require squizlabs/php_code-sniffer # Code style checker
composer global require "dealerdirect/phpcodesniffer-composer-installer"
phpcs --config-set --default_standard PSR12
composer global require phpstan/phpstan # Static analyzer
# PHP unit testing
composer global require phpunit/phpunit# Add Composer to Path
fish_add_path (composer global config bin-dir --absolute)Test it works:
which phpcs # Should show a pathSwift tools come with Xcode:
# Install Xcode Command Line Tools
xcode-select --install
# Install additional Swift tools
brew install swiftlint # Linter
brew install swift-format # FormatterTest it works:
which swift # Should show /usr/bin/swiftNote: For the Swift LSP server, you need the full Xcode app installed (not just command line tools). Download it from the Mac App Store.
# Install Java (required for Scala)
brew install openjdk
# Install Coursier (Scala installer)
brew install coursier/formulas/coursier
# Install Scala and development tools
cs setup # This installs scala, sbt, and other tools
# Install Metals (Scala language server)
cs install metalsTest it works:
which metals # Should show a path# Install SQL formatter, linter, and language server
npm install -g sqlint
npm install -g sql-language-server
npm install -g sql-formatter
# Optional: Install PostgreSQL client for testing
brew install postgresql@18Test it works:
which sqlint # Should show a path# Install Docker Desktop (includes Docker CLI)
[Download the installer](https://desktop.docker.com/mac/main/arm64/Docker.dmg)
# Start Docker Desktop from Applications folder
# Install Dockerfile linter
brew install hadolintTest it works:
which docker # Should show a path
which hadolint # Should show a path# Install Pandoc (for Markdown preview)
brew install pandocTest it works:
which pandoc # Should show a path# Install libxml2, which provides the xmllint formatting tool
brew install libxml2The only package that elpaca fails to install from Github. It's a package that adds structured editing and movement to a wide range of programming languages.
git clone git@github.com:mickeynp/combobulate.git ~/.emacs.d/combobulateemacsWhat happens on first launch:
- Emacs will automatically download and install packages (takes 2-5 minutes)
- You'll see a dashboard with recent files and projects
- The first time you open a code file, Emacs will ask to install tree-sitter grammars
Installing tree-sitter grammars:
- When you open a
.py,.js,.go, or other supported file for the first time - Emacs might prompt: "Install tree-sitter grammar for python?"
- Press
yto install it - This happens once per language
- You can also install them with
M-x treesit-auto-install-all
Let's test with a Python file:
-
Press
C-x C-f(hold Control, press x, release, then hold Control and press f) -
Type
~/test.pyand press Enter -
Type this code:
def hello(name): return f"Hello, {name}" print(hello("World"))
-
Save with
C-x C-s
You should see:
- ✅ Line numbers on the left
- ✅ Syntax highlighting in color
- ✅ Auto-completion popup when you type
- ✅ Code auto-formats when you save
If something doesn't work:
- Check that the language server is installed:
which pyright - Open Emacs and press
M-x lsp-doctor(hold Option/Alt, press x, type "lsp-doctor") - This will show you what's missing
Emacs uses special notation for keyboard shortcuts:
C-x= Hold Control and press xM-x= Hold Option/Alt (⌥) and press xC-c t= Hold Control and press c, then release and press ts-j= Hold Command (⌘) and press j
Some of the shortcuts below are custom for this configuration. All custom keybindings aim to be as ergonomic as possible to prevent the dreaded Emacs pinky. We don't use evil-mode because there's no point in doing that.
| Shortcut | Action |
|---|---|
C-x C-f |
Open a file |
C-x C-s |
Save current file |
C-x k |
Close current file |
C-x b |
Switch between open files |
C-x C-c |
Quit Emacs |
| Shortcut | Action |
|---|---|
C-s |
Search forward |
C-r |
Search backward |
M-g g |
Go to line number |
C-c j |
Jump to any line (visual) |
s-j |
Jump to any character (visual) |
| Shortcut | Action |
|---|---|
C-c p f |
Find file in project (fuzzy) |
C-c p p |
Switch between projects |
C-x t t |
Toggle file tree sidebar |
M-0 |
Focus on file tree |
C-c t a |
Show current project in tree |
| Shortcut | Action |
|---|---|
C-x g |
Open Git status |
In Magit status buffer:
s= Stage file or hunku= Unstage file or hunkc c= Commit (type message, thenC-c C-cto confirm)P p= Push to remoteF p= Pull from remoteq= Quit Magit
| Shortcut | Action |
|---|---|
C-c t |
Toggle terminal at bottom |
C-c p v |
Open terminal in project root |
| Shortcut | Action |
|---|---|
M-. |
Go to definition |
M-, |
Go back |
C-c C-d |
Show documentation |
M-n |
Next error |
M-p |
Previous error |
C-c l |
LSP command prefix |
| Shortcut | Action |
|---|---|
C-space |
Start selection |
C-w |
Cut selection |
M-w |
Copy selection |
C-y |
Paste |
M-; |
Comment/uncomment |
C-/ |
Undo |
| Shortcut | Action |
|---|---|
C-h t |
Start interactive tutorial |
C-h k |
Describe key (press this, then press another key) |
C-h m |
Show all shortcuts for current mode |
C-h f |
Describe function |