diff --git a/indent/clojure.vim b/indent/clojure.vim
index dcbef55..e80da79 100644
--- a/indent/clojure.vim
+++ b/indent/clojure.vim
@@ -1,19 +1,19 @@
 " Vim indent file
-" Language:           Clojure
-" Maintainer:         Alex Vear <alex@vear.uk>
-" Former Maintainers: Sung Pae <self@sungpae.com>
-"                     Meikel Brandmeyer <mb@kotka.de>
-" URL:                https://github.com/clojure-vim/clojure.vim
-" License:            Vim (see :h license)
-" Last Change:        %%RELEASE_DATE%%
+" Language:            Clojure
+" Maintainer:          Alex Vear <alex@vear.uk>
+" Former Maintainers:  Sung Pae <self@sungpae.com>
+"                      Meikel Brandmeyer <mb@kotka.de>
+" Last Change:         %%RELEASE_DATE%%
+" License:             Vim (see :h license)
+" Repository:          https://github.com/clojure-vim/clojure.vim
 
 if exists("b:did_indent")
 	finish
 endif
 let b:did_indent = 1
 
-let s:save_cpo = &cpo
-set cpo&vim
+let s:save_cpo = &cpoptions
+set cpoptions&vim
 
 let b:undo_indent = 'setlocal autoindent< smartindent< expandtab< softtabstop< shiftwidth< indentexpr< indentkeys<'
 
@@ -21,418 +21,124 @@ setlocal noautoindent nosmartindent
 setlocal softtabstop=2 shiftwidth=2 expandtab
 setlocal indentkeys=!,o,O
 
-if exists("*searchpairpos")
-
-	if !exists('g:clojure_maxlines')
-		let g:clojure_maxlines = 300
-	endif
-
-	if !exists('g:clojure_fuzzy_indent')
-		let g:clojure_fuzzy_indent = 1
-	endif
-
-	if !exists('g:clojure_fuzzy_indent_patterns')
-		let g:clojure_fuzzy_indent_patterns = ['^with', '^def', '^let']
-	endif
-
-	if !exists('g:clojure_fuzzy_indent_blacklist')
-		let g:clojure_fuzzy_indent_blacklist = ['-fn$', '\v^with-%(meta|out-str|loading-context)$']
-	endif
-
-	if !exists('g:clojure_special_indent_words')
-		let g:clojure_special_indent_words = 'deftype,defrecord,reify,proxy,extend-type,extend-protocol,letfn'
-	endif
-
-	if !exists('g:clojure_align_multiline_strings')
-		let g:clojure_align_multiline_strings = 0
-	endif
-
-	if !exists('g:clojure_align_subforms')
-		let g:clojure_align_subforms = 0
-	endif
-
-	if !exists('g:clojure_cljfmt_compat')
-		let g:clojure_cljfmt_compat = 0
+" TODO: ignore 'lisp' and 'lispwords' options (actually, turn them off?)
+
+" TODO: Optional Vim9script implementations of hotspot/bottleneck functions.
+" FIXME: fallback case when syntax highlighting is disabled.
+
+" Function to get the indentation of a line.
+" function! s:GetIndent(lnum)
+" 	let l = getline(a:lnum)
+" 	return len(l) - len(trim(l, " \t", 1))
+" endfunction
+
+function! s:GetSynIdName(line, col)
+	return synIDattr(synID(a:line, a:col, 0), 'name')
+endfunction
+
+function! s:SyntaxMatch(pattern, line, col)
+	return s:GetSynIdName(a:line, a:col) =~? a:pattern
+endfunction
+
+function! s:IgnoredRegion()
+	return s:SyntaxMatch('\vstring|regex|comment|character', line('.'), col('.'))
+endfunction
+
+function! s:NotAStringDelimiter()
+	return ! s:SyntaxMatch('stringdelimiter', line('.'), col('.'))
+endfunction
+
+function! s:IsInString()
+	return s:SyntaxMatch('string', line('.'), col('.'))
+endfunction
+
+function! s:NotARegexpDelimiter()
+	return ! s:SyntaxMatch('regexpdelimiter', line('.'), col('.'))
+endfunction
+
+function! s:IsInRegex()
+	return s:SyntaxMatch('regex', line('.'), col('.'))
+endfunction
+
+function! s:Conf(opt, default)
+	return get(b:, a:opt, get(g:, a:opt, a:default))
+endfunction
+
+function! s:ShouldAlignMultiLineStrings()
+	return s:Conf('clojure_align_multiline_strings', 0)
+endfunction
+
+function! s:ClosestMatch(match1, match2)
+	let [_, coord1] = a:match1
+	let [_, coord2] = a:match2
+	if coord1[0] < coord2[0]
+		return a:match2
+	elseif coord1[0] == coord2[0] && coord1[1] < coord2[1]
+		return a:match2
+	else
+		return a:match1
 	endif
