@@ -24,6 +24,51 @@ setlocal indentkeys=!,o,O
2424" NOTE: To debug this code, make sure to "set debug+=msg" otherwise errors
2525" will occur silently.
2626
27+ if ! exists (' g:clojure_fuzzy_indent_patterns' )
28+ let g: clojure_fuzzy_indent_patterns = [
29+ \ " \v ^with-%(meta|out-str|loading-context)\@ !" ,
30+ \ " ^def" ,
31+ \ " ^let"
32+ \ ]
33+ endif
34+
35+ if ! exists (' g:clojure_indent_rules' )
36+ " Defaults copied from: https://github.com/clojure-emacs/clojure-mode/blob/0e62583b5198f71856e4d7b80e1099789d47f2ed/clojure-mode.el#L1800-L1875
37+ let g: clojure_indent_rules = {
38+ \ " ns" : 1 ,
39+ \ " fn" : 1 , " def" : 1 , " defn" : 1 , " bound-fn" : 1 ,
40+ \ " if" : 1 , " if-not" : 1 , " if-some" : 1 , " if-let" : 1 ,
41+ \ " when" : 1 , " when-not" : 1 , " when-some" : 1 , " when-let" : 1 , " when-first" : 1 ,
42+ \ " case" : 1 , " cond" : 0 , " cond->" : 1 , " cond->>" : 1 , " condp" : 2 ,
43+ \ " while" : 1 , " loop" : 1 , " for" : 1 , " doseq" : 1 , " dotimes" : 1 ,
44+ \ " do" : 0 , " doto" : 1 , " comment" : 0 , " as->" : 2 ,
45+ \ " delay" : 0 , " future" : 0 , " locking" : 1 ,
46+ \ " fdef" : 1 ,
47+ \ " extend" : 1 ,
48+ \ " try" : 0 , " catch" : 2 , " finally" : 0 ,
49+ \ " let" : 1 , " binding" : 1 ,
50+ \ " defmethod" : 1 ,
51+ \ " this-as" : 1 ,
52+ \ " deftest" : 1 , " testing" : 1 , " use-fixtures" : 1 , " are" : 2 ,
53+ \ " alt!" : 0 , " alt!!" : 0 , " go" : 0 , " go-loop" : 1 , " thread" : 0 ,
54+ \ " run" : 1 , " run*" : 1 , " fresh" : 1
55+ \ }
56+
57+ " (letfn '(1 ((:defn)) nil))
58+ " (proxy '(2 nil nil (:defn)))
59+ " (reify '(:defn (1)))
60+ " (deftype '(2 nil nil (:defn)))
61+ " (defrecord '(2 nil nil (:defn)))
62+ " (defprotocol '(1 (:defn)))
63+ " (definterface '(1 (:defn)))
64+ " (extend-protocol '(1 :defn))
65+ " (extend-type '(1 :defn))
66+ " (specify '(1 :defn)) ; ClojureScript
67+ " (specify! '(1 :defn)) ; ClojureScript
68+ " (this-as 1) ; ClojureScript
69+ " clojure.test, core.async, core.logic
70+ endif
71+
2772" Get the value of a configuration option.
2873function ! s: Conf (opt , default)
2974 return get (b: , a: opt , get (g: , a: opt , a: default ))
@@ -165,23 +210,49 @@ function! s:StringIndent(delim_pos)
165210endfunction
166211
167212function ! s: ListIndent (delim_pos)
168- " TODO: attempt to extend "s:InsideForm" to provide information about
169- " the subforms being formatted to avoid second parsing step.
213+ " TODO: extend "s:InsideForm" to provide information about the
214+ " subforms being formatted to avoid second parsing step.
170215
171216 call cursor (a: delim_pos )
172217 let ln = getline(a:delim_pos[0])
173218 let base_indent = a: delim_pos [1 ]
174219
175- " 1. TODO: Macro/rule indentation
176- " if starts with a symbol or keyword: extract it.
177- " - Look up in rules table.
178- " - See number for forms forward to lookup.
179- " - Start parsing forwards "x" forms. (Skip metadata)
180- " - Apply indentation.
220+ " 1. Macro/rule indentation
221+ " if starts with a symbol, extract it.
222+ " - Split namespace off symbol and #'/' syntax.
223+ " - Check against pattern rules and apply indent on match.
224+ " - TODO: Look up in rules table and apply indent on match.
181225 " else, not found, go to 2.
182- " TODO: complex indentation (e.g. letfn)
183- " TODO: namespaces.
184- " let syms = split(ln[base_indent:], '[[:space:],;()\[\]{}@\\"^~`]', 1)
226+ "
227+ " TODO: handle complex indentation (e.g. letfn) and introduce
228+ " indentation config similar to Emacs' clojure-mode and cljfmt.
229+ " This new config option `clojure_indent_rules` should replace most
230+ " other indentation options.
231+ "
232+ " TODO: replace `clojure_fuzzy_indent_patterns` with `clojure_indent_patterns`
233+ let syms = split (ln [base_indent:], '[[:space:],;()\[\]{}@\\"^~`]', 1)
234+ if ! empty (syms)
235+ let sym = syms[0 ]
236+ " TODO: strip #' and ' from front of symbol.
237+ if sym = ~# ' \v^%([a-zA-Z!$&*_+=|<>?-]|[^\x00-\x7F])'
238+
239+ " TODO: handle namespaced and non-namespaced variants.
240+ if sym = ~# ' ./.'
241+ let [_namespace, name] = split (sym, ' /' )
242+ endif
243+
244+ for pat in s: Conf (' clojure_fuzzy_indent_patterns' , [])
245+ if sym = ~# pat
246+ return base_indent + 1
247+ endif
248+ endfor
249+
250+ let rules = s: Conf (' clojure_indent_rules' , {})
251+ let sym_match = get (rules, sym, -1 )
252+ " TODO: handle 2+ differently?
253+ if sym_match >= 0 | return base_indent + 1 | endif
254+ endif
255+ endif
185256
186257 " 2. Function indentation
187258 " if first operand is on the same line? (Treat metadata as args.)
0 commit comments