From dca12e3ef28180c4dcade842d0a16bd8c7325f7c Mon Sep 17 00:00:00 2001
From: Russ Tokuyama <russtoku@gmail.com>
Date: Wed, 21 Aug 2024 10:02:24 -1000
Subject: [PATCH 1/2] Convert tree-sitter.fnl, timer.fnl, text.fnl, stack.fnl,
 and tests

---
 fnl/conjure-spec/stack_spec.fnl |  39 +++++++
 fnl/conjure-spec/text_spec.fnl  | 155 ++++++++++++++++++++++++++++
 fnl/conjure/stack.fnl           |  19 ++--
 fnl/conjure/text.fnl            |  47 +++++----
 fnl/conjure/timer.fnl           |  18 ++--
 fnl/conjure/tree-sitter.fnl     |  65 +++++++-----
 lua/conjure-spec/stack_spec.lua |  38 +++++++
 lua/conjure-spec/text_spec.lua  | 176 ++++++++++++++++++++++++++++++++
 lua/conjure/stack.lua           |  24 +----
 lua/conjure/text.lua            |  52 ++--------
 lua/conjure/timer.lua           |  26 +----
 lua/conjure/tree-sitter.lua     | 104 ++++++-------------
 12 files changed, 544 insertions(+), 219 deletions(-)
 create mode 100644 fnl/conjure-spec/stack_spec.fnl
 create mode 100644 fnl/conjure-spec/text_spec.fnl
 create mode 100644 lua/conjure-spec/stack_spec.lua
 create mode 100644 lua/conjure-spec/text_spec.lua

diff --git a/fnl/conjure-spec/stack_spec.fnl b/fnl/conjure-spec/stack_spec.fnl
new file mode 100644
index 00000000..cde80a8c
--- /dev/null
+++ b/fnl/conjure-spec/stack_spec.fnl
@@ -0,0 +1,39 @@
+(local {: describe : it} (require :plenary.busted))
+(local assert (require :luassert.assert))
+
+(local stack (require :conjure.stack))
+
+
+
+;;;;;;;;;;
+;;; module/file being tested
+(describe "conjure.stack"
+  (fn []
+    (describe "push"
+      (fn []
+        (it "item on a stack"
+          (fn []
+            (assert.same [1 2 3] (-> (stack.push [] 1)
+                                     (stack.push 2)
+                                     (stack.push 3)))))))
+
+    (describe "pop"
+      (fn []
+        (it "top of stack"
+          (fn []
+            (assert.same [1 2] (stack.pop [1 2 3]))))
+
+        (it "empty stack"
+          (fn []
+            (assert.same [] (stack.pop []))))))
+
+    (describe "peek"
+      (fn []
+        (it "top of stack"
+          (fn []
+            (assert.are.equals 3 (stack.peek [1 2 3]))))
+
+        (it "empty stack"
+          (fn []
+            (assert.are.equals nil (stack.peek []))))
+        ))))
diff --git a/fnl/conjure-spec/text_spec.fnl b/fnl/conjure-spec/text_spec.fnl
new file mode 100644
index 00000000..a812dfee
--- /dev/null
+++ b/fnl/conjure-spec/text_spec.fnl
@@ -0,0 +1,155 @@
+(local {: describe : it} (require :plenary.busted))
+(local assert (require :luassert.assert))
+(local text (require :conjure.text))
+
+(describe "text"
+  (fn []
+    (describe "left-sample"
+      (fn []
+        (it "handles empty strings"
+          (fn []
+            (assert.are.equals "" (text.left-sample "" 0))))
+
+        (it "handles single characters"
+          (fn []
+            (assert.are.equals "f" (text.left-sample "f" 1))))
+
+        (it "does nothing if correct"
+          (fn []
+            (assert.are.equals "foo bar" (text.left-sample "foo bar" 10))))
+
+        (it "replaces lots of whitespace with a space"
+          (fn []
+            (assert.are.equals "foo bar" (text.left-sample "foo    \n\n bar" 10))))
+
+        (it "cuts the string if too long"
+          (fn []
+            (assert.are.equals "foo bar b..." (text.left-sample "foo    \n\n bar \n\n baz" 10))))
+
+        (it "trims leading and trailing whitespace"
+          (fn []
+            (assert.are.equals "foo bar" (text.left-sample "   foo \n \n bar  \n" 10))))))
+
+    (describe "right-sample"
+      (fn []
+        (it "same as left-sample, but we want the right"
+          (fn []
+            (assert.are.equals "...o bar baz" (text.right-sample "foo    \n\n bar \n\n baz" 10))))))
+
+    (describe "split-lines"
+      (fn []
+        (it "nothing to nothing"
+          (fn []
+            (assert.same [""] (text.split-lines "") "")))
+
+        (it "basic split"
+          (fn []
+            (assert.same ["foo" "bar"] (text.split-lines "foo\nbar") "")))
+
+        (it "blank lines"
+          (fn []
+            (assert.same ["foo" "" "bar"] (text.split-lines "foo\n\nbar") "")))
+
+        (it "Windows CRLF"
+          (fn []
+            (assert.same ["foo" "bar"] (text.split-lines "foo\r\nbar") "")
+            ))))
+
+    (describe "prefixed-lines"
+      (fn []
+        (it "nothing to nothing"
+          (fn []
+            (assert.same ["; "] (text.prefixed-lines "" "; "))))
+
+        (it "single line"
+          (fn []
+            (assert.same ["; foo"] (text.prefixed-lines "foo" "; "))))
+
+        (it "multiple lines"
+          (fn []
+            (assert.same ["; foo" "; bar"] (text.prefixed-lines "foo\nbar" "; "))))))
+
+    (describe "starts-with"
+      (fn []
+        (it "foo"
+          (fn []
+            (assert.are.equals true (text.starts-with "foobar" "foo"))))
+
+        (it "foob"
+          (fn []
+            (assert.are.equals true (text.starts-with "foobar" "foob"))))
+
+        (it "foox"
+          (fn []
+            (assert.are.equals false (text.starts-with "foobar" "foox"))))
+
+        (it "ohno"
+          (fn []
+            (assert.are.equals nil (text.starts-with nil "ohno"))))))
+
+    (describe "ends-with"
+      (fn []
+        (it "bar"
+          (fn []
+            (assert.are.equals true (text.ends-with "foobar" "bar"))))
+
+        (it "obar"
+          (fn []
+            (assert.are.equals true (text.ends-with "foobar" "obar"))))
+
+        (it "xbar"
+          (fn []
+            (assert.are.equals false (text.ends-with "foobar" "xbar"))))
+
+        (it "ohno"
+          (fn []
+            (assert.are.equals nil (text.ends-with nil "ohno"))))))
+
+    (describe "first-and-last-chars"
+      (fn []
+        (it "of parentheses around words"
+          (fn []
+            (assert.are.equals "()" (text.first-and-last-chars "(hello-world)"))))
+        (it "of empty string"
+          (fn []
+            (assert.are.equals "" (text.first-and-last-chars ""))))
+        (it "of single opening parenthesis"
+          (fn []
+            (assert.are.equals "(" (text.first-and-last-chars "("))))
+        (it "of nil"
+          (fn []
+            (assert.are.equals nil (text.first-and-last-chars nil))))))
+
+    (describe "chars"
+      (fn []
+        (it "of nothing"
+          (fn []
+            (assert.same [] (text.chars))))
+        (it "of empty string"
+          (fn []
+            (assert.same [] (text.chars ""))))
+        (it "of \"abc\""
+          (fn []
+            (assert.same [:a :b :c] (text.chars "abc"))))))
+
+    (describe "upper-first"
+      (fn []
+        (it "of empty string"
+            (fn []
+              (assert.are.equals "" (text.upper-first ""))))
+        (it "of \"A\""
+            (fn []
+              (assert.are.equals "A" (text.upper-first "A"))))
+        (it "of \"a\""
+            (fn []
+              (assert.are.equals "A" (text.upper-first "a"))))
+        (it "of first word of many words"
+            (fn []
+              (assert.are.equals "Foo bar bAZ 5" (text.upper-first "foo bar bAZ 5"))))
+        (it "of nil"
+            (fn []
+              (assert.are.equals nil (text.upper-first nil))))
+        (it "of string of numbers"
+            (fn []
+              (assert.are.equals "123" (text.upper-first "123"))
+              ))))))
diff --git a/fnl/conjure/stack.fnl b/fnl/conjure/stack.fnl
index c7becaac..64de65c5 100644
--- a/fnl/conjure/stack.fnl
+++ b/fnl/conjure/stack.fnl
@@ -1,17 +1,20 @@
-(import-macros {: module : def : defn : defonce : def- : defn- : defonce- : wrap-last-expr : wrap-module-body : deftest} :nfnl.macros.aniseed)
+(local {: autoload} (require :nfnl.module))
+(local a (autoload :conjure.aniseed.core))
 
