about summary refs log tree commit diff
path: root/fnl/nvrc/macro
diff options
context:
space:
mode:
authorsefidel <contact@sefidel.net>2022-02-10 00:24:03 +0900
committersefidel <contact@sefidel.net>2022-02-10 00:24:03 +0900
commit72d448e384249103748ee83b587c45924e4bc44d (patch)
tree2aa05a6aaf8c7aa37a8c278fd2fede6e62ff2218 /fnl/nvrc/macro
downloadnvimrc-72d448e384249103748ee83b587c45924e4bc44d.tar.gz
nvimrc-72d448e384249103748ee83b587c45924e4bc44d.zip
Initial commit
Diffstat (limited to 'fnl/nvrc/macro')
-rw-r--r--fnl/nvrc/macro/color.fnl9
-rw-r--r--fnl/nvrc/macro/event.fnl63
-rw-r--r--fnl/nvrc/macro/keymap.fnl46
-rw-r--r--fnl/nvrc/macro/misc.fnl1
-rw-r--r--fnl/nvrc/macro/pack.fnl80
-rw-r--r--fnl/nvrc/macro/set.fnl79
-rw-r--r--fnl/nvrc/macro/thread.fnl15
-rw-r--r--fnl/nvrc/macro/toolkit.fnl39
8 files changed, 332 insertions, 0 deletions
diff --git a/fnl/nvrc/macro/color.fnl b/fnl/nvrc/macro/color.fnl
new file mode 100644
index 0000000..9636956
--- /dev/null
+++ b/fnl/nvrc/macro/color.fnl
@@ -0,0 +1,9 @@
+(fn tbl? [x]
+  (= :table (type x)))
+
+(fn highlight [group-arg colset]
+  "Add a highlighting group."
+  (each [_ group (ipairs (if (tbl? group-arg) group-arg [group-arg]))]
+      (vim.api.nvim_set_hl 0 group colset)))
+
+{: highlight}
diff --git a/fnl/nvrc/macro/event.fnl b/fnl/nvrc/macro/event.fnl
new file mode 100644
index 0000000..3453431
--- /dev/null
+++ b/fnl/nvrc/macro/event.fnl
@@ -0,0 +1,63 @@
+(import-macros {: as->} :nvrc.macro.thread)
+
+(local {: format} string)
+(local {: insert : concat} table)
+
+(local {: fn? : gensym-checksum : vlua} (require :nvrc.macro.toolkit))
+
+(fn last [xs]
+  (. xs (length xs)))
+
+(fn ->str [x]
+  (tostring x))
+
+(fn includes? [xs x]
+  (accumulate [is? false _ v (ipairs xs) :until is?]
+    (= v x)))
+
+(lambda au! [name ...]
+  "Defines an autocommand group using the vim API."
+  `(do
+     (vim.cmd ,(format "augroup %s" name))
+     (vim.cmd :autocmd!)
+     (do
+       ,...)
+     (vim.cmd "augroup END")))
+
+(lambda aub! [name ...]
+  "Defines a buffer-local autocommand group using the vim API."
+  `(do
+     (vim.cmd ,(format "augroup %s" name))
+     (vim.cmd "autocmd! * <buffer>")
+     (do
+       ,...)
+     (vim.cmd "augroup END")))
+
+(lambda ac! [events pattern ...]
+  "Defines an autocommand using the vim API."
+  (let [events (as-> [$ events] (if (sequence? $) $ [$])
+                     (icollect [_ v (ipairs $)]
+                       (->str v)) (concat $ ","))
+        pattern (as-> [$ pattern] (if (sequence? $) $ [$])
+                      (icollect [_ v (ipairs $)]
+                        (->str v)) (concat $ ","))
+        once? (or (includes? [...] `++once) (includes? [...] :++once))
+        nested? (or (includes? [...] `++nested) (includes? [...] :++nested))
+        command (last [...])]
+    (if (fn? command)
+        (let [fsym (gensym-checksum "__" command)]
+          `(do
+             (global ,fsym ,command)
+             (vim.cmd ,(format (if (and once? nested?)
+                                   "autocmd %s %s ++once ++nested call %s" once?
+                                   "autocmd %s %s ++once call %s" nested?
+                                   "autocmd %s %s ++nested call %s"
+                                   "autocmd %s %s call %s")
+                               events pattern (vlua fsym)))))
+        `(vim.cmd ,(format (if (and once? nested?)
+                               "autocmd %s %s ++once ++nested %s" once?
+                               "autocmd %s %s ++once %s" nested?
+                               "autocmd %s %s ++nested %s" "autocmd %s %s %s")
+                           events pattern command)))))
+
+{: au! : aub! : ac!}
diff --git a/fnl/nvrc/macro/keymap.fnl b/fnl/nvrc/macro/keymap.fnl
new file mode 100644
index 0000000..7a784ab
--- /dev/null
+++ b/fnl/nvrc/macro/keymap.fnl
@@ -0,0 +1,46 @@
+(local {: gmatch} string)
+(local {: insert} table)
+
+(local {: fn?} (require :nvrc.macro.toolkit))
+
+(fn ->str [x]
+  (tostring x))
+
+(fn nil? [x]
+  (= nil x))
+
+(fn str? [x]
+  (= :string (type x)))
+
+(fn tbl? [x]
+  (= :table (type x)))
+
+(lambda map! [[modes & options] lhs rhs ?desc]
+  "Defines a new mapping using the lua API.
+  Supports all the options that the API supports."
+  (assert-compile (sym? modes) "expected symbol for modes" modes)
+  (assert-compile (tbl? options) "expected table for options" options)
+  (assert-compile (str? lhs) "expected string for lhs" lhs)
+  (assert-compile (or (str? rhs) (list? rhs) (fn? rhs) (sym? rhs))
+                  "expected string or list or function or symbol for rhs" rhs)
+  (assert-compile (or (nil? ?desc) (str? ?desc))
+                  "expected string or nil for description" ?desc)
+  (let [modes (icollect [char (gmatch (->str modes) ".")]
+                char)
+        options (collect [_ v (ipairs options)]
+                  (->str v)
+                  true)
+        rhs (if (and (not (fn? rhs)) (list? rhs)) `#,rhs rhs)
+        desc (if (and (not ?desc) (or (fn? rhs) (sym? rhs))) (view rhs) ?desc)
+        options (if desc (doto options (tset :desc desc)) options)]
+    `(vim.keymap.set ,modes ,lhs ,rhs ,options)))
+
+(lambda mapb! [[modes & options] lhs rhs ?description]
+  "Defines a new mapping using the lua API.
+  Supports all the options that the API supports.
+  Automatically sets the `:buffer` option."
+  (let [options (doto options
+                  (insert :buffer))]
+    (map! [modes (unpack options)] lhs rhs ?description)))
+
+{: map! : mapb!}
diff --git a/fnl/nvrc/macro/misc.fnl b/fnl/nvrc/macro/misc.fnl
new file mode 100644
index 0000000..cde60ce
--- /dev/null
+++ b/fnl/nvrc/macro/misc.fnl
@@ -0,0 +1 @@
+{:disable-builtins! #(vim.tbl_map #(tset vim.g (.. :loaded_ $) 1) $)}
diff --git a/fnl/nvrc/macro/pack.fnl b/fnl/nvrc/macro/pack.fnl
new file mode 100644
index 0000000..5ba7896
--- /dev/null
+++ b/fnl/nvrc/macro/pack.fnl
@@ -0,0 +1,80 @@
+(fn str? [x]
+  (= :string (type x)))
+
+(fn nil? [x]
+  (= nil x))
+
+(fn tbl? [x]
+  (= :table (type x)))
+
+(local {: format} string)
+(local {: insert} table)
+
+(global nvrc/pack [])
+(global nvrc/rock [])
+
+(lambda pack [identifier ?options]
+  "Returns a mixed table with the identifier as the first sequential element
+  and options as hash-table items.
+  See https://github.com/wbthomason/packer.nvim for information about the
+  options."
+  (assert-compile (str? identifier) "expected string for identifier" identifier)
+  (assert-compile (or (nil? ?options) (tbl? ?options))
+                  "expected table for options" ?options)
+  (let [options (or ?options {})
+        options (collect [k v (pairs options)]
+                         (if
+                           (= k :req) (values :config (format "require('nvrc.packs.%s')" v))
+                           (= k :init) (values :config (format "require('%s').setup()" v))
+                           (= k :defer) (values :setup (format "require('nvrc.utils').defer_unpack('%s', 5)" v))
+                           (values k v)))]
+    (doto options
+          (tset 1 identifier))))
+
+(lambda pack! [identifier ?options]
+  "Declares a plugin with its options.
+  This is a mixed table saved on the global compile-time variable nvrc/pack.
+  See https://github.com/wbthomason/packer.nvim for information about the
+  options."
+  (assert-compile (str? identifier) "expected string for identifier" identifier)
+  (assert-compile (or (nil? ?options) (tbl? ?options))
+                  "expected table for options" ?options)
+  (insert nvrc/pack (pack identifier ?options)))
+
+(lambda rock [identifier ?options]
+  "Returns a mixed table with the identifier as the first sequential element
+  and options as hash-table items.
+  See https://github.com/wbthomason/packer.nvim for information about the
+  options."
+  (assert-compile (str? identifier) "expected string for identifier" identifier)
+  (assert-compile (or (nil? ?options) (tbl? ?options))
+                  "expected table for options" ?options)
+  (let [options (or ?options {})]
+    (doto options
+          (tset 1 identifier))))
+
+(lambda rock! [identifier ?options]
+  "Declares a plugin with its options.
+  This is a mixed table saved on the global compile-time variable nvrc/rock.
+  See https://github.com/wbthomason/packer.nvim for information about the
+  options."
+  (assert-compile (str? identifier) "expected string for identifier" identifier)
+  (assert-compile (or (nil? ?options) (tbl? ?options))
+                  "expected table for options" ?options)
+  (insert nvrc/rock (rock identifier ?options)))
+
+(lambda unpack! []
+  "Initializes the plugin manager with the previously declared plugins and
+  their options."
+  (let [packs (icollect [_ v (ipairs nvrc/pack)]
+                        `(use ,v))
+        rocks (icollect [_ v (ipairs nvrc/rock)]
+                        `(use_rocks ,v))]
+    `((. (require :packer) :startup) #(do
+         ,(unpack (icollect [_ v (ipairs packs) :into rocks] v))))))
+
+{: pack
+ : pack!
+ : rock
+ : rock!
+ : unpack!}
diff --git a/fnl/nvrc/macro/set.fnl b/fnl/nvrc/macro/set.fnl
new file mode 100644
index 0000000..144bdef
--- /dev/null
+++ b/fnl/nvrc/macro/set.fnl
@@ -0,0 +1,79 @@
+(local {: fn? : gensym-checksum : vlua} (require :nvrc.macro.toolkit))
+
+(fn str? [x]
+  (= :string (type x)))
+
+(fn ->str [x]
+  (tostring x))
+
+(fn nil? [x]
+  (= nil x))
+
+(fn includes? [xs x]
+  (accumulate [is? false _ v (ipairs xs) :until is?]
+    (= v x)))
+
+(lambda set! [name ?value]
+  "Set a vim option via the lua API.
+  The name of the option must a symbol.
+  If no value is specified, if the name begins with 'no' the value
+  becomes false, true otherwise."
+  (assert-compile (sym? name) "expected symbol for name" name)
+  (let [name (->str name)
+        value (or ?value (not (name:match "^no")))
+        name (or (name:match "^no(.+)$") name)]
+    (if (fn? value)
+      (let [vsym (gensym-checksum "__" value)]
+        `(do
+            (global ,vsym ,value)
+            (tset vim.opt ,name ,(vlua vsym))))
+      (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)))))
+
+(lambda setl! [name ?value]
+  "Set a vim local option via the lua API.
+  The name of the option must a symbol.
+  If no value is specified, if the name begins with 'no' the value
+  becomes false, true otherwise."
+  (assert-compile (sym? name) "expected symbol for name" name)
+  (let [name (->str name)
+        value (or ?value
+                  (not (name:match "^no")))
+        name (or (name:match "^no(.+)$")
+                 name)]
+    (if (fn? value)
+      (let [fsym (gensym-checksum "__" value)]
+        `(do
+           (global ,fsym ,value)
+           (tset vim.opt_local ,name ,(vlua fsym))))
+      (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)))))
+
+(lambda setv! [name value]
+  "Set a vim variable via the lua API.
+  The name can be either a symbol or a string.
+  If the name begins with [gbwt] followed by [/:.], the name
+  is scoped to the respective scope."
+  (assert-compile (or (str? name) (sym? name))
+                  "expected string or symbol for name" name)
+  (let [name (->str name)
+        scope (when (includes? ["g/" "b/" "w/" "t/"
+                                "g." "b." "w." "t."
+                                "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)))
+
+{: set! : setl! : setv!}
diff --git a/fnl/nvrc/macro/thread.fnl b/fnl/nvrc/macro/thread.fnl
new file mode 100644
index 0000000..9060b04
--- /dev/null
+++ b/fnl/nvrc/macro/thread.fnl
@@ -0,0 +1,15 @@
+(local {: insert} table)
+
+(lambda as-> [[binding expr] ...]
+  "A threading macro where the first argument is the value binded to the
+  second argument, which must be a symbol.
+  This binding is valid for the whole body of the threading macro."
+  (assert-compile (sym? binding) "expected symbol for binding" binding)
+  `(let [,binding ,expr
+         ,(unpack (accumulate [exprs [] _ expr (ipairs [...])]
+                    (doto exprs
+                      (insert binding)
+                      (insert expr))))]
+     ,binding))
+
+{: as->}
diff --git a/fnl/nvrc/macro/toolkit.fnl b/fnl/nvrc/macro/toolkit.fnl
new file mode 100644
index 0000000..8a2bc50
--- /dev/null
+++ b/fnl/nvrc/macro/toolkit.fnl
@@ -0,0 +1,39 @@
+(local {: format} string)
+
+(fn ->str [x]
+  (tostring x))
+
+(fn head [xs]
+  (. xs 1))
+
+(fn fn? [x]
+  "Returns whether the parameter(s) is a function.
+  A function is defined as any list with 'fn or 'hashfn as
+  their first element."
+  (and (list? x) (or (= `fn (head x)) (= `hashfn (head x)))))
+
+(lambda gensym-checksum [...]
+  "Generates a new symbol from the checksum of the object
+  passed as a parameter.
+  The parameter first is casted into a string using the
+  function `fennel.view`.
+  If only one parameter is passed to the function the return
+  value is the checksum as a symbol.
+  If two parameters are passed, the first one is considered
+  the prefix.
+  If three parameters are passed, the first one is considered
+  the prefix and the last one is considered the suffix.
+  This function depends on the md5 library and the fennel library."
+  (match [...]
+    [prefix object suffix] (let [{: view} (require :fennel)
+                                 {:sumhexa md5} (require :md5)]
+                              (sym (.. prefix (md5 (view object)) suffix)))
+    [prefix object] (gensym-checksum prefix object "")
+    [object] (gensym-checksum "" object "")))
+
+(lambda vlua [x]
+  "Return a symbol mapped to `v:lua.%s()`, where `%s` is the symbol."
+  (assert-compile (sym? x) "expected symbol for x" x)
+  (format "v:lua.%s()" (->str x)))
+
+{: fn? : gensym-checksum : vlua}