This repository has been archived on 2024-10-28. You can view files and clone it, but cannot push or open issues or pull requests.
nvim-config/fnl/macros.fnl

132 lines
4.4 KiB
Fennel

;;; macros.fnl - useful macros
;; Helpful keymaping functions
(lambda bind! [modes key cmd ?a1 ?a2]
(let [desc (or ?a2 ?a1)
buf (if (and ?a1 ?a2) ?a1 ?a2)
opts { :noremap true
:silent true
:buffer buf }]
(when desc
(tset opts :desc desc))
(if (table? modes)
(let [output {}]
(each [_ mode (ipairs modes)]
(table.insert output `(vim.keymap.set ,mode ,key ,cmd ,opts)))
output)
`(vim.keymap.set ,modes ,key ,cmd ,opts))))
;; Better autocommands
(lambda hook! [hooks ?patterns callback]
(let [hook_table (if (= (type hooks) :table)
hooks
[ hooks ])
pattern_table (if (not ?patterns)
[]
(= (type ?patterns) :table)
?patterns
[ ?patterns ])]
(var group (.. (tostring (math.random 0 1000000000) "-config-hook")))
(each [_ hook (ipairs hook_table)]
(set group (.. group "-" hook)))
(each [_ pattern (ipairs pattern_table)]
(set group (.. group "-" pattern)))
`(vim.api.nvim_create_autocmd ,hook_table
{ :group
(vim.api.nvim_create_augroup ,group
{ :clear true })
:pattern ,pattern_table
:callback ,callback })))
;; Utility functions for use!
(lambda create-list-entries [...]
(let [output { :active-entry nil
:entries {} }]
(lambda output.process [self entry]
(var result false)
(when self.active-entry
(if (and (. self :entries self.active-entry :is-first)
(not (list? entry)))
(do (tset self :entries self.active-entry :data entry)
(set self.active-entry nil)
(set result true))
(= (type entry) :string)
(set self.active-entry nil)
(do (table.insert (. self :entries self.active-entry :data) entry)
(tset self :entries self.active-entry :is-first false)
(set result true))))
(when (and (= (type entry) :string) (. self :entries entry))
(assert-compile (not (. self :entries entry :present))
(.. "':" entry "' cannot appear more than once in `use'"))
(set self.active-entry entry)
(tset self :entries entry :present true)
(set result true))
result)
(lambda output.splice-into [self other]
(each [name entry (pairs self.entries)]
(when entry.present
(tset other name entry.data))))
(each [_ val (ipairs [...])]
(tset output :entries val { :present false :is-first true :data `(lambda [])}))
output))
;; Nicer macro for use
;; :config acts like use-package's :init and :config options,
;; taking in the following lisp expressions as its arguments
(lambda use! [repo ...]
(local output [ repo ])
(var last_key nil)
(var list_entries (create-list-entries :config :setup
:run))
(each [_ val (ipairs [...])]
(if last_key
(do (tset output last_key val)
(set last_key nil))
(not (list_entries:process val))
(set last_key val)))
(list_entries:splice-into output)
`(use ,output))
;; Call a plugin's `setup function'
(lambda setup! [pkg ...] (local output [ ])
(var last_key nil)
(each [_ val (ipairs [...])]
(if last_key
(do (tset output last_key val)
(set last_key nil))
(set last_key val)))
`((. (require ,pkg) :setup) ,output))
;; Call module function
(lambda module-call! [mod func ...]
`((. (require ,mod) ,func) ,...))
;; Return module function
(lambda module-fn! [mod func]
`(. (require ,mod) ,func))
;; Basically does what the Emacs function of the same name does.
;; Wraps the code inside with a `winsaveview' and `winrestview'
(lambda save-excursion! [...]
(let [args [...]
len (# args)]
(tset args len `(let [retvar# ,(. args len)]
(vim.fn.winrestview save#)
retvar#))
`(let [save# (vim.fn.winsaveview)]
,(unpack args))))
;; Returns the keys for table
;; Careful, this finds them will a loop every time it is called!
(lambda keys! [table]
`(icollect [key# _# (pairs ,table)] key#))
{: bind!
: hook!
: use!
: setup!
: module-call!
: module-fn!
: save-excursion!
: keys!}