From eded38c7b59447cff7598d6cd0d9ff89b501aaa6 Mon Sep 17 00:00:00 2001
From: sammyette <torchedsammy@gmail.com>
Date: Sat, 2 Dec 2023 12:35:12 -0400
Subject: [PATCH] feat: add completions for sudo

---
 .../{completions.lua => completions/init.lua} | 20 +++++++
 nature/completions/sudo.lua                   | 53 +++++++++++++++++++
 2 files changed, 73 insertions(+)
 rename nature/{completions.lua => completions/init.lua} (60%)
 create mode 100644 nature/completions/sudo.lua

diff --git a/nature/completions.lua b/nature/completions/init.lua
similarity index 60%
rename from nature/completions.lua
rename to nature/completions/init.lua
index f8127a1..a77a264 100644
--- a/nature/completions.lua
+++ b/nature/completions/init.lua
@@ -1,3 +1,23 @@
+local fs = require 'fs'
+
+-- explanation: this specific function gives to us info about
+-- the currently running source. this includes a path to the
+-- source file (info.source)
+-- we will use that to automatically load all commands by reading
+-- all the files in this dir and just requiring it.
+local info = debug.getinfo(1)
+local commandDir = fs.dir(info.source)
+if commandDir == '.' then return end
+
+local commands = fs.readdir(commandDir)
+for _, command in ipairs(commands) do
+	local name = command:gsub('%.lua', '') -- chop off extension
+	if name ~= 'init' then
+		-- skip this file (for obvious reasons)
+		require('nature.completions.' .. name)
+	end
+end
+
 function hilbish.completion.handler(line, pos)
 	if type(line) ~= 'string' then error '#1 must be a string' end
 	if type(pos) ~= 'number' then error '#2 must be a number' end
diff --git a/nature/completions/sudo.lua b/nature/completions/sudo.lua
new file mode 100644
index 0000000..5ca31e4
--- /dev/null
+++ b/nature/completions/sudo.lua
@@ -0,0 +1,53 @@
+local function curry(f)
+    return function (x) return function (y) return f(x,y) end end
+end
+
+local flags = {}
+local function flag(f, description)
+	flags[f] = {description}
+end
+
+local addflag = curry(flag)
+
+addflag '-A' 'Ask for password via askpass or $SUDO_ASKPASS'
+addflag '-B' 'Ring the bell as part of the password prompt.'
+
+hilbish.complete('command.sudo', function(query, ctx, fields)
+	table.remove(fields, 1)
+	local nonflags = table.filter(fields, function(v)
+		if v == '' then
+			return false
+		end
+		return v:match '^%-' == nil
+	end)
+
+	if #fields == 1 or #nonflags == 0 then
+		-- complete commands or sudo flags
+		if query:match ('^%-') then
+			local compFlags = {}
+			for flg, flgstuff in pairs(flags) do
+				if flg:match('^' .. query) then
+					compFlags[flg] = flgstuff
+				end
+			end
+
+			local compGroup = {
+				items = compFlags,
+				type = 'list'
+			}
+
+			return {compGroup}, query
+		end
+
+		local comps, pfx = hilbish.completion.bins(query, ctx, fields)
+		local compGroup = {
+			items = comps,
+			type = 'grid'
+		}
+
+		return {compGroup}, pfx
+	end
+
+	-- otherwise, get command flags
+	return hilbish.completion.call('command.' .. fields[2], query, ctx, fields)
+end)