-
-	function! s:syn_id_name()
-		return synIDattr(synID(line("."), col("."), 0), "name")
-	endfunction
-
-	function! s:ignored_region()
-		return s:syn_id_name() =~? '\vstring|regex|comment|character'
-	endfunction
-
-	function! s:current_char()
-		return getline('.')[col('.')-1]
-	endfunction
-
-	function! s:current_word()
-		return getline('.')[col('.')-1 : searchpos('\v>', 'n', line('.'))[1]-2]
-	endfunction
-
-	function! s:is_paren()
-		return s:current_char() =~# '\v[\(\)\[\]\{\}]' && !s:ignored_region()
-	endfunction
-
-	" Returns 1 if string matches a pattern in 'patterns', which should be
-	" a list of patterns.
-	function! s:match_one(patterns, string)
-		for pat in a:patterns
-			if a:string =~# pat | return 1 | endif
-		endfor
-	endfunction
-
-	function! s:match_pairs(open, close, stopat)
-		" Stop only on vector and map [ resp. {. Ignore the ones in strings and
-		" comments.
-		if a:stopat == 0 && g:clojure_maxlines > 0
-			let stopat = max([line(".") - g:clojure_maxlines, 0])
-		else
-			let stopat = a:stopat
-		endif
-
-		let pos = searchpairpos(a:open, '', a:close, 'bWn', "!s:is_paren()", stopat)
-		return [pos[0], col(pos)]
-	endfunction
-
-	function! s:clojure_check_for_string_worker()
-		" Check whether there is the last character of the previous line is
-		" highlighted as a string. If so, we check whether it's a ". In this
-		" case we have to check also the previous character. The " might be the
-		" closing one. In case the we are still in the string, we search for the
-		" opening ". If this is not found we take the indent of the line.
-		let nb = prevnonblank(v:lnum - 1)
-
-		if nb == 0
-			return -1
-		endif
-
-		call cursor(nb, 0)
-		call cursor(0, col("$") - 1)
-		if s:syn_id_name() !~? "string"
-			return -1
-		endif
-
-		" This will not work for a " in the first column...
-		if s:current_char() == '"'
-			call cursor(0, col("$") - 2)
-			if s:syn_id_name() !~? "string"
-				return -1
-			endif
-			if s:current_char() != '\'
-				return -1
-			endif
-			call cursor(0, col("$") - 1)
-		endif
-
-		let p = searchpos('\(^\|[^\\]\)\zs"', 'bW')
-
-		if p != [0, 0]
-			return p[1] - 1
-		endif
-
-		return indent(".")
-	endfunction
-
-	function! s:check_for_string()
-		let pos = getpos('.')
-		try
-			let val = s:clojure_check_for_string_worker()
-		finally
-			call setpos('.', pos)
-		endtry
-		return val
-	endfunction
-
-	function! s:strip_namespace_and_macro_chars(word)
-		return substitute(a:word, "\\v%(.*/|[#'`~@^,]*)(.*)", '\1', '')
-	endfunction
-
-	function! s:clojure_is_method_special_case_worker(position)
-		" Find the next enclosing form.
-		call search('\S', 'Wb')
-
-		" Special case: we are at a '(('.
-		if s:current_char() == '('
-			return 0
-		endif
-		call cursor(a:position)
-
-		let next_paren = s:match_pairs('(', ')', 0)
-
-		" Special case: we are now at toplevel.
-		if next_paren == [0, 0]
-			return 0
-		endif
-		call cursor(next_paren)
-
-		call search('\S', 'W')
-		let w = s:strip_namespace_and_macro_chars(s:current_word())
-
-		if g:clojure_special_indent_words =~# '\V\<' . w . '\>'
-
-			" `letfn` is a special-special-case.
-			if w ==# 'letfn'
-				" Earlier code left the cursor at:
-				"     (letfn [...] ...)
-				"      ^
-
-				" Search and get coordinates of first `[`
-				"     (letfn [...] ...)
-				"            ^
-				call search('\[', 'W')
-				let pos = getcurpos()
-				let letfn_bracket = [pos[1], pos[2]]
-
-				" Move cursor to start of the form this function was
-				" initially called on.  Grab the coordinates of the
-				" closest outer `[`.
-				call cursor(a:position)
-				let outer_bracket = s:match_pairs('\[', '\]', 0)
-
-				" If the located square brackets are not the same,
-				" don't use special-case formatting.
-				if outer_bracket != letfn_bracket
-					return 0
-				endif
-			endif
-
-			return 1
-		endif
-
+endfunction
+
+" Only need to search up.  Never down.
+function! s:GetClojureIndent()
+	let lnum = v:lnum
+
+	" Move cursor to the first column of the line we want to indent.
+	cursor(lnum, 0)
+
+	let matches = [
+		\  ['lst', searchpairpos( '(', '',  ')', 'bznW', function('<SID>IgnoredRegion'))],
+		\  ['vec', searchpairpos('\[', '', '\]', 'bznW', function('<SID>IgnoredRegion'))],
+		\  ['map', searchpairpos( '{', '',  '}', 'bznW', function('<SID>IgnoredRegion'))],
+		\  ['reg', s:IsInRegex() ? searchpairpos('#\zs"', '', '"', 'bznW', function('<SID>NotARegexpDelimiter')) : [0, 0]],
+		\  ['str', s:IsInString() ? searchpairpos('"', '', '"', 'bznW', function('<SID>NotAStringDelimiter')) : [0, 0]]
+		\ ]
+	echom 'Matches' matches
+
+	" Find closest matching higher form.
+	let [formtype, coord] = reduce(matches, function('<SID>ClosestMatch'), ['top', [0, 0]])
+	echom 'Match' formtype coord
+
+	if formtype == 'top'
+		" At the top level, no indent.
+		echom 'At the top level!'
 		return 0
