add :LispSchool
This commit is contained in:
@@ -3,3 +3,8 @@ undodir
|
|||||||
# Generated Lua files (compiled from Fennel by nfnl)
|
# Generated Lua files (compiled from Fennel by nfnl)
|
||||||
lua/config/
|
lua/config/
|
||||||
lua/plugins/
|
lua/plugins/
|
||||||
|
|
||||||
|
# Clojure/LSP tooling
|
||||||
|
.clj-kondo/
|
||||||
|
.lsp/
|
||||||
|
.nrepl-port
|
||||||
|
|||||||
@@ -35,6 +35,9 @@
|
|||||||
(keymap :n "<leader>bp" ":bprevious<CR>" {:desc "Previous buffer"})
|
(keymap :n "<leader>bp" ":bprevious<CR>" {:desc "Previous buffer"})
|
||||||
(keymap :n "<leader>bd" ":bdelete<CR>" {:desc "Delete buffer"})
|
(keymap :n "<leader>bd" ":bdelete<CR>" {:desc "Delete buffer"})
|
||||||
|
|
||||||
|
;; Copy to system clipboard
|
||||||
|
(keymap [:n :v] "<leader>y" "\"+y" {:desc "Yank to clipboard"})
|
||||||
|
|
||||||
;; Clear search highlight
|
;; Clear search highlight
|
||||||
(keymap :n "<Esc>" ":noh<CR>" {:desc "Clear search highlight"})
|
(keymap :n "<Esc>" ":noh<CR>" {:desc "Clear search highlight"})
|
||||||
|
|
||||||
@@ -136,4 +139,13 @@
|
|||||||
(fn [] (vim.cmd (.. "edit " (vim.lsp.get_log_path))))
|
(fn [] (vim.cmd (.. "edit " (vim.lsp.get_log_path))))
|
||||||
{:desc "Open LSP log file"})
|
{:desc "Open LSP log file"})
|
||||||
|
|
||||||
|
;; LispSchool - Interactive structural editing tutorial
|
||||||
|
(usercmd "LispSchool"
|
||||||
|
(fn [] (let [ls (require :lisp-school)] (ls.start)))
|
||||||
|
{:desc "Start LispSchool tutorial"})
|
||||||
|
|
||||||
|
(usercmd "LispSchoolNext"
|
||||||
|
(fn [] (let [ls (require :lisp-school)] (ls.next)))
|
||||||
|
{:desc "Next LispSchool lesson"})
|
||||||
|
|
||||||
{}
|
{}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
;; config/parinfer.fnl - Parinfer + vim-sexp insert mode coordination
|
||||||
|
;;
|
||||||
|
;; Single source of truth for whether parinfer is on/off by default
|
||||||
|
;; and what that means for vim-sexp's auto-insert bracket mappings.
|
||||||
|
;;
|
||||||
|
;; When parinfer is ON: it manages closing parens via indentation,
|
||||||
|
;; so vim-sexp auto-insert is disabled.
|
||||||
|
;; When parinfer is OFF: vim-sexp auto-insert is re-enabled so you
|
||||||
|
;; get closing brackets when typing openers.
|
||||||
|
|
||||||
|
;; ── Configuration ────────────────────────────────────────────────
|
||||||
|
;; Change this single flag to flip the default for all sexp filetypes.
|
||||||
|
|
||||||
|
(local default-enabled true)
|
||||||
|
|
||||||
|
;; ── Implementation ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
(local sexp-insert-keys ["(" ")" "[" "]" "{" "}" "\"" "<BS>"])
|
||||||
|
|
||||||
|
(fn enable-sexp-insert []
|
||||||
|
"Restore vim-sexp insert-mode bracket mappings in the current buffer."
|
||||||
|
(vim.cmd "imap <silent><buffer> ( <Plug>(sexp_insert_opening_round)")
|
||||||
|
(vim.cmd "imap <silent><buffer> ) <Plug>(sexp_insert_closing_round)")
|
||||||
|
(vim.cmd "imap <silent><buffer> [ <Plug>(sexp_insert_opening_square)")
|
||||||
|
(vim.cmd "imap <silent><buffer> ] <Plug>(sexp_insert_closing_square)")
|
||||||
|
(vim.cmd "imap <silent><buffer> { <Plug>(sexp_insert_opening_curly)")
|
||||||
|
(vim.cmd "imap <silent><buffer> } <Plug>(sexp_insert_closing_curly)")
|
||||||
|
(vim.cmd "imap <silent><buffer> \" <Plug>(sexp_insert_double_quote)")
|
||||||
|
(vim.cmd "imap <silent><buffer> <BS> <Plug>(sexp_insert_backspace)"))
|
||||||
|
|
||||||
|
(fn disable-sexp-insert []
|
||||||
|
"Remove vim-sexp insert-mode bracket mappings from the current buffer."
|
||||||
|
(each [_ key (ipairs sexp-insert-keys)]
|
||||||
|
(pcall vim.api.nvim_buf_del_keymap 0 "i" key)))
|
||||||
|
|
||||||
|
(fn toggle []
|
||||||
|
"Toggle parinfer in the current buffer and sync vim-sexp insert mappings."
|
||||||
|
(vim.cmd "ParinferToggle")
|
||||||
|
(let [on (= (vim.api.nvim_buf_get_var 0 "parinfer_enabled") 1)]
|
||||||
|
(if on
|
||||||
|
(disable-sexp-insert)
|
||||||
|
(enable-sexp-insert))))
|
||||||
|
|
||||||
|
{:default-enabled default-enabled
|
||||||
|
:toggle toggle}
|
||||||
@@ -0,0 +1,564 @@
|
|||||||
|
;; lisp-school.fnl - Interactive structural editing tutorial for vim-sexp
|
||||||
|
;; Compiled to lua/lisp-school.lua by nfnl
|
||||||
|
;;
|
||||||
|
;; Usage:
|
||||||
|
;; :LispSchool - Start (or restart) the tutorial
|
||||||
|
;; :LispSchoolNext - Advance to the next lesson
|
||||||
|
;; ]l - Buffer-local shortcut for :LispSchoolNext
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; State
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(var current-lesson 0)
|
||||||
|
(var buf nil)
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Helpers
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(fn ll-str []
|
||||||
|
"Return a display string for <localleader>."
|
||||||
|
(let [ll vim.g.maplocalleader]
|
||||||
|
(if (= ll " ") "<Space>"
|
||||||
|
(= ll nil) "\\"
|
||||||
|
ll)))
|
||||||
|
|
||||||
|
(fn leader-str []
|
||||||
|
"Return a display string for <leader>."
|
||||||
|
(let [l vim.g.mapleader]
|
||||||
|
(if (= l " ") "<Space>"
|
||||||
|
(= l nil) "\\"
|
||||||
|
l)))
|
||||||
|
|
||||||
|
(fn sep []
|
||||||
|
"Section separator line."
|
||||||
|
";; ─────────────────────────────────────────────────────────────────────────")
|
||||||
|
|
||||||
|
(fn buf-valid? []
|
||||||
|
"Check if our tutorial buffer still exists and is valid."
|
||||||
|
(and buf (vim.api.nvim_buf_is_valid buf)))
|
||||||
|
|
||||||
|
(fn append-lines [lines]
|
||||||
|
"Append lines to the tutorial buffer and scroll to them."
|
||||||
|
(when (buf-valid?)
|
||||||
|
(let [count (vim.api.nvim_buf_line_count buf)]
|
||||||
|
(vim.api.nvim_buf_set_lines buf count count false lines))
|
||||||
|
;; Move cursor to the first new line
|
||||||
|
(let [new-count (vim.api.nvim_buf_line_count buf)
|
||||||
|
first-new (- new-count (length lines))]
|
||||||
|
(vim.api.nvim_win_set_cursor 0 [(+ first-new 1) 0]))))
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Lessons
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(fn lesson-1 []
|
||||||
|
"Welcome - Thinking in Forms"
|
||||||
|
[(sep)
|
||||||
|
";;"
|
||||||
|
";; 🎓 Welcome to LispSchool!"
|
||||||
|
";; ========================="
|
||||||
|
";;"
|
||||||
|
";; This interactive tutorial teaches structural editing for Lisp code."
|
||||||
|
";;"
|
||||||
|
";; If you've written Java or C, you think in statements and lines."
|
||||||
|
";; In Lisp, we think in FORMS — nested parenthesized expressions."
|
||||||
|
";;"
|
||||||
|
";; Vocabulary:"
|
||||||
|
";; sexp = \"s-expression\", the formal name for Lisp's nested"
|
||||||
|
";; parenthesized syntax. (+ 1 2) is a sexp. So is (defn foo [x] x)."
|
||||||
|
";; You'll see this term a lot — it just means a balanced expression."
|
||||||
|
";; form = same thing as sexp, but the everyday Clojure word for it"
|
||||||
|
";; element = any single thing: a symbol, number, keyword, string, or a form"
|
||||||
|
";; atom = a non-list element: 42, :name, \"hello\", true"
|
||||||
|
";;"
|
||||||
|
";; The Neovim plugin that powers this tutorial is called vim-sexp"
|
||||||
|
";; (with tpope's vim-sexp-mappings-for-regular-people for sane keybindings)."
|
||||||
|
";;"
|
||||||
|
";; In Java: int x = foo(1, bar(2, 3));"
|
||||||
|
";; In Clojure: (def x (foo 1 (bar 2 3)))"
|
||||||
|
";;"
|
||||||
|
";; Every operation is a list. The first element is the operator."
|
||||||
|
";; Structure IS meaning. That's why we edit structure, not text."
|
||||||
|
";;"
|
||||||
|
";; What you'll learn:"
|
||||||
|
";; Lessons 2-3: Navigate — move through forms and elements"
|
||||||
|
";; Lessons 4-6: Edit — slurp, barf, wrap, splice, swap"
|
||||||
|
";; Lesson 7: Insert — wrapping with insert mode"
|
||||||
|
";; Lesson 8: Flow — parinfer + quick reference"
|
||||||
|
";;"
|
||||||
|
";; Advance to the next lesson with ]l or :LispSchoolNext"
|
||||||
|
";; Use u (undo) to reset after practicing."
|
||||||
|
";; Restart anytime with :LispSchool"
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""
|
||||||
|
";; Here's your first form. Place your cursor on it and just look."
|
||||||
|
";; Notice how everything is nested lists — forms inside forms."
|
||||||
|
""
|
||||||
|
"(defn greet [name]"
|
||||||
|
" (str \"Hello, \" name \"!\"))"
|
||||||
|
""
|
||||||
|
"(defn add [a b]"
|
||||||
|
" (+ a b))"
|
||||||
|
""
|
||||||
|
"(println (greet \"world\"))"
|
||||||
|
"(println (add 2 3))"
|
||||||
|
""])
|
||||||
|
|
||||||
|
(fn lesson-2 []
|
||||||
|
"Bracket Navigation & Top-Level Movement"
|
||||||
|
[(sep)
|
||||||
|
";;"
|
||||||
|
";; Lesson 2: Bracket Navigation & Top-Level Movement"
|
||||||
|
";; ================================================="
|
||||||
|
";;"
|
||||||
|
";; BRACKET JUMPS — find the edges of forms:"
|
||||||
|
";; ( jump to nearest opening paren/bracket (backward)"
|
||||||
|
";; ) jump to nearest closing paren/bracket (forward)"
|
||||||
|
";;"
|
||||||
|
";; These work like % in normal Vim but are sexp-aware."
|
||||||
|
";; They jump to the nearest enclosing bracket, not just the matching one."
|
||||||
|
";;"
|
||||||
|
";; TOP-LEVEL JUMPS — move between defn/def/ns forms:"
|
||||||
|
";; [[ jump to previous top-level form"
|
||||||
|
";; ]] jump to next top-level form"
|
||||||
|
";;"
|
||||||
|
";; Think of [[ and ]] like jumping between function definitions in C."
|
||||||
|
";;"
|
||||||
|
";; ✏️ Practice: Place your cursor inside the (+ a b) below."
|
||||||
|
";; Press ( to jump to the opening paren."
|
||||||
|
";; Press ) to jump to the closing paren."
|
||||||
|
";; Press [[ and ]] to jump between the three defns."
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""
|
||||||
|
"(defn first-fn [x]"
|
||||||
|
" (+ x 1))"
|
||||||
|
""
|
||||||
|
"(defn second-fn [a b]"
|
||||||
|
" (* (+ a b)"
|
||||||
|
" (- a b)))"
|
||||||
|
""
|
||||||
|
"(defn third-fn [items]"
|
||||||
|
" (map inc (filter even? items)))"
|
||||||
|
""])
|
||||||
|
|
||||||
|
(fn lesson-3 []
|
||||||
|
"Element Motions & Text Objects"
|
||||||
|
[(sep)
|
||||||
|
";;"
|
||||||
|
";; Lesson 3: Element Motions & Text Objects"
|
||||||
|
";; ========================================="
|
||||||
|
";;"
|
||||||
|
";; ELEMENT MOTIONS — move by element instead of by word:"
|
||||||
|
";; W move to next element (replaces WORD motion in sexp buffers)"
|
||||||
|
";; B move to previous element"
|
||||||
|
";; E move to end of element"
|
||||||
|
";; gE move to end of previous element"
|
||||||
|
";;"
|
||||||
|
";; In Java, 'word' makes sense. In Lisp, 'element' is the unit."
|
||||||
|
";; W treats (foo bar) as ONE element, not two words."
|
||||||
|
";;"
|
||||||
|
";; OPERATORS — the verbs that act on text objects:"
|
||||||
|
";; d delete (cut)"
|
||||||
|
";; c change (delete + enter insert mode)"
|
||||||
|
";; y yank (copy)"
|
||||||
|
";; v visual select (highlight for further action)"
|
||||||
|
";;"
|
||||||
|
";; TEXT OBJECTS — structural units you combine with operators:"
|
||||||
|
";; af around form (the parens + everything inside)"
|
||||||
|
";; if in form (everything inside, not the parens)"
|
||||||
|
";; aF around top-level form"
|
||||||
|
";; iF in top-level form"
|
||||||
|
";; ae around element (one element, including surrounding whitespace)"
|
||||||
|
";; ie in element (one element, no surrounding whitespace)"
|
||||||
|
";;"
|
||||||
|
";; ✏️ Practice:"
|
||||||
|
";; 1. Place cursor on 'inc' below. Press W to hop element-by-element."
|
||||||
|
";; 2. Put cursor inside (filter even? items). Press daf to delete the form."
|
||||||
|
";; 3. Undo with u. Put cursor on 'even?' and press die to delete just it."
|
||||||
|
";; 4. Undo with u. Put cursor anywhere in second-fn. Press daF to delete"
|
||||||
|
";; the entire top-level form."
|
||||||
|
";; 5. Undo with u. Try vif to visually select the inside of a form."
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""
|
||||||
|
"(defn first-fn [x y]"
|
||||||
|
" (+ x y 100))"
|
||||||
|
""
|
||||||
|
"(defn second-fn [items]"
|
||||||
|
" (map inc (filter even? items)))"
|
||||||
|
""
|
||||||
|
"(defn third-fn [a b c]"
|
||||||
|
" (println a b c))"
|
||||||
|
""])
|
||||||
|
|
||||||
|
(fn lesson-4 []
|
||||||
|
"Slurp & Barf (Growing and Shrinking Forms)"
|
||||||
|
[(sep)
|
||||||
|
";;"
|
||||||
|
";; Lesson 4: Slurp & Barf"
|
||||||
|
";; ======================="
|
||||||
|
";;"
|
||||||
|
";; These are the bread and butter of structural editing."
|
||||||
|
";; They grow or shrink a form by moving its brackets."
|
||||||
|
";;"
|
||||||
|
";; >) SLURP FORWARD — pull next sibling INTO the form"
|
||||||
|
";; The ) moves right, swallowing the next element."
|
||||||
|
";;"
|
||||||
|
";; <) BARF FORWARD — push last child OUT of the form"
|
||||||
|
";; The ) moves left, spitting out the last element."
|
||||||
|
";;"
|
||||||
|
";; <( SLURP BACKWARD — pull prev sibling INTO the form"
|
||||||
|
";; The ( moves left, swallowing the previous element."
|
||||||
|
";;"
|
||||||
|
";; >( BARF BACKWARD — push first child OUT of the form"
|
||||||
|
";; The ( moves right, spitting out the first element."
|
||||||
|
";;"
|
||||||
|
";; Mnemonic: the ARROW shows which way the bracket moves."
|
||||||
|
";; the PAREN shows which end of the form."
|
||||||
|
";;"
|
||||||
|
";; >) → the ) moves → (slurp from the right)"
|
||||||
|
";; <) ← the ) moves ← (barf from the right)"
|
||||||
|
";; <( ← the ( moves ← (slurp from the left)"
|
||||||
|
";; >( → the ( moves → (barf from the left)"
|
||||||
|
";;"
|
||||||
|
";; ✏️ Practice:"
|
||||||
|
";; 1. Put cursor inside (+ a) below. Press >) — watch b get slurped in."
|
||||||
|
";; Result: (+ a b) c → you're growing the form."
|
||||||
|
";; 2. Undo with u. Now press <) to barf a out: (+) a b c"
|
||||||
|
";; 3. Undo. Try <( and >( on the same form."
|
||||||
|
";; 4. Try slurping (* 1) to capture 2 and then 3."
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""
|
||||||
|
";; Slurp/barf playground"
|
||||||
|
"(+ a) b c"
|
||||||
|
""
|
||||||
|
"(* 1) 2 3"
|
||||||
|
""
|
||||||
|
";; Real-world example: build a nested call with slurp"
|
||||||
|
";; Goal: turn this: (println) (str \"hi \") name"
|
||||||
|
";; Into this: (println (str \"hi \" name))"
|
||||||
|
";; Steps: 1. cursor in (str \"hi \"), press >) to slurp name"
|
||||||
|
";; 2. cursor in (println), press >) to slurp (str \"hi \" name)"
|
||||||
|
"(println) (str \"hi \") name"
|
||||||
|
""])
|
||||||
|
|
||||||
|
(fn lesson-5 []
|
||||||
|
"Moving Elements & Forms"
|
||||||
|
[(sep)
|
||||||
|
";;"
|
||||||
|
";; Lesson 5: Moving Elements & Forms"
|
||||||
|
";; ==================================="
|
||||||
|
";;"
|
||||||
|
";; SWAP ELEMENTS — reorder siblings within a form:"
|
||||||
|
";; >e swap element to the right"
|
||||||
|
";; <e swap element to the left"
|
||||||
|
";;"
|
||||||
|
";; Think of these like \"move line up/down\" but for structural units."
|
||||||
|
";; In Java, you'd cut-paste a line. In Lisp, you swap elements."
|
||||||
|
";;"
|
||||||
|
";; ✏️ Practice:"
|
||||||
|
";; 1. Put cursor on 'b' in (foo a b c) below. Press <e to swap it left."
|
||||||
|
";; Result: (foo b a c) → (foo a b c) Wait, that's: b moves left."
|
||||||
|
";; Actually: cursor on b, <e → (foo b a c). Try >e to move it right."
|
||||||
|
";; 2. Reorder the function arguments to be (process c a b)."
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""
|
||||||
|
";; Swap elements"
|
||||||
|
"(foo a b c)"
|
||||||
|
""
|
||||||
|
";; Reorder arguments"
|
||||||
|
"(process a b c)"
|
||||||
|
""])
|
||||||
|
|
||||||
|
(fn lesson-6 []
|
||||||
|
"Wrapping & Splicing"
|
||||||
|
(let [ll (ll-str)]
|
||||||
|
[(sep)
|
||||||
|
";;"
|
||||||
|
";; Lesson 6: Wrapping & Splicing"
|
||||||
|
";; ==============================="
|
||||||
|
";;"
|
||||||
|
";; SIMPLE WRAP — wrap + insert in one step:"
|
||||||
|
(.. ";; " ll "w wrap ELEMENT in () and insert at head")
|
||||||
|
(.. ";; " ll "W wrap ELEMENT in () and insert at tail")
|
||||||
|
";;"
|
||||||
|
";; WRAP ELEMENT — surround an element with brackets (normal mode):"
|
||||||
|
";; cseb wrap element in () (mnemonic: change surround element, bracket)"
|
||||||
|
";; cse( wrap element in () (same as cseb)"
|
||||||
|
";; cse) wrap element in () (same as cseb)"
|
||||||
|
";; cse[ wrap element in []"
|
||||||
|
";; cse] wrap element in []"
|
||||||
|
";; cse{ wrap element in {}"
|
||||||
|
";; cse} wrap element in {}"
|
||||||
|
";;"
|
||||||
|
";; SPLICE — remove surrounding form, keep contents:"
|
||||||
|
";; dsf delete surrounding form (splice)"
|
||||||
|
";;"
|
||||||
|
";; Wrap is like adding a function call around something."
|
||||||
|
";; Splice is the opposite — removing a layer of nesting."
|
||||||
|
";;"
|
||||||
|
";; In Java terms:"
|
||||||
|
";; Wrap: x → foo(x) (add a function call)"
|
||||||
|
";; Splice: foo(x) → x (remove a function call)"
|
||||||
|
";;"
|
||||||
|
";; ✏️ Practice:"
|
||||||
|
(.. ";; 1. Put cursor on 'x' below. Press " ll "w and type 'inc '")
|
||||||
|
";; then Escape. You just wrapped x into (inc x). Undo with u."
|
||||||
|
";; 2. Put cursor on 'x' again. Press cseb to wrap it: (x)"
|
||||||
|
";; Undo with u."
|
||||||
|
";; 3. Put cursor on 'items' and press cse[ to wrap it: [items]"
|
||||||
|
";; Undo with u."
|
||||||
|
";; 4. Put cursor inside (inc x) and press dsf to splice."
|
||||||
|
";; Result: the (inc x) becomes just inc x"
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""
|
||||||
|
";; Wrapping playground"
|
||||||
|
"(def result x)"
|
||||||
|
""
|
||||||
|
"(def items (range 10))"
|
||||||
|
""
|
||||||
|
";; Splicing: remove the inner (inc x) wrapper"
|
||||||
|
"(defn foo [x]"
|
||||||
|
" (println (inc x)))"
|
||||||
|
""]))
|
||||||
|
|
||||||
|
(fn lesson-7 []
|
||||||
|
"Inserting, Wrapping Forms & Raise"
|
||||||
|
(let [ll (ll-str)]
|
||||||
|
[(sep)
|
||||||
|
";;"
|
||||||
|
";; Lesson 7: Inserting, Wrapping Forms & Raise"
|
||||||
|
";; ============================================="
|
||||||
|
";;"
|
||||||
|
";; INSERT AT FORM EDGES (tpope mappings):"
|
||||||
|
";; <I insert at the HEAD of the enclosing form (after opening paren)"
|
||||||
|
";; >I insert at the TAIL of the enclosing form (before closing paren)"
|
||||||
|
";;"
|
||||||
|
";; These are incredibly useful. <I jumps you to right after ( and enters"
|
||||||
|
";; insert mode. >I jumps to right before ) and enters insert mode."
|
||||||
|
";;"
|
||||||
|
(.. ";; WRAP FORM + INSERT (vim-sexp " ll " mappings):")
|
||||||
|
(.. ";; " ll "i wrap enclosing FORM in () and insert at head")
|
||||||
|
(.. ";; " ll "I wrap enclosing FORM in () and insert at tail")
|
||||||
|
";;"
|
||||||
|
(.. ";; " ll "[ wrap FORM in [] and insert at head")
|
||||||
|
(.. ";; " ll "] wrap FORM in [] and insert at tail")
|
||||||
|
(.. ";; " ll "{ wrap FORM in {} and insert at head")
|
||||||
|
(.. ";; " ll "} wrap FORM in {} and insert at tail")
|
||||||
|
";;"
|
||||||
|
";; RAISE — replace parent with child:"
|
||||||
|
(.. ";; " ll "o raise FORM (replace parent form with this form)")
|
||||||
|
(.. ";; " ll "O raise ELEMENT (replace parent form with this element)")
|
||||||
|
";;"
|
||||||
|
";; ✏️ Practice:"
|
||||||
|
";; 1. Put cursor inside (+ a b) below. Press <I to insert at head."
|
||||||
|
";; Type 'my-add ' then press Escape. You've renamed the function!"
|
||||||
|
";; Undo with u."
|
||||||
|
";; 2. Put cursor inside (+ a b). Press >I to insert at tail."
|
||||||
|
";; Type ' c' then Escape. You added an argument!"
|
||||||
|
";; Undo with u."
|
||||||
|
(.. ";; 3. Put cursor inside (inc x). Press " ll "o to raise it,")
|
||||||
|
";; replacing the (+ (inc x) y) with just (inc x)."
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""
|
||||||
|
";; Insert at edges"
|
||||||
|
"(+ a b)"
|
||||||
|
""
|
||||||
|
";; Raise"
|
||||||
|
"(+ (inc x) y)"
|
||||||
|
""
|
||||||
|
";; Build a threading macro: start with (process data)"
|
||||||
|
";; and wrap it step by step"
|
||||||
|
"(process data)"
|
||||||
|
""]))
|
||||||
|
|
||||||
|
(fn lesson-8 []
|
||||||
|
"Parinfer & Quick Reference"
|
||||||
|
(let [ll (ll-str)
|
||||||
|
ld (leader-str)
|
||||||
|
;; Build a reference card row: pads key+desc to exactly 66 chars between ║ markers
|
||||||
|
ref (fn [key desc]
|
||||||
|
(let [key-area (.. " " key)
|
||||||
|
gap (string.rep " " (math.max 4 (- 20 (length key-area))))
|
||||||
|
line (.. key-area gap desc)
|
||||||
|
pad (string.rep " " (math.max 0 (- 66 (length line))))]
|
||||||
|
(.. ";; ║" line pad "║")))]
|
||||||
|
[(sep)
|
||||||
|
";;"
|
||||||
|
";; Lesson 8: Parinfer & Quick Reference"
|
||||||
|
";; ======================================"
|
||||||
|
";;"
|
||||||
|
";; PARINFER — let indentation drive structure"
|
||||||
|
";;"
|
||||||
|
";; Parinfer automatically manages closing parens based on indentation."
|
||||||
|
";; Instead of manually balancing parens, you indent/dedent lines and"
|
||||||
|
";; parinfer moves the closing parens for you."
|
||||||
|
";;"
|
||||||
|
(.. ";; Toggle: " ld "tpi or :ParinferToggle")
|
||||||
|
";;"
|
||||||
|
";; When to use what:"
|
||||||
|
";; vim-sexp → explicit structural commands (slurp, barf, wrap, etc.)"
|
||||||
|
";; parinfer → casual editing, quick indentation-based restructuring"
|
||||||
|
";;"
|
||||||
|
";; They work great together: parinfer keeps parens balanced while you"
|
||||||
|
";; edit normally, and vim-sexp gives you precise structural control."
|
||||||
|
";;"
|
||||||
|
";; ✏️ Practice: Restructure a let binding with parinfer"
|
||||||
|
";;"
|
||||||
|
(.. ";; 1. Make sure parinfer is on (" ld "tpi to toggle).")
|
||||||
|
";;"
|
||||||
|
";; 2. Put cursor on the (+ a b c) line. Press << to dedent it."
|
||||||
|
";; The closing )] jumps up to the c line — parinfer moved it"
|
||||||
|
";; because (+ a b c) is no longer indented inside the let."
|
||||||
|
";; (let [a 1"
|
||||||
|
";; b 2"
|
||||||
|
";; c 3])"
|
||||||
|
";; (+ a b c)"
|
||||||
|
";;"
|
||||||
|
";; 3. Now go to the b 2 line. Press fb to jump to b, then"
|
||||||
|
";; i to enter insert mode. Type ( and press Escape."
|
||||||
|
";; Parinfer adds a closing ) at the end of the line:"
|
||||||
|
";; (let [a 1"
|
||||||
|
";; (b 2)"
|
||||||
|
";; c 3])"
|
||||||
|
";; (+ a b c)"
|
||||||
|
";;"
|
||||||
|
";; 4. Press f2 to jump to 2, then i to enter insert mode."
|
||||||
|
";; Type ) and press Escape. This closes the paren before 2:"
|
||||||
|
";; (let [a 1"
|
||||||
|
";; (b) 2"
|
||||||
|
";; c 3])"
|
||||||
|
";; (+ a b c)"
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""
|
||||||
|
";; Parinfer playground"
|
||||||
|
"(let [a 1"
|
||||||
|
" b 2"
|
||||||
|
" c 3]"
|
||||||
|
" (+ a b c))"
|
||||||
|
""
|
||||||
|
(sep)
|
||||||
|
";;"
|
||||||
|
";; ╔══════════════════════════════════════════════════════════════════╗"
|
||||||
|
";; ║ QUICK REFERENCE CARD ║"
|
||||||
|
";; ╠══════════════════════════════════════════════════════════════════╣"
|
||||||
|
";; ║ ║"
|
||||||
|
";; ║ NAVIGATION ║"
|
||||||
|
(ref "( / )" "jump to opening / closing bracket")
|
||||||
|
(ref "[[ / ]]" "prev / next top-level form")
|
||||||
|
(ref "W B E gE" "move by element (next, prev, end, prev-end)")
|
||||||
|
";; ║ ║"
|
||||||
|
";; ║ TEXT OBJECTS ║"
|
||||||
|
(ref "af / if" "around / in form")
|
||||||
|
(ref "aF / iF" "around / in top-level form")
|
||||||
|
(ref "ae / ie" "around / in element")
|
||||||
|
";; ║ ║"
|
||||||
|
";; ║ SLURP & BARF ║"
|
||||||
|
(ref ">)" "slurp forward (pull next elem in)")
|
||||||
|
(ref "<)" "barf forward (push last elem out)")
|
||||||
|
(ref "<(" "slurp backward (pull prev elem in)")
|
||||||
|
(ref ">(" "barf backward (push first elem out)")
|
||||||
|
";; ║ ║"
|
||||||
|
";; ║ SWAP ║"
|
||||||
|
(ref ">e / <e" "swap element right / left")
|
||||||
|
(ref ">f / <f" "swap form right / left")
|
||||||
|
";; ║ ║"
|
||||||
|
";; ║ WRAP & SPLICE ║"
|
||||||
|
(ref "cseb / cse(" "wrap element in ()")
|
||||||
|
(ref "cse[ / cse{" "wrap element in [] / {}")
|
||||||
|
(ref "dsf" "splice (delete surrounding form)")
|
||||||
|
";; ║ ║"
|
||||||
|
";; ║ INSERT ║"
|
||||||
|
(ref "<I / >I" "insert at form head / tail")
|
||||||
|
(ref (.. ll "w / " ll "W") "wrap element + insert head / tail")
|
||||||
|
(ref (.. ll "i / " ll "I") "wrap form + insert head / tail")
|
||||||
|
(ref (.. ll "o / " ll "O") "raise form / element")
|
||||||
|
";; ║ ║"
|
||||||
|
";; ║ PARINFER ║"
|
||||||
|
(ref (.. ld "tpi") "toggle parinfer")
|
||||||
|
";; ║ ║"
|
||||||
|
";; ╚══════════════════════════════════════════════════════════════════╝"
|
||||||
|
";;"
|
||||||
|
";; 🎉 Congratulations! You've completed LispSchool!"
|
||||||
|
";;"
|
||||||
|
";; Structural editing will feel awkward at first — that's normal."
|
||||||
|
";; Start with just ( ) for navigation and >) <) for slurp/barf."
|
||||||
|
";; Add more commands to your muscle memory over time."
|
||||||
|
";;"
|
||||||
|
";; Run :LispSchool anytime to review."
|
||||||
|
";;"
|
||||||
|
(sep)
|
||||||
|
""]))
|
||||||
|
|
||||||
|
;; Ordered list of lesson functions
|
||||||
|
(local lessons [lesson-1 lesson-2 lesson-3 lesson-4
|
||||||
|
lesson-5 lesson-6 lesson-7 lesson-8])
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Buffer management
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(fn create-buffer []
|
||||||
|
"Create the lisp-school.clj scratch buffer and switch to it."
|
||||||
|
(set buf (vim.api.nvim_create_buf true true))
|
||||||
|
(vim.api.nvim_buf_set_name buf "lisp-school.clj")
|
||||||
|
(vim.api.nvim_buf_set_option buf :buftype "nofile")
|
||||||
|
(vim.api.nvim_buf_set_option buf :swapfile false)
|
||||||
|
(vim.api.nvim_buf_set_option buf :filetype "clojure")
|
||||||
|
(vim.api.nvim_set_current_buf buf)
|
||||||
|
;; Buffer-local keymap: ]l to advance
|
||||||
|
(vim.api.nvim_buf_set_keymap buf :n "]l" ":LispSchoolNext<CR>"
|
||||||
|
{:noremap true :silent true :desc "Next LispSchool lesson"}))
|
||||||
|
|
||||||
|
(fn find-existing-buffer []
|
||||||
|
"Find an existing lisp-school.clj buffer, or nil."
|
||||||
|
(var found nil)
|
||||||
|
(each [_ b (ipairs (vim.api.nvim_list_bufs))]
|
||||||
|
(when (and (vim.api.nvim_buf_is_valid b)
|
||||||
|
(let [name (vim.api.nvim_buf_get_name b)]
|
||||||
|
(string.find name "lisp%-school%.clj$")))
|
||||||
|
(set found b)))
|
||||||
|
found)
|
||||||
|
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
;; Public API
|
||||||
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(fn start []
|
||||||
|
"Start or restart LispSchool."
|
||||||
|
;; Clean up existing buffer if any
|
||||||
|
(let [existing (find-existing-buffer)]
|
||||||
|
(when existing
|
||||||
|
(pcall vim.api.nvim_buf_delete existing {:force true})))
|
||||||
|
(set current-lesson 0)
|
||||||
|
(set buf nil)
|
||||||
|
(create-buffer)
|
||||||
|
;; Append lesson 1
|
||||||
|
(set current-lesson 1)
|
||||||
|
(let [lesson-fn (. lessons current-lesson)]
|
||||||
|
(append-lines (lesson-fn)))
|
||||||
|
;; Scroll to top
|
||||||
|
(vim.api.nvim_win_set_cursor 0 [1 0]))
|
||||||
|
|
||||||
|
(fn next-lesson []
|
||||||
|
"Advance to the next lesson."
|
||||||
|
(if (not (buf-valid?))
|
||||||
|
(vim.notify "Run :LispSchool first to start the tutorial." vim.log.levels.WARN)
|
||||||
|
(>= current-lesson (length lessons))
|
||||||
|
(vim.notify "You've completed all lessons! Run :LispSchool to restart." vim.log.levels.INFO)
|
||||||
|
(do
|
||||||
|
(set current-lesson (+ current-lesson 1))
|
||||||
|
(let [lesson-fn (. lessons current-lesson)]
|
||||||
|
(append-lines (lesson-fn))))))
|
||||||
|
|
||||||
|
{:start start
|
||||||
|
:next next-lesson}
|
||||||
+33
-181
@@ -25,199 +25,51 @@
|
|||||||
(set vim.g.conjure#log#hud#enabled true))}
|
(set vim.g.conjure#log#hud#enabled true))}
|
||||||
|
|
||||||
;; nvim-parinfer - Automatic parenthesis balancing
|
;; nvim-parinfer - Automatic parenthesis balancing
|
||||||
;; Works alongside paredit: parinfer handles passive balancing,
|
;; See fnl/config/parinfer.fnl for default-enabled flag and toggle logic
|
||||||
;; paredit provides explicit structural commands
|
|
||||||
{repo "gpanders/nvim-parinfer"
|
{repo "gpanders/nvim-parinfer"
|
||||||
:ft ["fennel" "clojure" "lisp" "scheme" "racket" "carp" "timl"]
|
:ft ["fennel" "clojure" "lisp" "scheme" "racket" "carp" "timl"]
|
||||||
|
:init (fn []
|
||||||
|
(let [par (require :config.parinfer)]
|
||||||
|
(set vim.g.parinfer_enabled par.default-enabled)))
|
||||||
:keys [{lhs "<leader>tpi"
|
:keys [{lhs "<leader>tpi"
|
||||||
rhs "<cmd>ParinferToggle<CR>"
|
rhs (fn [] (let [par (require :config.parinfer)] (par.toggle)))
|
||||||
:desc "Toggle Parinfer"}]}
|
:desc "Toggle Parinfer"}]}
|
||||||
|
|
||||||
;; nvim-paredit - Structural editing for Lisp
|
;; vim-sexp - Structural editing for S-expressions
|
||||||
;; Configured with vim-sexp + vim-sexp-mappings-for-regular-people compatible bindings
|
;; with tpope's vim-sexp-mappings-for-regular-people
|
||||||
;;
|
{repo "guns/vim-sexp"
|
||||||
;; Default paredit bindings (from nvim-paredit):
|
|
||||||
;; >)/<) slurp/barf forwards <(/>( slurp/barf backwards
|
|
||||||
;; >e/<e drag element >f/<f drag form
|
|
||||||
;; >p/<p drag pairs (/) parent form start/end
|
|
||||||
;; af/if around/in form aF/iF around/in top-level form
|
|
||||||
;; ae/ie around/in element <localleader>@ splice
|
|
||||||
;; <localleader>o/O raise form/element
|
|
||||||
;;
|
|
||||||
;; Additional bindings added below for vim-sexp compatibility
|
|
||||||
{repo "julienvincent/nvim-paredit"
|
|
||||||
:ft ["fennel" "clojure" "lisp" "scheme" "racket"]
|
:ft ["fennel" "clojure" "lisp" "scheme" "racket"]
|
||||||
:config (fn []
|
:dependencies ["tpope/vim-repeat"
|
||||||
(local paredit (require :nvim-paredit))
|
"tpope/vim-sexp-mappings-for-regular-people"]
|
||||||
(local api paredit.api)
|
:init (fn []
|
||||||
(local wrap paredit.wrap)
|
(set vim.g.sexp_filetypes "clojure,scheme,lisp,timl,fennel,racket")
|
||||||
(local cursor paredit.cursor)
|
;; Sync sexp auto-insert with parinfer default
|
||||||
(local keymap vim.keymap.set)
|
(let [par (require :config.parinfer)]
|
||||||
|
(set vim.g.sexp_enable_insert_mode_mappings
|
||||||
;; Use default keybindings
|
(if par.default-enabled 0 1))))}
|
||||||
(paredit.setup {})
|
|
||||||
|
|
||||||
;; ============================================================
|
|
||||||
;; vim-sexp-mappings-for-regular-people (tpope) style bindings
|
|
||||||
;; ============================================================
|
|
||||||
|
|
||||||
;; dsf - Splice (delete surrounding form) - alias for <localleader>@
|
|
||||||
(keymap :n "dsf" api.unwrap_form_under_cursor {:desc "Splice (delete surrounding form)"})
|
|
||||||
|
|
||||||
;; cse* - Surround element (no insert mode, surround.vim style)
|
|
||||||
(keymap :n "cseb" #(api.wrap_element_under_cursor "(" ")") {:desc "Wrap element in ()"})
|
|
||||||
(keymap :n "cse(" #(api.wrap_element_under_cursor "(" ")") {:desc "Wrap element in ()"})
|
|
||||||
(keymap :n "cse)" #(api.wrap_element_under_cursor "(" ")") {:desc "Wrap element in ()"})
|
|
||||||
(keymap :n "cse[" #(api.wrap_element_under_cursor "[" "]") {:desc "Wrap element in []"})
|
|
||||||
(keymap :n "cse]" #(api.wrap_element_under_cursor "[" "]") {:desc "Wrap element in []"})
|
|
||||||
(keymap :n "cse{" #(api.wrap_element_under_cursor "{" "}") {:desc "Wrap element in {}"})
|
|
||||||
(keymap :n "cse}" #(api.wrap_element_under_cursor "{" "}") {:desc "Wrap element in {}"})
|
|
||||||
|
|
||||||
;; <I / >I - Insert at form head/tail (tpope style)
|
|
||||||
(keymap :n "<I"
|
|
||||||
(fn []
|
|
||||||
(api.move_to_parent_form_start)
|
|
||||||
(vim.cmd "normal! l")
|
|
||||||
(vim.cmd "startinsert"))
|
|
||||||
{:desc "Insert at form head"})
|
|
||||||
(keymap :n ">I"
|
|
||||||
(fn []
|
|
||||||
(api.move_to_parent_form_end)
|
|
||||||
(vim.cmd "startinsert"))
|
|
||||||
{:desc "Insert at form tail"})
|
|
||||||
|
|
||||||
;; W/B/E/gE - Element-wise motions (override WORD motions)
|
|
||||||
(each [_ mode (ipairs [:n :x :o])]
|
|
||||||
(keymap mode "W" api.move_to_next_element_head {:desc "Next element head"})
|
|
||||||
(keymap mode "B" api.move_to_prev_element_head {:desc "Previous element head"})
|
|
||||||
(keymap mode "E" api.move_to_next_element_tail {:desc "Next element tail"})
|
|
||||||
(keymap mode "gE" api.move_to_prev_element_tail {:desc "Previous element tail"}))
|
|
||||||
|
|
||||||
;; ============================================================
|
|
||||||
;; vim-sexp (guns) style LocalLeader bindings
|
|
||||||
;; ============================================================
|
|
||||||
|
|
||||||
;; <localleader>w/W - Wrap element + insert at head/tail
|
|
||||||
(keymap :n "<localleader>w"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_element_under_cursor "( " ")")
|
|
||||||
{:placement "inner_start" :mode "insert"}))
|
|
||||||
{:desc "Wrap element, insert head"})
|
|
||||||
(keymap :n "<localleader>W"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_element_under_cursor "(" ")")
|
|
||||||
{:placement "inner_end" :mode "insert"}))
|
|
||||||
{:desc "Wrap element, insert tail"})
|
|
||||||
|
|
||||||
;; <localleader>i/I - Wrap form + insert at head/tail
|
|
||||||
(keymap :n "<localleader>i"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_enclosing_form_under_cursor "( " ")")
|
|
||||||
{:placement "inner_start" :mode "insert"}))
|
|
||||||
{:desc "Wrap form, insert head"})
|
|
||||||
(keymap :n "<localleader>I"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_enclosing_form_under_cursor "(" ")")
|
|
||||||
{:placement "inner_end" :mode "insert"}))
|
|
||||||
{:desc "Wrap form, insert tail"})
|
|
||||||
|
|
||||||
;; <localleader>[ ] { } - Wrap form in brackets/braces + insert
|
|
||||||
(keymap :n "<localleader>["
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_enclosing_form_under_cursor "[ " "]")
|
|
||||||
{:placement "inner_start" :mode "insert"}))
|
|
||||||
{:desc "Wrap form in [], insert head"})
|
|
||||||
(keymap :n "<localleader>]"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_enclosing_form_under_cursor "[" "]")
|
|
||||||
{:placement "inner_end" :mode "insert"}))
|
|
||||||
{:desc "Wrap form in [], insert tail"})
|
|
||||||
(keymap :n "<localleader>{"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_enclosing_form_under_cursor "{ " "}")
|
|
||||||
{:placement "inner_start" :mode "insert"}))
|
|
||||||
{:desc "Wrap form in {}, insert head"})
|
|
||||||
(keymap :n "<localleader>}"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_enclosing_form_under_cursor "{" "}")
|
|
||||||
{:placement "inner_end" :mode "insert"}))
|
|
||||||
{:desc "Wrap form in {}, insert tail"})
|
|
||||||
|
|
||||||
;; <localleader>e[ e] e{ e} - Wrap element in brackets/braces + insert
|
|
||||||
(keymap :n "<localleader>e["
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_element_under_cursor "[ " "]")
|
|
||||||
{:placement "inner_start" :mode "insert"}))
|
|
||||||
{:desc "Wrap element in [], insert head"})
|
|
||||||
(keymap :n "<localleader>e]"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_element_under_cursor "[" "]")
|
|
||||||
{:placement "inner_end" :mode "insert"}))
|
|
||||||
{:desc "Wrap element in [], insert tail"})
|
|
||||||
(keymap :n "<localleader>e{"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_element_under_cursor "{ " "}")
|
|
||||||
{:placement "inner_start" :mode "insert"}))
|
|
||||||
{:desc "Wrap element in {}, insert head"})
|
|
||||||
(keymap :n "<localleader>e}"
|
|
||||||
(fn []
|
|
||||||
(cursor.place_cursor
|
|
||||||
(wrap.wrap_element_under_cursor "{" "}")
|
|
||||||
{:placement "inner_end" :mode "insert"}))
|
|
||||||
{:desc "Wrap element in {}, insert tail"})
|
|
||||||
|
|
||||||
;; <localleader>h/l - Insert at list head/tail (vim-sexp originals)
|
|
||||||
;; Same as <I/>I but with localleader
|
|
||||||
(keymap :n "<localleader>h"
|
|
||||||
(fn []
|
|
||||||
(api.move_to_parent_form_start)
|
|
||||||
(vim.cmd "normal! l")
|
|
||||||
(vim.cmd "startinsert"))
|
|
||||||
{:desc "Insert at list head"})
|
|
||||||
(keymap :n "<localleader>l"
|
|
||||||
(fn []
|
|
||||||
(api.move_to_parent_form_end)
|
|
||||||
(vim.cmd "startinsert"))
|
|
||||||
{:desc "Insert at list tail"})
|
|
||||||
|
|
||||||
;; [[ / ]] - Move to prev/next top-level form
|
|
||||||
(each [_ mode (ipairs [:n :x :o])]
|
|
||||||
(keymap mode "]]"
|
|
||||||
(fn []
|
|
||||||
;; Go to current top-level, then find next
|
|
||||||
(api.move_to_parent_form_end)
|
|
||||||
(api.move_to_next_element_head))
|
|
||||||
{:desc "Next top-level form"})
|
|
||||||
(keymap mode "[["
|
|
||||||
(fn []
|
|
||||||
;; Go to current top-level start, then find prev
|
|
||||||
(api.move_to_parent_form_start)
|
|
||||||
(api.move_to_prev_element_head))
|
|
||||||
{:desc "Previous top-level form"})))}
|
|
||||||
|
|
||||||
;; Clojure-Typst - Syntax highlighting for #t"" Typst literals in Clojure
|
|
||||||
;; Injects Typst highlighting into tagged literals, ~() switches back to Clojure
|
|
||||||
{:dir "/home/ajet/repos/clojure-typst/editors/nvim"
|
|
||||||
:ft ["clojure"]}
|
|
||||||
|
|
||||||
;; Mason - Package manager for LSP servers, DAP servers, linters, formatters
|
;; Mason - Package manager for LSP servers, DAP servers, linters, formatters
|
||||||
;; Run :MasonInstall clojure_lsp lua_ls to install servers
|
|
||||||
{repo "williamboman/mason.nvim"
|
{repo "williamboman/mason.nvim"
|
||||||
:cmd ["Mason" "MasonInstall" "MasonUpdate"]
|
:lazy false
|
||||||
:build ":MasonUpdate"
|
:build ":MasonUpdate"
|
||||||
:opts {:ui {:border "rounded"}}}
|
:opts {:ui {:border "rounded"}}}
|
||||||
|
|
||||||
|
;; Auto-install LSP servers and tools via Mason
|
||||||
|
{repo "WhoIsSethDaniel/mason-tool-installer.nvim"
|
||||||
|
:lazy false
|
||||||
|
:dependencies ["williamboman/mason.nvim"]
|
||||||
|
:opts {:ensure_installed ["clojure-lsp" "clj-kondo"]}}
|
||||||
|
|
||||||
|
;; Hop - EasyMotion-like word jumping
|
||||||
|
{repo "smoka7/hop.nvim"
|
||||||
|
:version "*"
|
||||||
|
:event "VeryLazy"
|
||||||
|
:config (fn []
|
||||||
|
(let [hop (require :hop)]
|
||||||
|
(hop.setup)
|
||||||
|
(vim.keymap.set :n "gw" (fn [] (hop.hint_words))
|
||||||
|
{:desc "Hop to word"})))}
|
||||||
|
|
||||||
;; which-key - Shows keybinding hints
|
;; which-key - Shows keybinding hints
|
||||||
;; lhs constant defined at top - which-key specs use index [1] for the key sequence
|
;; lhs constant defined at top - which-key specs use index [1] for the key sequence
|
||||||
{repo "folke/which-key.nvim"
|
{repo "folke/which-key.nvim"
|
||||||
|
|||||||
+6
-2
@@ -1,13 +1,17 @@
|
|||||||
{
|
{
|
||||||
"conjure": { "branch": "main", "commit": "403639610bcb9b6a5dfc494dc3179cc19773a471" },
|
"conjure": { "branch": "main", "commit": "403639610bcb9b6a5dfc494dc3179cc19773a471" },
|
||||||
|
"hop.nvim": { "branch": "master", "commit": "08ddca799089ab96a6d1763db0b8adc5320bf050" },
|
||||||
"lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" },
|
"lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" },
|
||||||
|
"mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" },
|
||||||
"mason.nvim": { "branch": "main", "commit": "44d1e90e1f66e077268191e3ee9d2ac97cc18e65" },
|
"mason.nvim": { "branch": "main", "commit": "44d1e90e1f66e077268191e3ee9d2ac97cc18e65" },
|
||||||
"nfnl": { "branch": "main", "commit": "fecf731e02bc51d88372c4f992fe1ef0c19c02ae" },
|
"nfnl": { "branch": "main", "commit": "fecf731e02bc51d88372c4f992fe1ef0c19c02ae" },
|
||||||
"nvim-paredit": { "branch": "master", "commit": "b6ba636874a3115d944e35746444724240568aca" },
|
|
||||||
"nvim-parinfer": { "branch": "master", "commit": "3968e669d9f02589aa311d33cb475b16b27c5fbb" },
|
"nvim-parinfer": { "branch": "master", "commit": "3968e669d9f02589aa311d33cb475b16b27c5fbb" },
|
||||||
"nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" },
|
"nvim-treesitter": { "branch": "main", "commit": "19c729dae6e0eeb79423df0cf37780aa9a7cc3b7" },
|
||||||
"plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" },
|
"plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" },
|
||||||
"telescope.nvim": { "branch": "master", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" },
|
"telescope.nvim": { "branch": "master", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" },
|
||||||
"tokyonight.nvim": { "branch": "main", "commit": "5da1b76e64daf4c5d410f06bcb6b9cb640da7dfd" },
|
"tokyonight.nvim": { "branch": "main", "commit": "5da1b76e64daf4c5d410f06bcb6b9cb640da7dfd" },
|
||||||
|
"vim-repeat": { "branch": "master", "commit": "65846025c15494983dafe5e3b46c8f88ab2e9635" },
|
||||||
|
"vim-sexp": { "branch": "master", "commit": "f5bd4cb2535969fe4741b24fa5f51690521dbaf0" },
|
||||||
|
"vim-sexp-mappings-for-regular-people": { "branch": "master", "commit": "4debb74b0a3e530f1b18e5b7dff98a40b2ad26f1" },
|
||||||
"which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
|
"which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user