]> git.newer.systems - setclass.git/commitdiff
init
authorTucker Johnson <tucker@newer.systems>
Wed, 18 Jun 2025 20:32:18 +0000 (16:32 -0400)
committerTucker Johnson <tucker@newer.systems>
Wed, 18 Jun 2025 20:32:18 +0000 (16:32 -0400)
.gitignore [new file with mode: 0644]
core.lua [new file with mode: 0644]
init.lua [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..afed073
--- /dev/null
@@ -0,0 +1 @@
+*.csv
diff --git a/core.lua b/core.lua
new file mode 100644 (file)
index 0000000..5a7ba3b
--- /dev/null
+++ b/core.lua
@@ -0,0 +1,100 @@
+local ok, bit = pcall(require, "bit32")
+if not ok then
+  bit = require("bit")  -- LuaJIT fallback
+end
+
+local M = {}
+
+local pluginDir = debug.getinfo(1, "S").source:sub(2):match("(.*/)")
+local csvPath = pluginDir .. "set-classes.csv"
+local csvLoaded = false
+local lookup = {}
+
+local function load_csv()
+  local f = io.open(csvPath, "r")
+  if not f then error("Could not open setclasses.csv at " .. csvPath) end
+  for line in f:lines() do
+    local dec, setClass = line:match("^(%d+),%[?([0-9AB ]+)%]?")
+    if dec and setClass then
+      lookup[tonumber(dec)] = "[" .. setClass .. "]"
+    end
+  end
+  f:close()
+end
+
+function M.get_visual_selection()
+  local start_pos = vim.fn.getpos("'<")
+  local end_pos = vim.fn.getpos("'>")
+  local lines = vim.fn.getline(start_pos[2], end_pos[2])
+  if #lines == 0 then return "" end
+  if #lines == 1 then
+    return string.sub(lines[1], start_pos[3], end_pos[3])
+  end
+  lines[1] = string.sub(lines[1], start_pos[3])
+  lines[#lines] = string.sub(lines[#lines], 1, end_pos[3])
+  return table.concat(lines, "\n")
+end
+
+function M.analyze_set(inputStr)
+  if not csvLoaded then
+    load_csv()
+    csvLoaded = true
+  end
+
+  local function parse_set(input)
+    local pcs = {}
+    for i = 1, #input do
+      local char = input:sub(i, i):upper()
+      local pc = tonumber(char)
+      if char == 'A' then pc = 10
+      elseif char == 'B' then pc = 11 end
+      if pc and pc >= 0 and pc < 12 then
+        table.insert(pcs, pc)
+      else
+        error("Invalid pc: " .. char)
+      end
+    end
+    return pcs
+  end
+
+  local function compute_bitmask(pcs)
+    local mask = 0
+    for _, pc in ipairs(pcs) do
+      mask = bit.bor(mask, bit.lshift(1, pc))
+    end
+    return mask
+  end
+
+  local function complement(mask)
+    return bit.band(bit.bnot(mask), 0xFFF)
+  end
+
+  local function multiply_set(pcs, factor)
+    local result = {}
+    for _, pc in ipairs(pcs) do
+      table.insert(result, (pc * factor) % 12)
+    end
+    return result
+  end
+
+  local pcs = parse_set(inputStr)
+  local mask = compute_bitmask(pcs)
+  local decimal = mask
+  local setClass = lookup[decimal] or "[Unknown]"
+  local complementMask = complement(mask)
+  local complementClass = lookup[complementMask] or "[Unknown]"
+  local m5Set = multiply_set(pcs, 5)
+  local m5Mask = compute_bitmask(m5Set)
+  local m5Decimal = m5Mask
+  local m5Class = lookup[m5Decimal] or "[Unknown]"
+
+  return {
+    input = inputStr,
+    decimal = decimal,
+    set_class = setClass,
+    complement_class = complementClass,
+    m5_class = m5Class
+  }
+end
+
+return M
diff --git a/init.lua b/init.lua
new file mode 100644 (file)
index 0000000..5028733
--- /dev/null
+++ b/init.lua
@@ -0,0 +1,17 @@
+local M = {}
+local core = require("setclass.core")
+
+function M.analyze_selection()
+  local input = core.get_visual_selection()
+  local result = core.analyze_set(input)
+  if result then
+    vim.notify("input:            " .. result.input .. " (" .. result.decimal .. ")")
+    vim.notify("set class:       " .. result.set_class)
+    vim.notify("abs. complement: " .. result.complement_class)
+    vim.notify("M5:              " .. result.m5_class)
+  else
+    vim.notify("Invalid set")
+  end
+end
+
+return M