-	endfunction
-
-	function! s:is_method_special_case(position)
-		let pos = getpos('.')
-		try
-			let val = s:clojure_is_method_special_case_worker(a:position)
-		finally
-			call setpos('.', pos)
-		endtry
-		return val
-	endfunction
-
-	" Check if form is a reader conditional, that is, it is prefixed by #?
-	" or #?@
-	function! s:is_reader_conditional_special_case(position)
-		return getline(a:position[0])[a:position[1] - 3 : a:position[1] - 2] == "#?"
-			\|| getline(a:position[0])[a:position[1] - 4 : a:position[1] - 2] == "#?@"
-	endfunction
-
-	" Returns 1 for opening brackets, -1 for _anything else_.
-	function! s:bracket_type(char)
-		return stridx('([{', a:char) > -1 ? 1 : -1
-	endfunction
-
-	" Returns: [opening-bracket-lnum, indent]
-	function! s:clojure_indent_pos()
-		" Get rid of special case.
-		if line(".") == 1
-			return [0, 0]
-		endif
-
-		" We have to apply some heuristics here to figure out, whether to use
-		" normal lisp indenting or not.
-		let i = s:check_for_string()
-		if i > -1
-			return [0, i + !!g:clojure_align_multiline_strings]
-		endif
-
-		call cursor(0, 1)
-
-		" Find the next enclosing [ or {. We can limit the second search
-		" to the line, where the [ was found. If no [ was there this is
-		" zero and we search for an enclosing {.
-		let paren = s:match_pairs('(', ')', 0)
-		let bracket = s:match_pairs('\[', '\]', paren[0])
-		let curly = s:match_pairs('{', '}', bracket[0])
-
-		" In case the curly brace is on a line later then the [ or - in
-		" case they are on the same line - in a higher column, we take the
-		" curly indent.
-		if curly[0] > bracket[0] || curly[1] > bracket[1]
-			if curly[0] > paren[0] || curly[1] > paren[1]
-				return curly
-			endif
-		endif
-
-		" If the curly was not chosen, we take the bracket indent - if
-		" there was one.
-		if bracket[0] > paren[0] || bracket[1] > paren[1]
-			return bracket
-		endif
-
-		" There are neither { nor [ nor (, ie. we are at the toplevel.
-		if paren == [0, 0]
-			return paren
-		endif
-
-		" Now we have to reimplement lispindent. This is surprisingly easy, as
-		" soon as one has access to syntax items.
-		"
-		" - Check whether we are in a special position after a word in
-		"   g:clojure_special_indent_words. These are special cases.
-		" - Get the next keyword after the (.
-		" - If its first character is also a (, we have another sexp and align
-		"   one column to the right of the unmatched (.
-		" - In case it is in lispwords, we indent the next line to the column of
-		"   the ( + sw.
-		" - If not, we check whether it is last word in the line. In that case
-		"   we again use ( + sw for indent.
-		" - In any other case we use the column of the end of the word + 2.
-		call cursor(paren)
-
-		if s:is_method_special_case(paren)
-			return [paren[0], paren[1] + &shiftwidth - 1]
-		endif
-
-		if s:is_reader_conditional_special_case(paren)
-			return paren
-		endif
-
-		" In case we are at the last character, we use the paren position.
-		if col("$") - 1 == paren[1]
-			return paren
-		endif
-
-		" In case after the paren is a whitespace, we search for the next word.
-		call cursor(0, col('.') + 1)
-		if s:current_char() == ' '
-			call search('\v\S', 'W')
-		endif
-
-		" If we moved to another line, there is no word after the (. We
-		" use the ( position for indent.
-		if line(".") > paren[0]
-			return paren
-		endif
-
-		" We still have to check, whether the keyword starts with a (, [ or {.
-		" In that case we use the ( position for indent.
-		let w = s:current_word()
-		if s:bracket_type(w[0]) == 1
-			return paren
-		endif
-
-		" If the keyword begins with #, check if it is an anonymous
-		" function or set, in which case we indent by the shiftwidth
-		" (minus one if g:clojure_align_subforms = 1), or if it is
-		" ignored, in which case we use the ( position for indent.
-		if w[0] == "#"
-			" TODO: Handle #=() and other rare reader invocations?
-			if w[1] == '(' || w[1] == '{'
-				return [paren[0], paren[1] + (g:clojure_align_subforms ? 0 : &shiftwidth - 1)]
-			elseif w[1] == '_'
-				return paren
-			elseif w[1] == "'" && g:clojure_cljfmt_compat
-				return paren
-			endif
-		endif
-
-		" Paren indent for keywords, symbols and derefs
-		if g:clojure_cljfmt_compat && w[0] =~# "[:@']"
-			return paren
-		endif
-
-		" Test words without namespace qualifiers and leading reader macro
-		" metacharacters.
-		"
-		" e.g. clojure.core/defn and #'defn should both indent like defn.
-		let ww = s:strip_namespace_and_macro_chars(w)
-
-		if &lispwords =~# '\V\<' . ww . '\>'
-			return [paren[0], paren[1] + &shiftwidth - 1]
-		endif
-
-		if g:clojure_fuzzy_indent
-			\ && !s:match_one(g:clojure_fuzzy_indent_blacklist, ww)
-			\ && s:match_one(g:clojure_fuzzy_indent_patterns, ww)
-			return [paren[0], paren[1] + &shiftwidth - 1]
-		endif
-
-		call search('\v\_s', 'cW')
-		call search('\v\S', 'W')
-		if paren[0] < line(".")
-			return [paren[0], paren[1] + (g:clojure_align_subforms ? 0 : &shiftwidth - 1)]
-		endif
-
-		call search('\v\S', 'bW')
-		return [line('.'), col('.') + 1]
-	endfunction
-
-	function! GetClojureIndent()
-		let lnum = line('.')
-		let orig_lnum = lnum
-		let orig_col = col('.')
-		let [opening_lnum, indent] = s:clojure_indent_pos()
-
-		" Account for multibyte characters
-		if opening_lnum > 0
-			let indent -= indent - virtcol([opening_lnum, indent])
-		endif
-
-		" Return if there are no previous lines to inherit from
-		if opening_lnum < 1 || opening_lnum >= lnum - 1
-			call cursor(orig_lnum, orig_col)
-			return indent
-		endif
-
-		let bracket_count = 0
-
-		" Take the indent of the first previous non-white line that is
-		" at the same sexp level. cf. src/misc1.c:get_lisp_indent()
-		while 1
-			let lnum = prevnonblank(lnum - 1)
-			let col = 1
-
-			if lnum <= opening_lnum
-				break
-			endif
-
-			call cursor(lnum, col)
-
-			" Handle bracket counting edge case
-			if s:is_paren()
-				let bracket_count += s:bracket_type(s:current_char())
-			endif
-
-			while 1
-				if search('\v[(\[{}\])]', '', lnum) < 1
-					break
-				elseif !s:ignored_region()
-					let bracket_count += s:bracket_type(s:current_char())
-				endif
-			endwhile
-
-			if bracket_count == 0
-				" Check if this is part of a multiline string
-				call cursor(lnum, 1)
-				if s:syn_id_name() !~? '\vstring|regex'
-					call cursor(orig_lnum, orig_col)
-					return indent(lnum)
-				endif
-			endif
-		endwhile
+	elseif formtype == 'lst'
+		echom 'Special format rules!'
+		" TODO
+		" Grab text!
+		echom getline(coord[0], lnum - 1)
+		" Begin lexing!
+		return coord[1] + 1
+	elseif formtype == 'vec' || formtype == 'map'
+		" Inside a vector, map or set.
+		return coord[1]
+	elseif formtype == 'reg'
+		" Inside a regex.
+		echom 'Inside a regex!'
+		return coord[1] - (s:ShouldAlignMultiLineStrings() ? 0 : 2)
+	elseif formtype == 'str'
+		" Inside a string.
+		echom 'Inside a string!'
+		return coord[1] - (s:ShouldAlignMultiLineStrings() ? 0 : 1)
+	endif
 
-		call cursor(orig_lnum, orig_col)
-		return indent
-	endfunction
+	return 2
+endfunction
 
-	setlocal indentexpr=GetClojureIndent()
 
-else
+setlocal indentexpr=s:GetClojureIndent()
 
-	" In case we have searchpairpos not available we fall back to
-	" normal lisp indenting.
-	setlocal indentexpr=
-	setlocal lisp
-	let b:undo_indent .= '| setlocal lisp<'
 
-endif
+" TODO: if exists("*searchpairpos")
+" In case we have searchpairpos not available we fall back to normal lisp
+" indenting.
+"setlocal indentexpr=
+"setlocal lisp
+"let b:undo_indent .= '| setlocal lisp<'
 
-let &cpo = s:save_cpo
+let &cpoptions = s:save_cpo
 unlet! s:save_cpo
 
 " vim:sts=8:sw=8:ts=8:noet