add readme

This commit is contained in:
2026-01-29 14:11:57 -05:00
parent 3b6d7d95ce
commit 89207e8271
+410
View File
@@ -0,0 +1,410 @@
# Neovim Fennel/Clojure Configuration
A Neovim configuration optimized for Lisp development (Fennel, Clojure, Scheme, Racket) using [Fennel](https://fennel-lang.org/) as the configuration language.
## Prerequisites
- **Neovim 0.11+** (uses built-in LSP configuration)
- **Git** (for plugin installation)
### Optional but Recommended
Install language servers for full IDE features:
```bash
# Clojure LSP (for Clojure/ClojureScript)
brew install clojure-lsp/brew/clojure-lsp
# Fennel Language Server (for Fennel)
cargo install fennel-language-server
# Lua Language Server (for Lua/Neovim plugin development)
brew install lua-language-server
```
Or use Mason inside Neovim: `:MasonInstall clojure-lsp lua-language-server`
## Quick Start
1. Clone this repo to `~/.config/nvim`
2. Open Neovim - plugins install automatically on first launch
3. Open a `.fnl` or `.clj` file and start editing
## Understanding Lisp Editing
If you're new to Lisp, here are the key concepts that make editing different from other languages.
### S-Expressions (Sexps)
All Lisp code is made of nested parenthesized expressions called **s-expressions** or **sexps**:
```clojure
(defn greet [name] ; <- this whole thing is a "form" or "sexp"
(str "Hello, " name)) ; <- this is a nested form
```
- **Form**: A complete s-expression (anything in balanced parens/brackets/braces)
- **Element**: A single item - either an atom (`name`, `42`, `:keyword`) or a form
### Structural Editing
Instead of editing text character-by-character, Lisp programmers edit **structures**. The paredit plugin keeps your parentheses balanced automatically and lets you manipulate code by its structure.
**Example - Slurping:**
```clojure
;; Before: cursor on the (+ 1 2) form
(let [x (+ 1 2)] 3)
;; After pressing >) (slurp forward)
(let [x (+ 1 2) 3])
```
**Example - Barfing:**
```clojure
;; Before
(let [x (+ 1 2 3)])
;; After pressing <) (barf forward) on the + form
(let [x (+ 1 2) 3])
```
### Interactive Development (REPL)
Lisp development is **interactive**. You connect to a running program (REPL) and evaluate code as you write it. Conjure handles this - you can evaluate any expression and see results immediately.
---
## Keybindings Reference
**Leader key: `Space`**
Press `Space` and wait to see available options via which-key.
### General Navigation
| Key | Action |
|-----|--------|
| `Ctrl-h/j/k/l` | Move between windows |
| `Space f f` | Find files (Telescope) |
| `Space f g` | Live grep in project |
| `Space f b` | List open buffers |
| `Space f h` | Search help tags |
| `Space b n` | Next buffer |
| `Space b p` | Previous buffer |
| `Space b d` | Delete buffer |
### General Editing
| Key | Action |
|-----|--------|
| `jk` | Escape insert mode |
| `Space w` | Save file |
| `Space f s` | Save all files |
| `Space q` | Quit |
| `Esc` | Clear search highlight |
### LSP (Language Server)
Available when editing files with LSP support (Clojure, Fennel, Lua):
| Key | Action |
|-----|--------|
| `gd` | Go to definition |
| `gD` | Go to declaration |
| `gr` | Find references |
| `gi` | Go to implementation |
| `K` | Show hover documentation |
| `Space r n` | Rename symbol |
| `Space c a` | Code actions |
| `Space e` | Show diagnostic popup |
| `Space F` | Format buffer |
| `[d` | Previous diagnostic |
| `]d` | Next diagnostic |
**Commands:** `:LspInfo`, `:LspStart`, `:LspStop`, `:LspRestart`, `:LspLog`
---
## Conjure - REPL Integration
Conjure connects your editor to a running REPL, allowing you to evaluate code interactively.
### Starting a REPL
**Clojure:**
```bash
# In your project directory
clj -M:repl # or however your project starts a REPL
```
**Fennel:**
```bash
fennel --repl
```
Conjure auto-connects when you open a Lisp file and a REPL is running.
### Evaluation Keybindings
All Conjure bindings start with `Space` (local leader):
| Key | Action |
|-----|--------|
| `Space e e` | Evaluate form under cursor |
| `Space e r` | Evaluate root (top-level) form |
| `Space e b` | Evaluate entire buffer |
| `Space e f` | Evaluate file |
| `Space e !` | Evaluate form and replace with result |
| `Space e w` | Evaluate word under cursor |
### Log Buffer
Results appear in a floating HUD window. To interact with the full log:
| Key | Action |
|-----|--------|
| `Space l v` | Open log in vertical split |
| `Space l s` | Open log in horizontal split |
| `Space l t` | Open log in new tab |
| `Space l q` | Close log windows |
| `Space l r` | Reset/clear the log |
### Documentation
| Key | Action |
|-----|--------|
| `K` | Show documentation for symbol under cursor |
| `Space e d` | Describe form under cursor |
### Tip: Learn Interactively
Run `:ConjureSchool` for an interactive tutorial inside Neovim.
---
## nvim-paredit - Structural Editing
Paredit keeps parentheses balanced and provides structural editing commands.
### Navigation
Move by **elements** (atoms or forms) rather than words:
| Key | Action |
|-----|--------|
| `W` | Next element head |
| `B` | Previous element head |
| `E` | Next element tail |
| `gE` | Previous element tail |
| `(` | Jump to parent form's opening paren |
| `)` | Jump to parent form's closing paren |
| `T` | Jump to top-level form's head |
### Slurp and Barf
**Slurp**: Pull the next/previous element INTO the current form
**Barf**: Push the last/first element OUT OF the current form
| Key | Action |
|-----|--------|
| `>)` | Slurp forward (pull next element in) |
| `<(` | Slurp backward (pull previous element in) |
| `<)` | Barf forward (push last element out) |
| `>(` | Barf backward (push first element out) |
**Visual example:**
```clojure
;; Cursor on inner form: (+ 1 2)
(foo (+ 1 2) 3 4)
;; >) slurp forward - pull 3 into the form
(foo (+ 1 2 3) 4)
;; >) again - pull 4 in
(foo (+ 1 2 3 4))
;; <) barf forward - push 4 back out
(foo (+ 1 2 3) 4)
```
### Dragging Elements
Move elements/forms left and right within their parent:
| Key | Action |
|-----|--------|
| `>e` | Drag element right |
| `<e` | Drag element left |
| `>f` | Drag form right |
| `<f` | Drag form left |
### Wrapping
Wrap an element in delimiters:
| Key | Action |
|-----|--------|
| `cse(` or `cse)` | Wrap element in `()` |
| `cse[` or `cse]` | Wrap element in `[]` |
| `cse{` or `cse}` | Wrap element in `{}` |
### Splice (Unwrap)
| Key | Action |
|-----|--------|
| `dsf` | Splice - delete surrounding form, keeping contents |
**Example:**
```clojure
;; Before (cursor inside the when form)
(when true (println "hello"))
;; dsf - splice, removing the when form
true (println "hello")
```
### Raise
| Key | Action |
|-----|--------|
| `Space o` | Raise form (replace parent with current form) |
| `Space O` | Raise element (replace parent with current element) |
### Text Objects
Use with operators like `d`, `c`, `y`, `v`:
| Text Object | Meaning |
|-------------|---------|
| `af` | Around form (including parens) |
| `if` | Inside form (excluding parens) |
| `aF` | Around top-level form |
| `iF` | Inside top-level form |
| `ae` | Around element |
| `ie` | Inside element |
**Examples:**
- `daf` - Delete around form (delete entire form including parens)
- `cif` - Change inside form (replace form contents)
- `yae` - Yank around element
---
## Workflow Examples
### Editing a Clojure Function
1. Start your REPL: `clj` in terminal
2. Open your `.clj` file
3. Write a function:
```clojure
(defn add [a b]
(+ a b))
```
4. `Space e r` to evaluate the top-level form
5. Test it: type `(add 1 2)` and `Space e e` to evaluate
6. See `3` appear in the HUD
### Refactoring with Paredit
Transform `(if test a b)` to `(when test a)`:
1. Position cursor on `if`
2. `ciw` to change word, type `when`
3. Move to `b`, `dae` to delete the element
4. Done: `(when test a)`
### Wrapping Code in a Let
```clojure
;; Start with:
(+ x y)
;; Position on the form, then: cse(
((+ x y))
;; Now you have wrapped parens. Type your let:
(let [z 1] (+ x y))
```
---
## File Structure
```
~/.config/nvim/
├── init.lua # Entry point (Lua)
├── lua/
│ ├── bootstrap.lua # Core plugins (nfnl, treesitter, telescope)
│ ├── config/ # AUTO-GENERATED from fnl/config/
│ └── plugins/ # AUTO-GENERATED from fnl/plugins/
└── fnl/
├── config/init.fnl # Your settings, keymaps, LSP config
└── plugins/init.fnl # Plugin specifications
```
**Important:** Edit files in `fnl/`, not `lua/config/` or `lua/plugins/` - those are auto-generated.
---
## Customization
### Add a Plugin
Edit `fnl/plugins/init.fnl`, add a spec to the vector:
```fennel
{:1 "author/plugin-name"
:config (fn [] (setup-code-here))}
```
### Add a Keymap
Edit `fnl/config/init.fnl`:
```fennel
(vim.keymap.set :n "<leader>x" ":SomeCommand<CR>" {:desc "Do something"})
```
### Change the Colorscheme
Edit the tokyonight config in `fnl/plugins/init.fnl`, or add a different colorscheme plugin.
---
## Troubleshooting
### LSP not working?
1. Check if the server is installed: `:LspInfo`
2. Check the log: `:LspLog`
3. Ensure you're in a project with root markers (`.git`, `deps.edn`, etc.)
### Conjure not connecting?
1. Make sure your REPL is running before opening the file
2. For Clojure: ensure nREPL is exposed (default port 7888 or `.nrepl-port` file)
3. Check `:ConjureLog` for connection errors
### Paredit feels wrong?
Structural editing takes practice. Start with just `>)` and `<)` for slurp/barf, then gradually add more commands. The `:help nvim-paredit` documentation is excellent.
---
## Learning Resources
- **Conjure Interactive Tutorial**: `:ConjureSchool`
- **Fennel Language**: https://fennel-lang.org/tutorial
- **Clojure for the Brave and True**: https://www.braveclojure.com/
- **Paredit Guide** (Emacs, but concepts apply): https://www.emacswiki.org/emacs/ParEdit
---
## Credits
- [nfnl](https://github.com/Olical/nfnl) - Fennel to Lua compiler for Neovim
- [Conjure](https://github.com/Olical/conjure) - Interactive REPL environment
- [nvim-paredit](https://github.com/julienvincent/nvim-paredit) - Structural editing
- [lazy.nvim](https://github.com/folke/lazy.nvim) - Plugin manager
- [tokyonight.nvim](https://github.com/folke/tokyonight.nvim) - Colorscheme