-(module conjure.stack
-  {autoload {a conjure.aniseed.core}})
-
-(defn push [s v]
+(fn push [s v]
   (table.insert s v)
   s)
 
-(defn pop [s]
+(fn pop [s]
   (table.remove s)
   s)
 
-(defn peek [s]
+(fn peek [s]
   (a.last s))
 
-*module*
+{
+ : push
+ : pop
+ : peek
+ }
+
diff --git a/fnl/conjure/text.fnl b/fnl/conjure/text.fnl
index 77116781..f8c89262 100644
--- a/fnl/conjure/text.fnl
+++ b/fnl/conjure/text.fnl
@@ -1,16 +1,14 @@
-(import-macros {: module : def : defn : defonce : def- : defn- : defonce- : wrap-last-expr : wrap-module-body : deftest} :nfnl.macros.aniseed)
+(local {: autoload} (require :nfnl.module))
+(local a (autoload :conjure.aniseed.core))
+(local str (autoload :conjure.aniseed.string))
 
-(module conjure.text
-  {require {a conjure.aniseed.core
-            str conjure.aniseed.string}})
-
-(defn trailing-newline? [s]
+(fn trailing-newline? [s]
   (string.match s "\r?\n$"))
 
-(defn trim-last-newline [s]
+(fn trim-last-newline [s]
   (string.gsub s "\r?\n$" ""))
 
-(defn left-sample [s limit]
+(fn left-sample [s limit]
   (let [flat (-> (string.gsub s "\n" " ")
                  (string.gsub "%s+" " ")
                  (str.trim))]
@@ -18,13 +16,13 @@
       flat
       (.. (string.sub flat 0 (a.dec limit)) "..."))))
 
-(defn right-sample [s limit]
+(fn right-sample [s limit]
   (string.reverse (left-sample (string.reverse s) limit)))
 
-(defn split-lines [s]
+(fn split-lines [s]
   (str.split s "\r?\n"))
 
-(defn prefixed-lines [s prefix opts]
+(fn prefixed-lines [s prefix opts]
   (->> (split-lines s)
        (a.map-indexed
          (fn [[n line]]
@@ -33,22 +31,22 @@
              line
              (.. prefix line))))))
 
-(defn starts-with [str start]
+(fn starts-with [str start]
   (when str
     (= (string.sub str 1 (a.count start)) start)))
 
-(defn ends-with [str end]
+(fn ends-with [str end]
   (when str
     (or (= end "") (= end (string.sub str (- (a.count end)))))))
 
-(defn first-and-last-chars [str]
+(fn first-and-last-chars [str]
   (when str
     (if (> (a.count str) 1)
       (.. (string.sub str 1 1)
           (string.sub str -1 -1))
       str)))
 
-(defn strip-ansi-escape-sequences [s]
+(fn strip-ansi-escape-sequences [s]
   (-> s
       (string.gsub "\x1b%[%d+;%d+;%d+;%d+;%d+m" "")
       (string.gsub "\x1b%[%d+;%d+;%d+;%d+m" "")
@@ -56,15 +54,28 @@
       (string.gsub "\x1b%[%d+;%d+m" "")
       (string.gsub "\x1b%[%d+m" "")))
 
-(defn chars [s]
+(fn chars [s]
   (local res [])
   (when s
     (each [c (string.gmatch s ".")]
       (table.insert res c)))
   res)
 
-(defn upper-first [s]
+(fn upper-first [s]
   (when s
     (s:gsub "^%l" string.upper)))
 
-*module*
+{
+ : trailing-newline?
+ : trim-last-newline
+ : left-sample
+ : right-sample
+ : split-lines
+ : prefixed-lines
+ : starts-with
+ : ends-with
+ : first-and-last-chars
+ : strip-ansi-escape-sequences
+ : chars
+ : upper-first
+ }
diff --git a/fnl/conjure/timer.fnl b/fnl/conjure/timer.fnl
index e4f81307..1006eb3f 100644
--- a/fnl/conjure/timer.fnl
+++ b/fnl/conjure/timer.fnl
@@ -1,18 +1,20 @@
-(import-macros {: module : def : defn : defonce : def- : defn- : defonce- : wrap-last-expr : wrap-module-body : deftest} :nfnl.macros.aniseed)
+(local {: autoload} (require :nfnl.module))
+(local a (autoload :conjure.aniseed.core))
+(local nvim (autoload :conjure.aniseed.nvim))
 
-(module conjure.timer
-  {autoload {a conjure.aniseed.core
-             nvim conjure.aniseed.nvim}})
-
-(defn defer [f ms]
+(fn defer [f ms]
+  ;; vim.loop is deprecated in Neovim 0.10. Use vim.uv instead.
   (let [t (vim.loop.new_timer)]
     (t:start ms 0 (vim.schedule_wrap f))
     t))
 
-(defn destroy [t]
+(fn destroy [t]
   (when t
     (t:stop)
     (t:close))
   nil)
 
-*module*
+{
+ : defer
+ : destroy
+ }
diff --git a/fnl/conjure/tree-sitter.fnl b/fnl/conjure/tree-sitter.fnl
index 85eb6e29..c5db0df4 100644
--- a/fnl/conjure/tree-sitter.fnl
+++ b/fnl/conjure/tree-sitter.fnl
@@ -1,21 +1,18 @@
-(import-macros {: module : def : defn : defonce : def- : defn- : defonce- : wrap-last-expr : wrap-module-body : deftest} :nfnl.macros.aniseed)
-
-(module conjure.tree-sitter
-  {autoload {a conjure.aniseed.core
-             str conjure.aniseed.string
-             nvim conjure.aniseed.nvim
-             client conjure.client
-             config conjure.config
-             text conjure.text}})
+(local {: autoload} (require :nfnl.module))
+(local a (autoload :nfnl.core))
+(local nvim (autoload :conjure.aniseed.nvim))
+(local client (autoload :conjure.client))
+(local config (autoload :conjure.config))
+(local text (autoload :conjure.text))
 
 ;; Initially based on https://github.com/savq/conjure-julia <3
 
-(def- ts
+(local ts
   (let [(ok? x) (pcall #(require :nvim-treesitter.ts_utils))]
     (when ok?
       x)))
 
-(defn enabled? []
+(fn enabled? []
   "Do we have tree-sitter support in the current nvim, buffer and filetype. If
   this is false, you might need to install
   https://github.com/nvim-treesitter/nvim-treesitter
@@ -30,12 +27,12 @@
     true
     false))
 
-(defn parse! []
+(fn parse! []
   (let [(ok? parser) (pcall vim.treesitter.get_parser)]
     (if ok?
       (parser:parse))))
 
-(defn node->str [node]
+(fn node->str [node]
   "Turn the node into a string, nils flow through. Separate forms are joined by
   new lines."
   (when node
@@ -43,27 +40,27 @@
       (vim.treesitter.get_node_text node (nvim.get_current_buf))
       (vim.treesitter.query.get_node_text node (nvim.get_current_buf)))))
 
-(defn lisp-comment-node? [node]
+(fn lisp-comment-node? [node]
   "Node is a (comment ...) form"
   (text.starts-with (node->str node) "(comment"))
 
-(defn parent [node]
+(fn parent [node]
   "Get the parent if possible."
   (when node
     (node:parent)))
 
-(defn document? [node]
+(fn document? [node]
   "Is the node the entire document, i.e. has no parent?"
   (not (parent node)))
 
-(defn range [node]
+(fn range [node]
   "Get the character range of the form."
   (when node
     (let [(sr sc er ec) (node:range)]
       {:start [(a.inc sr) sc]
        :end [(a.inc er) (a.dec ec)]})))
 
-(defn node->table [node]
+(fn node->table [node]
   "If it is a node, convert it to a Lua table we can work with in Conjure. If
   it's already a table with the right keys just return that."
   (if
@@ -76,7 +73,7 @@
 
     nil))
 
-(defn get-root [node]
+(fn get-root [node]
   "Get the root node below the entire document."
   (parse!)
 
@@ -88,7 +85,7 @@
       (client.optional-call :comment-node? parent-node) node
       (get-root parent-node))))
 
-(defn leaf? [node]
+(fn leaf? [node]
   "Does the node have any children? Or is it the end of the tree?"
   (when node
     (= 0 (node:child_count))))
@@ -96,12 +93,12 @@
 ;; Some node types I've seen: sym_lit, symbol, multi_symbol...
 ;; So I'm not sure if each language just picks a flavour, but this should cover all of our bases.
 ;; Clients can also opt in and hint with their own symbol-node? functions now too.
-(defn sym? [node]
+(fn sym? [node]
   (when node
     (or (string.find (node:type) :sym)
         (client.optional-call :symbol-node? node))))
 
-(defn get-leaf [node]
+(fn get-leaf [node]
   "Return the leaf node under the cursor or nothing at all."
   (parse!)
 
@@ -112,7 +109,7 @@
         (set node (parent node)))
       node)))
 
-(defn node-surrounded-by-form-pair-chars? [node extra-pairs]
+(fn node-surrounded-by-form-pair-chars? [node extra-pairs]
   (let [node-str (node->str node)
         first-and-last-chars (text.first-and-last-chars node-str)]
     (or (a.some
@@ -126,7 +123,7 @@
           extra-pairs)
         false)))
 
-(defn node-prefixed-by-chars? [node prefixes]
+(fn node-prefixed-by-chars? [node prefixes]
   (let [node-str (node->str node)]
     (or (a.some
           (fn [prefix]
@@ -134,7 +131,7 @@
           prefixes)
         false)))
 
-(defn get-form [node]
+(fn get-form [node]
   "Get the current form under the cursor. Walks up until it finds a non-leaf.
 
   Warning, this can return a table containing content and range! Use
@@ -197,4 +194,20 @@
             (a.println "Warning: Conjure client returned an unknown get-form-modifier" res)
             node))))))
 
-*module*
+{
+ : enabled?
+ : parse!
+ : node->str
+ : lisp-comment-node?
+ : parent
+ : document?
+ : range
+ : node->table
+ : get-root
+ : leaf?
+ : sym?
+ : get-leaf
+ : node-surrounded-by-form-pair-chars?
+ : node-prefixed-by-chars?
+ : get-form
+ }
diff --git a/lua/conjure-spec/stack_spec.lua b/lua/conjure-spec/stack_spec.lua
new file mode 100644
index 00000000..8e0379b7
--- /dev/null
+++ b/lua/conjure-spec/stack_spec.lua
@@ -0,0 +1,38 @@
+-- [nfnl] Compiled from fnl/conjure-spec/stack_spec.fnl by https://github.com/Olical/nfnl, do not edit.
+local _local_1_ = require("plenary.busted")
+local describe = _local_1_["describe"]
+local it = _local_1_["it"]
+local assert = require("luassert.assert")
+local stack = require("conjure.stack")
+local function _2_()
+  local function _3_()
+    local function _4_()
+      return assert.same({1, 2, 3}, stack.push(stack.push(stack.push({}, 1), 2), 3))
+    end
+    return it("item on a stack", _4_)
+  end
+  describe("push", _3_)
+  local function _5_()
+    local function _6_()
+      return assert.same({1, 2}, stack.pop({1, 2, 3}))
+    end
+    it("top of stack", _6_)
+    local function _7_()
+      return assert.same({}, stack.pop({}))
+    end
+    return it("empty stack", _7_)
+  end
+  describe("pop", _5_)
+  local function _8_()
+    local function _9_()
+      return assert.are.equals(3, stack.peek({1, 2, 3}))
+    end
+    it("top of stack", _9_)
+    local function _10_()
+      return assert.are.equals(nil, stack.peek({}))
+    end
+    return it("empty stack", _10_)
+  end
+  return describe("peek", _8_)
+end
+return describe("conjure.stack", _2_)
diff --git a/lua/conjure-spec/text_spec.lua b/lua/conjure-spec/text_spec.lua
new file mode 100644
index 00000000..79d5c4d9
--- /dev/null
+++ b/lua/conjure-spec/text_spec.lua
@@ -0,0 +1,176 @@
+-- [nfnl] Compiled from fnl/conjure-spec/text_spec.fnl by https://github.com/Olical/nfnl, do not edit.
+local _local_1_ = require("plenary.busted")
+local describe = _local_1_["describe"]
+local it = _local_1_["it"]
+local assert = require("luassert.assert")
+local text = require("conjure.text")
+local function _2_()
+  local function _3_()
+    local function _4_()
+      return assert.are.equals("", text["left-sample"]("", 0))
+    end
+    it("handles empty strings", _4_)
+    local function _5_()
+      return assert.are.equals("f", text["left-sample"]("f", 1))
+    end
+    it("handles single characters", _5_)
+    local function _6_()
+      return assert.are.equals("foo bar", text["left-sample"]("foo bar", 10))
+    end
+    it("does nothing if correct", _6_)
+    local function _7_()
+      return assert.are.equals("foo bar", text["left-sample"]("foo    \n\n bar", 10))
+    end
+    it("replaces lots of whitespace with a space", _7_)
+    local function _8_()
+      return assert.are.equals("foo bar b...", text["left-sample"]("foo    \n\n bar \n\n baz", 10))
+    end
+    it("cuts the string if too long", _8_)
+    local function _9_()
+      return assert.are.equals("foo bar", text["left-sample"]("   foo \n \n bar  \n", 10))
+    end
+    return it("trims leading and trailing whitespace", _9_)
+  end
+  describe("left-sample", _3_)
+  local function _10_()
+    local function _11_()
+      return assert.are.equals("...o bar baz", text["right-sample"]("foo    \n\n bar \n\n baz", 10))
+    end
+    return it("same as left-sample, but we want the right", _11_)
+  end
+  describe("right-sample", _10_)
+  local function _12_()
+    local function _13_()
+      return assert.same({""}, text["split-lines"](""), "")
+    end
+    it("nothing to nothing", _13_)
+    local function _14_()
+      return assert.same({"foo", "bar"}, text["split-lines"]("foo\nbar"), "")
+    end
+    it("basic split", _14_)
+    local function _15_()
+      return assert.same({"foo", "", "bar"}, text["split-lines"]("foo\n\nbar"), "")
+    end
+    it("blank lines", _15_)
+    local function _16_()
+      return assert.same({"foo", "bar"}, text["split-lines"]("foo\13\nbar"), "")
+    end
+    return it("Windows CRLF", _16_)
+  end
+  describe("split-lines", _12_)
+  local function _17_()
+    local function _18_()
+      return assert.same({"; "}, text["prefixed-lines"]("", "; "))
+    end
+    it("nothing to nothing", _18_)
+    local function _19_()
+      return assert.same({"; foo"}, text["prefixed-lines"]("foo", "; "))
+    end
+    it("single line", _19_)
+    local function _20_()
+      return assert.same({"; foo", "; bar"}, text["prefixed-lines"]("foo\nbar", "; "))
+    end
+    return it("multiple lines", _20_)
+  end
+  describe("prefixed-lines", _17_)
+  local function _21_()
+    local function _22_()
+      return assert.are.equals(true, text["starts-with"]("foobar", "foo"))
+    end
+    it("foo", _22_)
+    local function _23_()
+      return assert.are.equals(true, text["starts-with"]("foobar", "foob"))
+    end
+    it("foob", _23_)
+    local function _24_()
+      return assert.are.equals(false, text["starts-with"]("foobar", "foox"))
+    end
+    it("foox", _24_)
+    local function _25_()
+      return assert.are.equals(nil, text["starts-with"](nil, "ohno"))
+    end
+    return it("ohno", _25_)
+  end
+  describe("starts-with", _21_)
+  local function _26_()
+    local function _27_()
+      return assert.are.equals(true, text["ends-with"]("foobar", "bar"))
+    end
+    it("bar", _27_)
+    local function _28_()
+      return assert.are.equals(true, text["ends-with"]("foobar", "obar"))
+    end
+    it("obar", _28_)
+    local function _29_()
+      return assert.are.equals(false, text["ends-with"]("foobar", "xbar"))
+    end
+    it("xbar", _29_)
+    local function _30_()
+      return assert.are.equals(nil, text["ends-with"](nil, "ohno"))
+    end
+    return it("ohno", _30_)
+  end
+  describe("ends-with", _26_)
+  local function _31_()
+    local function _32_()
+      return assert.are.equals("()", text["first-and-last-chars"]("(hello-world)"))
+    end
+    it("of parentheses around words", _32_)
+    local function _33_()
+      return assert.are.equals("", text["first-and-last-chars"](""))
+    end
+    it("of empty string", _33_)
+    local function _34_()
+      return assert.are.equals("(", text["first-and-last-chars"]("("))
+    end
+    it("of single opening parenthesis", _34_)
+    local function _35_()
+      return assert.are.equals(nil, text["first-and-last-chars"](nil))
+    end
+    return it("of nil", _35_)
+  end
+  describe("first-and-last-chars", _31_)
+  local function _36_()
+    local function _37_()
+      return assert.same({}, text.chars())
+    end
+    it("of nothing", _37_)
+    local function _38_()
+      return assert.same({}, text.chars(""))
+    end
+    it("of empty string", _38_)
+    local function _39_()
+      return assert.same({"a", "b", "c"}, text.chars("abc"))
+    end
+    return it("of \"abc\"", _39_)
+  end
+  describe("chars", _36_)
+  local function _40_()
+    local function _41_()
+      return assert.are.equals("", text["upper-first"](""))
+    end
+    it("of empty string", _41_)
+    local function _42_()
+      return assert.are.equals("A", text["upper-first"]("A"))
+    end
+    it("of \"A\"", _42_)
+    local function _43_()
+      return assert.are.equals("A", text["upper-first"]("a"))
+    end
+    it("of \"a\"", _43_)
+    local function _44_()
+      return assert.are.equals("Foo bar bAZ 5", text["upper-first"]("foo bar bAZ 5"))
+    end
+    it("of first word of many words", _44_)
+    local function _45_()
+      return assert.are.equals(nil, text["upper-first"](nil))
+    end
+    it("of nil", _45_)
+    local function _46_()
+      return assert.are.equals("123", text["upper-first"]("123"))
+    end
+    return it("of string of numbers", _46_)
+  end
+  return describe("upper-first", _40_)
+end
+return describe("text", _2_)
diff --git a/lua/conjure/stack.lua b/lua/conjure/stack.lua
index e081c7c1..52861e5b 100644
--- a/lua/conjure/stack.lua
+++ b/lua/conjure/stack.lua
@@ -1,34 +1,16 @@
 -- [nfnl] Compiled from fnl/conjure/stack.fnl by https://github.com/Olical/nfnl, do not edit.
-local _2amodule_name_2a = "conjure.stack"
-local _2amodule_2a
-do
-  _G.package.loaded[_2amodule_name_2a] = {}
-  _2amodule_2a = _G.package.loaded[_2amodule_name_2a]
-end
-local _2amodule_locals_2a
-do
-  _2amodule_2a["aniseed/locals"] = {}
-  _2amodule_locals_2a = (_2amodule_2a)["aniseed/locals"]
-end
-local autoload = (require("aniseed.autoload")).autoload
+local _local_1_ = require("nfnl.module")
+local autoload = _local_1_["autoload"]
 local a = autoload("conjure.aniseed.core")
-do end (_2amodule_locals_2a)["a"] = a
-do local _ = {nil, nil, nil, nil, nil, nil} end
 local function push(s, v)
   table.insert(s, v)
   return s
 end
-_2amodule_2a["push"] = push
-do local _ = {push, nil} end
 local function pop(s)
   table.remove(s)
   return s
 end
-_2amodule_2a["pop"] = pop
-do local _ = {pop, nil} end
 local function peek(s)
   return a.last(s)
 end
-_2amodule_2a["peek"] = peek
-do local _ = {peek, nil} end
-return _2amodule_2a
+return {push = push, pop = pop, peek = peek}
diff --git a/lua/conjure/text.lua b/lua/conjure/text.lua
index 7ec5d137..74ce739c 100644
--- a/lua/conjure/text.lua
+++ b/lua/conjure/text.lua
@@ -1,29 +1,14 @@
 -- [nfnl] Compiled from fnl/conjure/text.fnl by https://github.com/Olical/nfnl, do not edit.
-local _2amodule_name_2a = "conjure.text"
-local _2amodule_2a
-do
-  _G.package.loaded[_2amodule_name_2a] = {}
-  _2amodule_2a = _G.package.loaded[_2amodule_name_2a]
-end
-local _2amodule_locals_2a
-do
-  _2amodule_2a["aniseed/locals"] = {}
-  _2amodule_locals_2a = (_2amodule_2a)["aniseed/locals"]
-end
-local a, str = require("conjure.aniseed.core"), require("conjure.aniseed.string")
-do end (_2amodule_locals_2a)["a"] = a
-_2amodule_locals_2a["str"] = str
-do local _ = {nil, nil, nil, nil, nil, nil} end
+local _local_1_ = require("nfnl.module")
+local autoload = _local_1_["autoload"]
+local a = autoload("conjure.aniseed.core")
+local str = autoload("conjure.aniseed.string")
 local function trailing_newline_3f(s)
   return string.match(s, "\13?\n$")
 end
-_2amodule_2a["trailing-newline?"] = trailing_newline_3f
-do local _ = {trailing_newline_3f, nil} end
 local function trim_last_newline(s)
   return string.gsub(s, "\13?\n$", "")
 end
-_2amodule_2a["trim-last-newline"] = trim_last_newline
-do local _ = {trim_last_newline, nil} end
 local function left_sample(s, limit)
   local flat = str.trim(string.gsub(string.gsub(s, "\n", " "), "%s+", " "))
   if (limit >= a.count(flat)) then
@@ -32,23 +17,16 @@ local function left_sample(s, limit)
     return (string.sub(flat, 0, a.dec(limit)) .. "...")
   end
 end
-_2amodule_2a["left-sample"] = left_sample
-do local _ = {left_sample, nil} end
 local function right_sample(s, limit)
   return string.reverse(left_sample(string.reverse(s), limit))
 end
-_2amodule_2a["right-sample"] = right_sample
-do local _ = {right_sample, nil} end
 local function split_lines(s)
   return str.split(s, "\13?\n")
 end
-_2amodule_2a["split-lines"] = split_lines
-do local _ = {split_lines, nil} end
 local function prefixed_lines(s, prefix, opts)
-  local function _4_(_2_)
-    local _arg_3_ = _2_
-    local n = _arg_3_[1]
-    local line = _arg_3_[2]
+  local function _4_(_3_)
+    local n = _3_[1]
+    local line = _3_[2]
     if ((1 == n) and a.get(opts, "skip-first?")) then
       return line
     else
@@ -57,8 +35,6 @@ local function prefixed_lines(s, prefix, opts)
   end
   return a["map-indexed"](_4_, split_lines(s))
 end
-_2amodule_2a["prefixed-lines"] = prefixed_lines
-do local _ = {prefixed_lines, nil} end
 local function starts_with(str0, start)
   if str0 then
     return (string.sub(str0, 1, a.count(start)) == start)
@@ -66,8 +42,6 @@ local function starts_with(str0, start)
     return nil
   end
 end
-_2amodule_2a["starts-with"] = starts_with
-do local _ = {starts_with, nil} end
 local function ends_with(str0, _end)
   if str0 then
     return ((_end == "") or (_end == string.sub(str0, ( - a.count(_end)))))
@@ -75,8 +49,6 @@ local function ends_with(str0, _end)
     return nil
   end
 end
-_2amodule_2a["ends-with"] = ends_with
-do local _ = {ends_with, nil} end
 local function first_and_last_chars(str0)
   if str0 then
     if (a.count(str0) > 1) then
@@ -88,13 +60,9 @@ local function first_and_last_chars(str0)
     return nil
   end
 end
-_2amodule_2a["first-and-last-chars"] = first_and_last_chars
-do local _ = {first_and_last_chars, nil} end
 local function strip_ansi_escape_sequences(s)
   return string.gsub(string.gsub(string.gsub(string.gsub(string.gsub(s, "\27%[%d+;%d+;%d+;%d+;%d+m", ""), "\27%[%d+;%d+;%d+;%d+m", ""), "\27%[%d+;%d+;%d+m", ""), "\27%[%d+;%d+m", ""), "\27%[%d+m", "")
 end
-_2amodule_2a["strip-ansi-escape-sequences"] = strip_ansi_escape_sequences
-do local _ = {strip_ansi_escape_sequences, nil} end
 local function chars(s)
   local res = {}
   if s then
@@ -105,8 +73,6 @@ local function chars(s)
   end
   return res
 end
-_2amodule_2a["chars"] = chars
-do local _ = {chars, nil} end
 local function upper_first(s)
   if s then
     return s:gsub("^%l", string.upper)
@@ -114,6 +80,4 @@ local function upper_first(s)
     return nil
   end
 end
-_2amodule_2a["upper-first"] = upper_first
-do local _ = {upper_first, nil} end
-return _2amodule_2a
+return {["trailing-newline?"] = trailing_newline_3f, ["trim-last-newline"] = trim_last_newline, ["left-sample"] = left_sample, ["right-sample"] = right_sample, ["split-lines"] = split_lines, ["prefixed-lines"] = prefixed_lines, ["starts-with"] = starts_with, ["ends-with"] = ends_with, ["first-and-last-chars"] = first_and_last_chars, ["strip-ansi-escape-sequences"] = strip_ansi_escape_sequences, chars = chars, ["upper-first"] = upper_first}
diff --git a/lua/conjure/timer.lua b/lua/conjure/timer.lua
index 02769ece..71eb8362 100644
--- a/lua/conjure/timer.lua
+++ b/lua/conjure/timer.lua
@@ -1,27 +1,13 @@
 -- [nfnl] Compiled from fnl/conjure/timer.fnl by https://github.com/Olical/nfnl, do not edit.
-local _2amodule_name_2a = "conjure.timer"
-local _2amodule_2a
-do
-  _G.package.loaded[_2amodule_name_2a] = {}
-  _2amodule_2a = _G.package.loaded[_2amodule_name_2a]
-end
-local _2amodule_locals_2a
-do
-  _2amodule_2a["aniseed/locals"] = {}
-  _2amodule_locals_2a = (_2amodule_2a)["aniseed/locals"]
-end
-local autoload = (require("aniseed.autoload")).autoload
-local a, nvim = autoload("conjure.aniseed.core"), autoload("conjure.aniseed.nvim")
-do end (_2amodule_locals_2a)["a"] = a
-_2amodule_locals_2a["nvim"] = nvim
-do local _ = {nil, nil, nil, nil, nil, nil, nil} end
+local _local_1_ = require("nfnl.module")
+local autoload = _local_1_["autoload"]
+local a = autoload("conjure.aniseed.core")
+local nvim = autoload("conjure.aniseed.nvim")
 local function defer(f, ms)
   local t = vim.loop.new_timer()
   t:start(ms, 0, vim.schedule_wrap(f))
   return t
 end
-_2amodule_2a["defer"] = defer
-do local _ = {defer, nil} end
 local function destroy(t)
   if t then
     t:stop()
@@ -30,6 +16,4 @@ local function destroy(t)
   end
   return nil
 end
-_2amodule_2a["destroy"] = destroy
-do local _ = {destroy, nil} end
-return _2amodule_2a
+return {defer = defer, destroy = destroy}
diff --git a/lua/conjure/tree-sitter.lua b/lua/conjure/tree-sitter.lua
index 5f0048b7..e663c97a 100644
--- a/lua/conjure/tree-sitter.lua
+++ b/lua/conjure/tree-sitter.lua
@@ -1,52 +1,36 @@
 -- [nfnl] Compiled from fnl/conjure/tree-sitter.fnl by https://github.com/Olical/nfnl, do not edit.
-local _2amodule_name_2a = "conjure.tree-sitter"
-local _2amodule_2a
-do
-  _G.package.loaded[_2amodule_name_2a] = {}
-  _2amodule_2a = _G.package.loaded[_2amodule_name_2a]
-end
-local _2amodule_locals_2a
-do
-  _2amodule_2a["aniseed/locals"] = {}
-  _2amodule_locals_2a = (_2amodule_2a)["aniseed/locals"]
-end
-local autoload = (require("aniseed.autoload")).autoload
-local a, client, config, nvim, str, text = autoload("conjure.aniseed.core"), autoload("conjure.client"), autoload("conjure.config"), autoload("conjure.aniseed.nvim"), autoload("conjure.aniseed.string"), autoload("conjure.text")
-do end (_2amodule_locals_2a)["a"] = a
-_2amodule_locals_2a["client"] = client
-_2amodule_locals_2a["config"] = config
-_2amodule_locals_2a["nvim"] = nvim
-_2amodule_locals_2a["str"] = str
-_2amodule_locals_2a["text"] = text
-do local _ = {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil} end
+local _local_1_ = require("nfnl.module")
+local autoload = _local_1_["autoload"]
+local a = autoload("nfnl.core")
+local nvim = autoload("conjure.aniseed.nvim")
+local client = autoload("conjure.client")
+local config = autoload("conjure.config")
+local text = autoload("conjure.text")
 local ts
 do
   local ok_3f, x = nil, nil
-  local function _1_()
+  local function _2_()
     return require("nvim-treesitter.ts_utils")
   end
-  ok_3f, x = pcall(_1_)
+  ok_3f, x = pcall(_2_)
   if ok_3f then
     ts = x
   else
     ts = nil
   end
 end
-_2amodule_locals_2a["ts"] = ts
-do local _ = {nil, nil} end
 local function enabled_3f()
-  local function _3_()
+  local and_4_ = ("table" == type(ts)) and config["get-in"]({"extract", "tree_sitter", "enabled"})
+  if and_4_ then
     local ok_3f, parser = pcall(vim.treesitter.get_parser)
-    return (ok_3f and parser)
+    and_4_ = (ok_3f and parser)
   end
-  if (("table" == type(ts)) and config["get-in"]({"extract", "tree_sitter", "enabled"}) and _3_()) then
+  if and_4_ then
     return true
   else
     return false
   end
 end
-_2amodule_2a["enabled?"] = enabled_3f
-do local _ = {enabled_3f, nil} end
 local function parse_21()
   local ok_3f, parser = pcall(vim.treesitter.get_parser)
   if ok_3f then
@@ -55,8 +39,6 @@ local function parse_21()
     return nil
   end
 end
-_2amodule_2a["parse!"] = parse_21
-do local _ = {parse_21, nil} end
 local function node__3estr(node)
   if node then
     if vim.treesitter.get_node_text then
@@ -68,13 +50,9 @@ local function node__3estr(node)
     return nil
   end
 end
-_2amodule_2a["node->str"] = node__3estr
-do local _ = {node__3estr, nil} end
 local function lisp_comment_node_3f(node)
   return text["starts-with"](node__3estr(node), "(comment")
 end
-_2amodule_2a["lisp-comment-node?"] = lisp_comment_node_3f
-do local _ = {lisp_comment_node_3f, nil} end
 local function parent(node)
   if node then
     return node:parent()
@@ -82,13 +60,9 @@ local function parent(node)
     return nil
   end
 end
-_2amodule_2a["parent"] = parent
-do local _ = {parent, nil} end
 local function document_3f(node)
   return not parent(node)
 end
-_2amodule_2a["document?"] = document_3f
-do local _ = {document_3f, nil} end
 local function range(node)
   if node then
     local sr, sc, er, ec = node:range()
@@ -97,8 +71,6 @@ local function range(node)
     return nil
   end
 end
-_2amodule_2a["range"] = range
-do local _ = {range, nil} end
 local function node__3etable(node)
   if (a.get(node, "range") and a.get(node, "content")) then
     return node
@@ -108,8 +80,6 @@ local function node__3etable(node)
     return nil
   end
 end
-_2amodule_2a["node->table"] = node__3etable
-do local _ = {node__3etable, nil} end
 local function get_root(node)
   parse_21()
   local node0 = (node or ts.get_node_at_cursor())
@@ -124,8 +94,6 @@ local function get_root(node)
     return get_root(parent_node)
   end
 end
-_2amodule_2a["get-root"] = get_root
-do local _ = {get_root, nil} end
 local function leaf_3f(node)
   if node then
     return (0 == node:child_count())
@@ -133,8 +101,6 @@ local function leaf_3f(node)
     return nil
   end
 end
-_2amodule_2a["leaf?"] = leaf_3f
-do local _ = {leaf_3f, nil} end
 local function sym_3f(node)
   if node then
     return (string.find(node:type(), "sym") or client["optional-call"]("symbol-node?", node))
@@ -142,8 +108,6 @@ local function sym_3f(node)
     return nil
   end
 end
-_2amodule_2a["sym?"] = sym_3f
-do local _ = {sym_3f, nil} end
 local function get_leaf(node)
   parse_21()
   local node0 = (node or ts.get_node_at_cursor())
@@ -157,36 +121,32 @@ local function get_leaf(node)
     return nil
   end
 end
-_2amodule_2a["get-leaf"] = get_leaf
-do local _ = {get_leaf, nil} end
 local function node_surrounded_by_form_pair_chars_3f(node, extra_pairs)
   local node_str = node__3estr(node)
   local first_and_last_chars = text["first-and-last-chars"](node_str)
-  local function _17_(_15_)
-    local _arg_16_ = _15_
-    local start = _arg_16_[1]
-    local _end = _arg_16_[2]
+  local function _18_(_17_)
+    local start = _17_[1]
+    local _end = _17_[2]
     return (first_and_last_chars == (start .. _end))
   end
-  local function _20_(_18_)
-    local _arg_19_ = _18_
-    local start = _arg_19_[1]
-    local _end = _arg_19_[2]
-    return (text["starts-with"](node_str, start) and text["ends-with"](node_str, _end))
+  local or_19_ = a.some(_18_, config["get-in"]({"extract", "form_pairs"}))
+  if not or_19_ then
+    local function _21_(_20_)
+      local start = _20_[1]
+      local _end = _20_[2]
+      return (text["starts-with"](node_str, start) and text["ends-with"](node_str, _end))
+    end
+    or_19_ = a.some(_21_, extra_pairs)
   end
-  return (a.some(_17_, config["get-in"]({"extract", "form_pairs"})) or a.some(_20_, extra_pairs) or false)
+  return (or_19_ or false)
 end
-_2amodule_2a["node-surrounded-by-form-pair-chars?"] = node_surrounded_by_form_pair_chars_3f
-do local _ = {node_surrounded_by_form_pair_chars_3f, nil} end
 local function node_prefixed_by_chars_3f(node, prefixes)
   local node_str = node__3estr(node)
-  local function _21_(prefix)
+  local function _22_(prefix)
     return text["starts-with"](node_str, prefix)
   end
-  return (a.some(_21_, prefixes) or false)
+  return (a.some(_22_, prefixes) or false)
 end
-_2amodule_2a["node-prefixed-by-chars?"] = node_prefixed_by_chars_3f
-do local _ = {node_prefixed_by_chars_3f, nil} end
 local function get_form(node)
   if not node then
     parse_21()
@@ -198,9 +158,9 @@ local function get_form(node)
   elseif (leaf_3f(node0) or (false == client["optional-call"]("form-node?", node0))) then
     return get_form(parent(node0))
   else
-    local _let_23_ = (client["optional-call"]("get-form-modifier", node0) or {})
-    local modifier = _let_23_["modifier"]
-    local res = _let_23_
+    local _let_24_ = (client["optional-call"]("get-form-modifier", node0) or {})
+    local modifier = _let_24_["modifier"]
+    local res = _let_24_
     if (not modifier or ("none" == modifier)) then
       return node0
     elseif ("parent" == modifier) then
@@ -215,6 +175,4 @@ local function get_form(node)
     end
   end
 end
-_2amodule_2a["get-form"] = get_form
-do local _ = {get_form, nil} end
-return _2amodule_2a
+return {["enabled?"] = enabled_3f, ["parse!"] = parse_21, ["node->str"] = node__3estr, ["lisp-comment-node?"] = lisp_comment_node_3f, parent = parent, ["document?"] = document_3f, range = range, ["node->table"] = node__3etable, ["get-root"] = get_root, ["leaf?"] = leaf_3f, ["sym?"] = sym_3f, ["get-leaf"] = get_leaf, ["node-surrounded-by-form-pair-chars?"] = node_surrounded_by_form_pair_chars_3f, ["node-prefixed-by-chars?"] = node_prefixed_by_chars_3f, ["get-form"] = get_form}

From 842f06595c75301e130f2680fc648b8ba27de9bc Mon Sep 17 00:00:00 2001
From: Russ Tokuyama <russtoku@gmail.com>
Date: Wed, 21 Aug 2024 13:54:47 -1000
Subject: [PATCH 2/2] Remove unnecessary comment from stack_spec.fnl

---
 fnl/conjure-spec/stack_spec.fnl | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/fnl/conjure-spec/stack_spec.fnl b/fnl/conjure-spec/stack_spec.fnl
index cde80a8c..4494a413 100644
--- a/fnl/conjure-spec/stack_spec.fnl
+++ b/fnl/conjure-spec/stack_spec.fnl
@@ -1,12 +1,7 @@
 (local {: describe : it} (require :plenary.busted))
 (local assert (require :luassert.assert))
-
 (local stack (require :conjure.stack))
 
-
-
-;;;;;;;;;;
-;;; module/file being tested
 (describe "conjure.stack"
   (fn []
     (describe "push"