2022-12-26 20:07:10 +01:00
|
|
|
local A = require("my.abbreviations")
|
|
|
|
|
2022-10-09 03:28:51 +02:00
|
|
|
local M = {}
|
|
|
|
|
2022-12-26 20:07:10 +01:00
|
|
|
-- function M.abolish(from, to)
|
|
|
|
-- vim.cmd(":Abolish -buffer " .. from .. " " .. to)
|
|
|
|
-- end
|
|
|
|
--
|
|
|
|
-- function M.abolishMany(many)
|
|
|
|
-- for _, entry in pairs(many) do M.abolish(entry[1], entry[2]) end
|
|
|
|
-- end
|
|
|
|
|
|
|
|
local function concatTables(t1, t2)
|
|
|
|
assert(type(t1) == "table")
|
|
|
|
assert(type(t2) == "table")
|
|
|
|
|
|
|
|
local t3 = {}
|
|
|
|
for i = 1, #t1 do t3[#t3 + 1] = t1[i] end
|
|
|
|
for i = 1, #t2 do t3[#t3 + 1] = t2[i] end
|
|
|
|
return t3
|
2022-10-09 03:28:51 +02:00
|
|
|
end
|
|
|
|
|
2022-12-26 20:07:10 +01:00
|
|
|
local function betterAbolish(unprocessed, context, out)
|
|
|
|
local from = unprocessed[1] or {}
|
|
|
|
local to = unprocessed[2] or {}
|
|
|
|
|
|
|
|
assert(type(from) == "table" and type(to) == "table",
|
|
|
|
"Both arguments should be tables. Found " .. vim.inspect(from) .. " and " ..
|
|
|
|
vim.inspect(to) .. " instead.")
|
|
|
|
|
|
|
|
-- print(vim.inspect({ context = context, unprocessed = unprocessed }))
|
|
|
|
|
|
|
|
if #from == 0 and #to == 0 then
|
|
|
|
table.insert(out, context)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
for i = 1, 2, 1 do
|
|
|
|
local head = unprocessed[i][1]
|
|
|
|
if type(head) == "string" then
|
|
|
|
local context_clone = { context[1], context[2] }
|
|
|
|
|
|
|
|
context_clone[i] = context_clone[i] .. head
|
|
|
|
|
|
|
|
local unprocessed_clone = { unprocessed[1], unprocessed[2] }
|
|
|
|
unprocessed_clone[i] = { unpack(unprocessed[i], 2) }
|
|
|
|
|
|
|
|
return betterAbolish(unprocessed_clone, context_clone, out)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- print(vim.inspect({ from, to, context }))
|
|
|
|
|
|
|
|
assert(type(from[1]) == "table", vim.inspect(from) .. " starts with neither a table nor a string")
|
|
|
|
assert(type(to[1]) == "table", vim.inspect(to) .. " does not start with a table")
|
|
|
|
|
|
|
|
for i = 1, #from[1], 1 do
|
|
|
|
local when = from[1][i]
|
|
|
|
local replacement = when
|
|
|
|
|
|
|
|
if #to[1] > 0 then replacement = to[1][((i - 1) % #to[1]) + 1] end
|
|
|
|
|
|
|
|
assert(type(when) == "table")
|
|
|
|
assert(type(replacement) == "table")
|
|
|
|
|
|
|
|
local unprocessed_clone = {
|
|
|
|
concatTables(when, { unpack(from, 2) }),
|
|
|
|
concatTables(replacement, { unpack(to, 2) })
|
|
|
|
}
|
|
|
|
|
|
|
|
-- print(vim.inspect({
|
|
|
|
-- unprocessed_clone = unprocessed_clone,
|
|
|
|
-- when = when,
|
|
|
|
-- replacement = replacement,
|
|
|
|
-- from = from,
|
|
|
|
-- to = to,
|
|
|
|
-- i = i
|
|
|
|
-- }))
|
|
|
|
|
|
|
|
betterAbolish(unprocessed_clone, context, out)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function M.betterAbolish(from, to)
|
|
|
|
local result = {}
|
|
|
|
betterAbolish({ from, to }, { "", "" }, result)
|
|
|
|
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
local function withCasing(input)
|
|
|
|
local out = {}
|
|
|
|
|
|
|
|
for i = 1, #input, 1 do
|
|
|
|
local from = input[i][1]
|
|
|
|
local to = input[i][2]
|
|
|
|
|
|
|
|
table.insert(out, { from, to })
|
|
|
|
table.insert(out, { string.upper(from), string.upper(to) })
|
|
|
|
|
|
|
|
if #from and #to then
|
|
|
|
table.insert(out, {
|
|
|
|
string.upper(string.sub(from, 1, 1)) .. string.sub(from, 2),
|
|
|
|
string.upper(string.sub(to, 1, 1)) .. string.sub(to, 2)
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return out
|
|
|
|
end
|
|
|
|
|
|
|
|
---Parses the input for this plugin
|
|
|
|
---@param input string
|
|
|
|
---@param context {delimiters:{left:string,right:string},separator:string}
|
|
|
|
---@return nil|{positio:number,message:string}
|
|
|
|
---@return (string|table)[]|nil
|
|
|
|
local function parse(input, context)
|
|
|
|
local position = 1
|
|
|
|
---@type { start:number, contents:(string|table)[] }[]
|
|
|
|
local stack = { { start = position, contents = {} } }
|
|
|
|
|
|
|
|
local function error(message, pos)
|
|
|
|
return { position = pos or position, message = message }
|
|
|
|
end
|
|
|
|
|
|
|
|
local escaped = false
|
|
|
|
local escapedChars = {
|
|
|
|
["\\"] = true,
|
|
|
|
[context.delimiters.left] = true,
|
|
|
|
[context.delimiters.right] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
-- When encountering {}, instead of treating it like a single
|
|
|
|
-- choice containing an empty string, we must treat it as an empty choice
|
|
|
|
--
|
|
|
|
-- The specialEmpty arg tells us whether to consider such cases.
|
|
|
|
local function saveUp(specialEmpty)
|
|
|
|
local prev = stack[#stack - 1].contents
|
|
|
|
local current = stack[#stack]
|
|
|
|
|
|
|
|
assert(type(prev[#prev]) == "table")
|
|
|
|
---@cast prev table
|
|
|
|
|
|
|
|
-- If specialEmpty is true (so we are processing a '}'),
|
|
|
|
-- we only want to keep empty strings (so those where #current.contents == 0)
|
|
|
|
-- if we've had a , before (so #prev[#prev] > 0)
|
|
|
|
if not specialEmpty or #current.contents > 0 or #prev[#prev] > 0 then
|
|
|
|
table.insert(prev[#prev], current.contents)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
while position <= string.len(input) do
|
|
|
|
local first = string.sub(input, position, position)
|
|
|
|
local next = string.sub(input, position + 1, position + 1)
|
|
|
|
local current = stack[#stack]
|
|
|
|
|
|
|
|
if not escaped and first == "\\" and escapedChars[next] then
|
|
|
|
escaped = true
|
|
|
|
|
|
|
|
elseif not escaped and first == context.delimiters.left then
|
|
|
|
table.insert(current.contents, {})
|
|
|
|
stack[#stack + 1] = { start = position, contents = {} }
|
|
|
|
elseif not escaped and first == context.delimiters.right then
|
|
|
|
if #stack == 1 then
|
|
|
|
return nil, error("Delimiter " .. context.delimiters.right .. " never opened")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- we want special treatment for {}
|
|
|
|
saveUp(true)
|
|
|
|
|
|
|
|
stack[#stack] = nil
|
|
|
|
elseif not escaped and first == context.separator and #stack > 1 then
|
|
|
|
-- we want to treat empty strings before , as empty strings
|
|
|
|
saveUp(false)
|
|
|
|
|
|
|
|
current.contents = {}
|
|
|
|
else
|
|
|
|
local last = current.contents[#current.contents]
|
|
|
|
|
|
|
|
if type(last) == "string" then
|
|
|
|
current.contents[#current.contents] = last .. first
|
|
|
|
else
|
|
|
|
table.insert(current.contents, first)
|
|
|
|
end
|
|
|
|
|
|
|
|
escaped = false
|
|
|
|
end
|
|
|
|
|
|
|
|
position = position + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
if #stack > 1 then
|
|
|
|
return nil, error("Delimiter " .. context.delimiters.left .. " never closed", stack[2].start)
|
|
|
|
end
|
|
|
|
|
|
|
|
return stack[1].contents, nil
|
|
|
|
end
|
|
|
|
|
|
|
|
local context = { delimiters = { left = "{", right = "}" }, separator = "," }
|
|
|
|
|
2022-10-09 03:28:51 +02:00
|
|
|
function M.abolishMany(many)
|
2022-12-26 20:07:10 +01:00
|
|
|
local total = 0
|
|
|
|
|
2022-10-09 03:28:51 +02:00
|
|
|
for _, entry in pairs(many) do
|
2022-12-26 20:07:10 +01:00
|
|
|
local left = parse(entry[1], context)
|
|
|
|
local right = parse(entry[2], context)
|
|
|
|
|
|
|
|
local abbreviations = withCasing(M.betterAbolish(left, right))
|
|
|
|
total = total + #abbreviations
|
|
|
|
|
|
|
|
A.manyLocalAbbr(abbreviations)
|
2022-10-09 03:28:51 +02:00
|
|
|
end
|
2022-12-26 20:07:10 +01:00
|
|
|
|
|
|
|
print("Added " .. total .. " abbreviations")
|
2022-10-09 03:28:51 +02:00
|
|
|
end
|
|
|
|
|
2022-12-26 20:07:10 +01:00
|
|
|
-- function M.setup()
|
|
|
|
-- local context = { delimiters = { left = "{", right = "}" }, separator = "," }
|
|
|
|
-- print(vim.inspect({ parse("abc\\d{a, d,e}dsdf\\{sdf\\}", context) }))
|
|
|
|
-- local parsed, _ = parse("ab{e,{f0,1e,d2},f,{3,4,5},\\{{000,111}\\}}cd", context)
|
|
|
|
-- -- local parsed, _ = parse("abc", context)
|
|
|
|
-- print(vim.inspect(parsed))
|
|
|
|
-- local processed = M.betterAbolish(parsed, parsed)
|
|
|
|
-- print(vim.inspect(processed))
|
|
|
|
-- end
|
|
|
|
|
2022-10-09 03:28:51 +02:00
|
|
|
return M
|