Created
September 25, 2021 09:53
-
-
Save bangedorrunt/b7570fad84e6923398a217f9d46e29f3 to your computer and use it in GitHub Desktop.
troubleshoot.fnl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;;; Helper Functions Declaration | |
;; (import-macros {: defn | |
;; : into | |
;; : empty | |
;; : when-let | |
;; : if-let | |
;; : when-some | |
;; : if-some} :cljlib.macros) | |
(local {: inc | |
: dec | |
: first | |
: last | |
: rest | |
: any? | |
: every? | |
:some some? | |
: keys | |
: vals | |
: reduce | |
: reduce-kv | |
: merge | |
:mapv map | |
: filter | |
: string? | |
: number? | |
: nil? | |
: contains? | |
;; :map? tbl? | |
;; : set? | |
;; :vector? seq? | |
;; : vector | |
: empty? | |
: cons | |
: conj | |
: dissoc} (require :cljlib)) | |
;; (local {: format} string) | |
;; Reserve name for `into` macros | |
;; tbl->seq | |
;; seq->tbl | |
;; str->seq | |
(fn ->str [obj] | |
"Converts an object to its string representation" | |
(tostring obj)) | |
(fn str->seq [s] | |
"Convert an string into a sequence of characters." | |
(icollect [c (string.gmatch s ".")] | |
c)) | |
;; (fn ->key-opts [seq] | |
;; "Returns a set following the structure of `{:key true}` from a sequence" | |
;; (reduce #(merge $1 {$2 true}) {} seq)) | |
(fn ->key-opts [xs] | |
"Convert a sequence into a table of each value of the sequence as the | |
key and the value being `true`." | |
(collect [_ v (ipairs xs)] | |
(values v true))) | |
(fn fn? [obj] | |
"Returns true if the object is a function | |
This only works at compilation time" | |
(and (list? obj) (or (= (->str (first obj)) :hashfn) | |
(= (->str (first obj)) :fn)))) | |
(fn exists? [module-name] | |
"Returns true if the module exists and false if it doesn't" | |
(let [(ok? _) (pcall require module-name)] | |
ok?)) | |
;;; Macros Declaration | |
;; NOTE: https://github.com/rktjmp/hotpot.nvim/discussions/6 | |
;; Put Unique Global | |
;; | |
;; (val :any prefix? :string) -> (uuid :string) | |
;; | |
;; Takes any given value, generates a unique name (with optional prefix) | |
;; and inserts value into _G. Returns unique name. | |
(fn pug [val prefix?] | |
;; gensym will generate a unique id across a compile pass, but hotpot/aniseed | |
;; may compile files in separate passes as they are modified, so symbols may | |
;; collide you can avoid this by passing a unique prefix per-file or using | |
;; something like the "uid" below, based on compile time | |
(let [inter-compile-uid (_G.os.date "%s") | |
name (if prefix? | |
(.. (->str (gensym prefix?)) inter-compile-uid) | |
(.. (->str (gensym :pug)) inter-compile-uid))] | |
`(do | |
(tset _G ,name ,val) | |
,name))) | |
;; Wrap given in v:lua x pug call | |
(fn vlua [what prefix?] | |
`(.. "v:lua." ,(pug what prefix?) "()")) | |
;; BUG: `vlua` seems to have side-effect with `aniseed` plugin | |
;; current version using gensym doesn't evaluate `vlua` at runtime | |
(fn command! [name expr] | |
(let [name (->str name)] | |
(if (fn? expr) | |
`(vim.cmd (string.format "command! %s call %s" ,name ,(vlua expr))) | |
`(vim.cmd (string.format "command! %s %s" ,name ,expr))))) | |
(fn buf-command! [name expr] | |
(let [name (->str name)] | |
(if (fn? expr) | |
`(vim.cmd (string.format "command! -buffer %s call %s" ,name ,(vlua expr))) | |
`(vim.cmd (string.format "command! -buffer %s %s" ,name ,expr))))) | |
;; (fn command! [name f] | |
;; `(vim.cmd ,(string.format "command! %s %s" (->str name) (->str f)))) | |
;; (fn buf-command! [name f] | |
;; `(vim.cmd ,(string.format "command! -buffer %s %s" (->str name) (->str f)))) | |
(fn lua-command! [name f] | |
(let [f (.. "lua " (->str f))] | |
`(command! ,name ,f))) | |
(fn lua-buf-command! [name f] | |
(let [f (.. "lua " (->str f))] | |
`(buf-command! ,name ,f))) | |
(fn unless [condition ...] | |
"Takes a single condition and evaluates the rest as a body if it's nil or | |
false. This is intended for side-effects." | |
`(when (not ,condition) | |
,...)) | |
(fn set! [...] | |
"Set one or multiple vim options using the `vim.opt` API | |
The option name must be a symbol | |
If the option doesn't have a corresponding value, if it begins with no the | |
value becomes false, and if it doesn't it becomes true" | |
(fn expr [name ?value] | |
(let [name (->str name) | |
value (if (nil? ?value) (not (name:match :^no)) ?value) | |
name (if (nil? ?value) (or (name:match "^no(.*)$") name) name)] | |
(if (fn? value) | |
`(tset vim.opt ,name (string.format "%s" ,(vlua value))) | |
(match (name:sub -1) | |
"+" `(: (. vim.opt ,(name:sub 1 -2)) :append ,value) | |
"-" `(: (. vim.opt ,(name:sub 1 -2)) :remove ,value) | |
"^" `(: (. vim.opt ,(name:sub 1 -2)) :prepend ,value) | |
_ `(tset vim.opt ,name ,value))))) | |
(fn exprs [...] | |
(match [...] | |
(where [& rest] (empty? rest)) [] | |
(where [name value & rest] (not (sym? value))) | |
[(expr name value) (unpack (exprs (unpack rest)))] | |
[name & rest] [(expr name) (unpack (exprs (unpack rest)))] | |
_ [])) | |
(let [exprs (exprs ...)] | |
(if (> (length exprs) 1) | |
`(do | |
,(unpack exprs)) | |
(unpack exprs)))) | |
(fn set-local! [...] | |
"Set a local vim option using the `vim.opt_local` API" | |
(fn expr [name ?value] | |
(let [name (->str name) | |
value (if (nil? ?value) (not (name:match :^no)) ?value) | |
name (if (nil? ?value) (or (name:match "^no(.*)$") name) name)] | |
(if (fn? value) | |
`(tset vim.opt_local ,name (string.format "%s" ,(vlua value))) | |
(match (name:sub -1) | |
"+" `(: (. vim.opt_local ,(name:sub 1 -2)) :append ,value) | |
"-" `(: (. vim.opt_local ,(name:sub 1 -2)) :remove ,value) | |
"^" `(: (. vim.opt_local ,(name:sub 1 -2)) :prepend ,value) | |
_ `(tset vim.opt_local ,name ,value))))) | |
(fn exprs [...] | |
(match [...] | |
(where [& rest] (empty? rest)) [] | |
(where [name value & rest] (not (sym? value))) | |
[(expr name value) (unpack (exprs (unpack rest)))] | |
[name & rest] [(expr name) (unpack (exprs (unpack rest)))] | |
_ [])) | |
(let [exprs (exprs ...)] | |
(if (> (length exprs) 1) | |
`(do | |
,(unpack exprs)) | |
(unpack exprs)))) | |
(fn let! [...] | |
"Set a vim variable using the vim.[g b w t] API" | |
(fn expr [name value] | |
(let [name (->str name) | |
scope (when (contains? [:g/ :b/ :w/ :t/] (name:sub 1 2)) | |
(name:sub 1 1)) | |
name (if (nil? scope) name (name:sub 3))] | |
`(tset ,(match scope | |
:b `vim.b | |
:w `vim.w | |
:t `vim.t | |
_ `vim.g) ,name ,value))) | |
(fn exprs [...] | |
(match [...] | |
(where [& rest] (empty? rest)) [] | |
[name value & rest] [(expr name value) (unpack (exprs (unpack rest)))] | |
_ [])) | |
(let [exprs (exprs ...)] | |
(if (> (length exprs) 1) | |
`(do | |
,(unpack exprs)) | |
(unpack exprs)))) | |
(fn augroup! [name ...] | |
"Defines an autocommand group using the `vim.cmd` API." | |
`(do | |
,(unpack | |
(-> [`(vim.cmd ,(string.format "augroup %s" name)) | |
`(vim.cmd "autocmd!")] | |
(conj ...) | |
(conj `(vim.cmd "augroup END")))))) | |
(fn buf-augroup! [name ...] | |
"Defines a buffer-local autocommand group using the `vim.cmd` API." | |
`(do | |
,(unpack | |
(-> [`(vim.cmd ,(string.format "augroup %s" name)) | |
`(vim.cmd "autocmd! * <buffer>")] | |
(conj ...) | |
(conj `(vim.cmd "augroup END")))))) | |
(fn autocmd! [events pattern command] | |
"Defines an autocommand" | |
(let [events (if (sequence? events) events [events]) | |
events (-> (map ->str events) | |
(table.concat ",")) | |
pattern (if (sequence? pattern) pattern [pattern]) | |
pattern (-> (map ->str pattern) | |
(table.concat ","))] | |
(if (fn? command) | |
`(vim.cmd (string.format "autocmd %s %s call %s" ,events ,pattern | |
,(vlua command))) | |
`(vim.cmd (string.format "autocmd %s %s %s" ,events ,pattern ,command))))) | |
(fn buf-autocmd! [events command] | |
"Defines an autocommand" | |
(let [events (if (sequence? events) events [events]) | |
events (-> (map ->str events) | |
(table.concat ","))] | |
(if (fn? command) | |
`(vim.cmd (string.format "autocmd %s <buffer> call %s" ,events | |
,(vlua command))) | |
`(vim.cmd (string.format "autocmd %s <buffer> %s" ,events ,command))))) | |
(fn wk-map! [mode | |
lhs | |
{:buffer buffer? | |
:silent silent? | |
:noremap noremap? | |
:nowait nowait?} | |
description] | |
"A mapping using which-key" | |
`(let [(ok?# which-key#) (pcall require :which-key)] | |
(when ok?# | |
(which-key#.register {,lhs ,description} | |
{:mode ,mode | |
:buffer ,(if buffer? 0) | |
:silent ,(if silent? true) | |
:noremap ,(if (not noremap?) false) | |
:nowait ,(if nowait? true)})))) | |
(fn nmap! [[modes & options] lhs rhs ?description] | |
"Defines a vim mapping using the `vim.api.nvim_set_keymap` API or the | |
`vim.api.nvim_buf_set_keymap` if the option `:buffer` was passed. | |
Support all the options the API supports. | |
If the `rhs` argument is a function then automatically includes the `:expr` | |
option." | |
(fn nvim-set-keymap [mode lhs rhs options] | |
(let [buffer? (?. options :buffer) | |
options (dissoc options :buffer)] | |
(if buffer? | |
`(vim.api.nvim_buf_set_keymap 0 ,mode ,lhs ,rhs ,options) | |
`(vim.api.nvim_set_keymap ,mode ,lhs ,rhs ,options)))) | |
(fn is-rhs-a-fn? [rhs] | |
(if (fn? rhs) | |
(vlua rhs) | |
rhs)) | |
(let [modes (-> modes | |
->str | |
str->seq) | |
options | |
(if (fn? rhs) | |
(conj options :expr) | |
options) | |
options (->key-opts options) | |
exprs (map #(nvim-set-keymap $ lhs (is-rhs-a-fn? rhs) options) modes) | |
exprs (if (and ?description (exists? :which-key)) | |
(conj exprs (unpack (map #(wk-map! $ lhs options ?description) modes))) | |
exprs)] | |
(if (> (length exprs) 1) | |
`(do | |
,(unpack exprs)) | |
(unpack exprs)))) | |
(fn noremap! [[modes & options] lhs rhs ?description] | |
"Defines a vim mapping using the `vim.api.nvim_set_keymap` API or the | |
`vim.api.nvim_buf_set_keymap` if the option `:buffer` was passed. | |
Support all the options the API supports. | |
If the `rhs` argument is a function then automatically includes the `:expr` | |
option. | |
Automatically includes the `:noremap` option." | |
(let [options (cons :noremap options)] | |
`(nmap! ,(cons modes options) ,lhs ,rhs ,?description))) | |
(fn buf-nmap! [[modes & options] lhs rhs ?description] | |
"Defines a vim mapping using the `vim.api.nvim_buf_set_keymap` if the option | |
`:buffer` was passed. | |
Support all the options the API supports. | |
If the `rhs` argument is a function then automatically includes the `:expr` | |
option." | |
(let [options (cons :buffer options)] | |
`(nmap! ,(cons modes options) ,lhs ,rhs ,?description))) | |
(fn buf-noremap! [[modes & options] lhs rhs ?description] | |
"Defines a vim mapping using the `vim.api.nvim_buf_set_keymap` if the option | |
`:buffer` was passed. | |
Support all the options the API supports. | |
If the `rhs` argument is a function then automatically includes the `:expr` | |
option. | |
Automatically includes the `:noremap` option." | |
(let [options (->> options | |
(cons :buffer) | |
(cons :noremap))] | |
`(nmap! ,(cons modes options) ,lhs ,rhs ,?description))) | |
(fn hi! [group opts] | |
"Defines a highlight" | |
(let [f (fn [k v] | |
(match k | |
:fg (let [fg (. opts :fg)] | |
`(.. :ctermfg= ,fg " guifg=" ,fg)) | |
:bg (let [bg (. opts :bg)] | |
`(.. :ctermbg= ,bg " guibg=" ,bg)) | |
_ `(.. ,(->str k) "=" ,v))) | |
args (reduce-kv (fn [acc k v] | |
`(.. ,acc " " ,(f k v))) | |
group opts)] | |
`(->> ,args | |
(string.format "hi %s") | |
vim.cmd))) | |
(fn t [key] | |
"Returns the string with termcodes replaced" | |
`(vim.api.nvim_replace_termcodes ,(->str key) true true true)) | |
(fn feedkeys [key] | |
`(vim.api.nvim_feedkeys ,(t key) :n true)) | |
(fn has? [property] | |
"Returns true if vim has a propety" | |
`(match (vim.fn.has ,property) | |
1 true | |
0 false | |
_# nil)) | |
{: pug | |
: vlua | |
: set! | |
: set-local! | |
: let! | |
: command! | |
: buf-command! | |
: lua-command! | |
: lua-buf-command! | |
: augroup! | |
: buf-augroup! | |
: autocmd! | |
: buf-autocmd! | |
: nmap! | |
: noremap! | |
: buf-nmap! | |
: buf-noremap! | |
: hi! | |
: t | |
: feedkeys | |
: has? | |
: unless} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment