Common Lisp language support for the Zed editor with integrated LSP server and Jupyter kernel support.
- LSP Features: Syntax highlighting, autocomplete, hover documentation, goto-definition
- Smart Completion: Type-aware parameter snippets, package-qualified completions
- Multi-Package Support: Package labels, user symbols prioritized
- Interactive REPL: Built-in REPL with
Ctrl+Shift+Enter, shared state across files - Rich Output: Display markdown, tables, images, and JSON inline
- Jupyter Compatible: Optional Jupyter Lab/Notebook support
- Cross-Platform: Works on macOS and Linux (not tested)
Required for all features:
-
Common Lisp Implementation (one of):
-
SBCL (recommended - full feature support):
- macOS:
brew install sbcl - Linux:
apt install sbcl/dnf install sbcl/pacman -S sbcl
- macOS:
-
ECL (alternative - ~90% feature parity):
- macOS:
brew install ecl - Linux:
apt install ecl/dnf install ecl/pacman -S ecl
- macOS:
Configure your preferred implementation via
~/.zed-cl/config.json(see Configuration section below). -
Note: Quicklisp and required dependencies will be installed automatically during the build process (make build or make setup-quicklisp).
git clone https://github.com/etyurkin/zed-cl
cd zed-cl
make buildIn Zed:
- Open command palette (
Cmd+Shift+P) - Run "zed: install dev extension"
- Select the cloned directory
All configuration is stored in ~/.zed-cl/config.json using profiles:
{
"active_profile": "sbcl",
"profiles": {
"sbcl": {
"lisp_impl": "sbcl",
"system_index": "system-index.db",
"completion_package_whitelist": [
"CORE-KEYWORDS",
"COMMON-LISP",
"COMMON-LISP-USER"
]
}
}
}Each profile can configure:
lisp_impl- Common Lisp implementation ("sbcl"or"ecl")system_index- System index database filename (in~/.zed-cl/)completion_package_whitelist- Packages to show in completions
Create different profiles for different workflows:
{
"active_profile": "sbcl-full",
"profiles": {
"sbcl-full": {
"lisp_impl": "sbcl",
"system_index": "sbcl-complete.db",
"completion_package_whitelist": ["CORE-KEYWORDS", "COMMON-LISP", "COMMON-LISP-USER"]
},
"ecl-dev": {
"lisp_impl": "ecl",
"system_index": "ecl-packages.db",
"completion_package_whitelist": ["COMMON-LISP", "COMMON-LISP-USER"]
},
"minimal": {
"lisp_impl": "sbcl",
"system_index": "system-index.db",
"completion_package_whitelist": ["COMMON-LISP"]
}
}
}Switch profiles by changing active_profile and restarting Zed.
Control which packages appear in completions. By default (when not set), shows all user-defined packages plus COMMON-LISP and KEYWORD.
Special values:
"CORE-KEYWORDS"- Only core keywords (excludes system keywords)"ALL-KEYWORDS"- All keywords including system ones
Open any .lisp file and get:
- Autocomplete for Common Lisp built-ins and your code
- Hover documentation
- Goto-definition
- Package-aware completions
Inline evaluation:
- Open a
.lispfile - Select code or position cursor in a form
- Press
Ctrl+Shift+Enterto evaluate - See results inline
Terminal REPL (for development):
- Open command palette (
Cmd+Shift+P) - Type "Tasks: Spawn"
- Select "Common Lisp REPL"
- Get an interactive REPL in a terminal tab
All evaluations share a single REPL environment - definitions are automatically available in autocomplete.
Direct Terminal Connection (Advanced):
For debugging or advanced use, connect directly to the master REPL socket:
./scripts/connect-repl.shThis connects via Unix domain socket to the shared REPL using the configured Lisp implementation.
Goto-definition works out-of-the-box for your workspace code. To enable goto-definition for external libraries (Quicklisp packages, SBCL built-ins, etc.), build a system index.
The extension bundles an indexer tool at ~/.zed/extensions/installed/zed-cl/<version>/bin/zed-cl-index.
For SBCL users - index SBCL sources:
# Using Makefile (indexes SBCL built-ins)
make build-system-index
# Or manually
~/.zed/extensions/installed/zed-cl/<version>/bin/zed-cl-index \
--source-dir /path/to/sbcl/src/code \
--output ~/.zed-cl/system-index.db \
--default-package COMMON-LISPFor all users - index Quicklisp packages:
# Example: Index Alexandria
zed-cl-index \
--source-dir ~/quicklisp/dists/quicklisp/software/alexandria-<version> \
--output ~/.zed-cl/system-index.db \
--default-package ALEXANDRIAmacOS (Homebrew):
$(brew --prefix sbcl)/share/sbcl/src
# Usually: /opt/homebrew/share/sbcl/src or /usr/local/share/sbcl/srcLinux:
/usr/share/sbcl/src # Debian/Ubuntu
/usr/share/sbcl-source/src # Some distributionsBuild an index:
zed-cl-index \
--source-dir <PATH> # Directory containing .lisp files (searches recursively)
--output <DB_FILE> # Output database file (appends if exists)
--default-package <PACKAGE> # Default package for symbols without (in-package ...)Query an index:
zed-cl-index \
--query \
--database <DB_FILE> # Database to query
--symbol <SYMBOL> # Symbol name (e.g., MAPCAR, FORMAT) [required]
--package <PACKAGE> # Package name (e.g., SB-IMPL) [optional - searches all packages if omitted]Index SBCL standard library:
# Core runtime (list functions, sequences, etc.)
zed-cl-index \
--source-dir /opt/homebrew/share/sbcl/src/code \
--output ~/.zed-cl/system-index.db \
--default-package COMMON-LISP
# CLOS/MOP (classes, methods, generic functions)
zed-cl-index \
--source-dir /opt/homebrew/share/sbcl/src/pcl \
--output ~/.zed-cl/system-index.db \
--default-package COMMON-LISP
# Interpreter
zed-cl-index \
--source-dir /opt/homebrew/share/sbcl/src/interpreter \
--output ~/.zed-cl/system-index.db \
--default-package COMMON-LISPIndex Quicklisp libraries:
# Alexandria
zed-cl-index \
--source-dir ~/quicklisp/dists/quicklisp/software/alexandria-20241012-git \
--output ~/.zed-cl/system-index.db \
--default-package ALEXANDRIA
# Iterate
zed-cl-index \
--source-dir ~/quicklisp/dists/quicklisp/software/iterate-1.5.3 \
--output ~/.zed-cl/system-index.db \
--default-package ITERATEQuery the index:
# Find MAPCAR in a specific package
zed-cl-index --query \
--database ~/.zed-cl/system-index.db \
--package SB-IMPL \
--symbol MAPCAR
# Output:
# Looking up: SB-IMPL::MAPCAR
#
# Found 1 definition(s):
#
# [1] function in SB-IMPL
# File: /opt/homebrew/share/sbcl/src/code/list.lisp
# Position: line 1388, char 19
# Find MAPCAR in all packages (omit --package)
zed-cl-index --query \
--database ~/.zed-cl/system-index.db \
--symbol MAPCAR
# Output:
# Looking up: MAPCAR (in all packages)
#
# Found 1 definition(s) across packages:
#
# [1] function in SB-IMPL
# File: /opt/homebrew/share/sbcl/src/code/list.lisp
# Position: line 1388, char 19Create different indexes for different projects:
# Minimal: Just SBCL core
zed-cl-index \
--source-dir /path/to/sbcl/src/code \
--output ~/.zed-cl/system-sbcl-only.db \
--default-package COMMON-LISP
# Full: SBCL + all your Quicklisp libraries
zed-cl-index \
--source-dir /path/to/sbcl/src/code \
--output ~/.zed-cl/system-full.db \
--default-package COMMON-LISP
# ... add more librariesSwitch between indexes by changing the system_index field in your active profile in ~/.zed-cl/config.json and restarting the extension.
- User code: Automatically indexed when you open/save
.lispfiles →~/.zed-cl/user-index.db - System libraries: Manually indexed using
zed-cl-index→~/.zed-cl/system-index.db(or custom name) - Goto-definition search order:
- User index (your workspace code)
- System index (SBCL + libraries you indexed)
# Build
make build # Build Rust binaries and extension
make dev # Development mode
make check # Type check only
make test # Run tests
# Jupyter
make install-jupyter # Register kernel for Jupyter
make verify # Verify SBCL installation
# Maintenance
make clean # Clean build artifacts
make help # Show all commandsList running processes:
# Count each process type
ps aux | grep -c '[z]ed-cl-kernel' # Count kernels
ps aux | grep -c '[z]ed-cl-lsp' # Count LSP servers
ps aux | grep -c 'master-repl' # Count master REPLs
# Show detailed process list
ps aux | grep -E 'zed-cl-kernel|zed-cl-lsp|master-repl' | grep -v grepKill processes:
# Kill all zed-cl processes
pkill -f 'zed-cl-kernel' && pkill -f 'zed-cl-lsp' && pkill -f 'master-repl'
# Kill individual components
pkill -f 'zed-cl-kernel' # Kill only kernels
pkill -f 'zed-cl-lsp' # Kill only LSP
pkill -f 'master-repl' # Kill only master REPL
# Force kill if needed
pkill -9 -f 'zed-cl-kernel' && pkill -9 -f 'zed-cl-lsp' && pkill -9 -f 'master-repl'LSP Server:
/tmp/cl-zed-lsp.log- LSP debug logs/tmp/master-repl.log- Master REPL logs
Zed Application:
~/Library/Logs/Zed/Zed.log(macOS)~/.local/share/zed/logs/Zed.log(Linux)
Database Indexes:
~/.zed-cl/system-index.db- System libraries (SBCL + manually indexed packages)~/.zed-cl/user-index.db- User workspace code (auto-indexed)
┌───────────────────────┐
│ Master REPL Process │
│ (Unix domain sockets) │
└──────────┬────────────┘
│
┌─────────┼──────────┐
│ │ │
┌───▼───┐ ┌──▼───┐ ┌───▼───┐
│Console│ │ Zed │ │ Zed │
│ REPL │ │ REPL │ │ LSP │
└───────┘ └──────┘ └───────┘
All components connect to a single master REPL via Unix domain sockets for true state sharing. Code evaluated in any component is immediately available in all others.
MIT