1

Compare commits

..

15 Commits

Author SHA1 Message Date
2b2d831837 Cleanup 2024-05-04 10:29:49 -07:00
5de6deae99 Better wrapping on comma 2024-05-04 10:27:52 -07:00
50216e52a9 Keep track of parameter start and endpoints 2024-05-04 10:19:59 -07:00
9d241775a9 Update line prefix behavior 2024-05-02 21:17:58 -07:00
c068ad5b84 Update config 2024-05-02 20:21:50 -07:00
66400690bf Add line max 2024-05-02 20:21:29 -07:00
0deb8db17e Improve wrapping 2024-05-02 20:14:54 -07:00
75cc3a3cb5 Text stripping 2024-05-02 18:10:16 -07:00
ca45fc2fdb Check for comments in addition to strings 2024-05-02 17:35:41 -07:00
a9b2f24d46 Cleanup 2024-05-01 21:50:58 -07:00
170dccdaa9 CLeanup 2024-05-01 20:20:50 -07:00
d06d6865df Cleanup 2024-04-30 18:31:16 -07:00
e8dcbc6da4 Update preferences 2024-04-29 20:33:02 -07:00
0778dbca64 Fix padding 2024-04-29 18:46:58 -07:00
193d7fbd57 Cleanup 2024-04-28 22:11:34 -07:00
3 changed files with 188 additions and 123 deletions

View File

@ -1,4 +1,4 @@
local configs = { local opt_curr = {
default = { default = {
brace_last_indent = false, brace_last_indent = false,
brace_last_wrap = true, brace_last_wrap = true,
@ -6,57 +6,50 @@ local configs = {
comma_last = false, comma_last = false,
comma_prefix = false, comma_prefix = false,
comma_prefix_indent = false, comma_prefix_indent = false,
line_max = 32,
line_prefix = '', line_prefix = '',
trim_inner_spaces = true,
}, },
go = { go = {
comma_last = true, comma_last = true,
}, },
vim = { vim = {
brace_last_wrap = false,
line_prefix = '\\', line_prefix = '\\',
} }
} }
local function set(opts, filetypes) local function setup(opt)
if opts then for file_type, file_opt in pairs(opt) do
if type(filetypes) == 'string' then local file_opt_curr = opt_curr[file_type]
filetypes = {filetypes} if not file_opt_curr then
elseif not filetypes then file_opt_curr = {}
filetypes = {'default'} opt_curr[file_type] = file_opt_curr
end end
for _, filetype in ipairs(filetypes) do for param_name, param_value in pairs(file_opt) do
local config = configs[filetype] file_opt_curr[param_name] = param_value
if not config then
config = {}
configs[filetype] = config
end
for key, value in pairs(opts) do
config[key] = value
end
end end
end end
end end
local function get() local function get()
local file_config = configs[vim.bo.filetype] local file_opt_curr = opt_curr[vim.bo.filetype]
local config = {} local file_opt = {}
for key, value in pairs(configs.default) do for param_name, param_value in pairs(opt_curr.default) do
config[key] = value file_opt[param_name] = param_value
if file_config then if file_opt_curr then
local file_value = file_config[key] param_value = file_opt_curr[param_name]
if file_value ~= nil then if param_value ~= nil then
config[key] = file_config[key] file_opt[param_name] = param_value
end end
end end
end end
return config return file_opt
end end
return { return {
set = set, setup = setup,
get = get, get = get,
} }

View File

@ -10,5 +10,5 @@ end
return { return {
reflow = reflow, reflow = reflow,
setup = config.set, setup = config.setup,
} }

View File

@ -14,11 +14,11 @@ function Cursor:is_valid()
return self.row > 0 and self.col > 0 return self.row > 0 and self.col > 0
end end
function Cursor:is_string() function Cursor:is_literal()
assert(self:is_valid()) assert(self:is_valid())
local syn_id = vim.fn.synID(self.row, self.col, false) local syn_id = vim.fn.synID(self.row, self.col, false)
local syn_attr = vim.fn.synIDattr(syn_id, 'name') local syn_attr = vim.fn.synIDattr(syn_id, 'name')
return syn_attr:find('String$') return syn_attr:find('String$') ~= nil or syn_attr:find('Comment$') ~= nil
end end
function Cursor.get_current() function Cursor.get_current()
@ -86,7 +86,7 @@ function BracePair:find_closest(backward)
local ignore_func = function() local ignore_func = function()
local cursor = Cursor.get_current() local cursor = Cursor.get_current()
return cursor:is_string() return cursor:is_literal()
end end
local escaped_pair = self:get_escaped() local escaped_pair = self:get_escaped()
@ -191,6 +191,10 @@ function BraceRange.find_closest_any()
end end
end end
function BraceRange:get_rows()
return self.stop.row - self.start.row
end
function BraceRange:is_wrapped() function BraceRange:is_wrapped()
return self.start.row < self.stop.row return self.start.row < self.stop.row
end end
@ -223,35 +227,100 @@ end
local Param = {} local Param = {}
Param.__index = Param Param.__index = Param
function Param.new(text, pair) function Param.new(pair, opt)
local param = { local param = {
text = text,
pair = pair, pair = pair,
opt = opt,
text = '',
literals = {},
offset = nil, offset = nil,
start = nil,
stop = nil,
terminator = nil,
} }
return setmetatable(param, Param) return setmetatable(param, Param)
end end
function Param:append(char) function Param:append(char, cursor)
assert(cursor:is_valid())
self.text = self.text .. char self.text = self.text .. char
table.insert(self.literals, cursor:is_literal())
if cursor == Cursor.get_current() then
self.offset = #self.text
end end
function Param:activate() if not self.start then
self.start = cursor
end
self.stop = cursor
end
function Param:terminate(cursor)
self.terminator = cursor
if self.terminator == Cursor.get_current() then
self.offset = #self.text self.offset = #self.text
end end
end
function Param:is_active() function Param:is_active()
return self.offset ~= nil return self.offset ~= nil
end end
function Param:flush() function Param:slice(start, stop)
if self.offset then assert(#self.text == #self.literals)
self.offset = math.min(self.offset, #self.text:match('(.-)%s*$'))
self.offset = math.max(self.offset - #self.text:match('^%s*'), 1) local text = ''
local literals = {}
for i = start, stop do
text = text .. self.text:sub(i, i)
table.insert(literals, self.literals[i])
end
self.text = text
self.literals = literals
if self.offset then
self.offset = math.min(self.offset, stop)
self.offset = math.max(self.offset - start + 1, 1)
end
end
function Param:trim()
assert(#self.text == #self.literals)
self:slice(1, #self.text - #self.text:match('%s*$'))
self:slice(1 + #self.text:match('^%s*'), #self.text)
if self.text:match('^' .. self.opt.line_prefix) then
self:slice(1 + #self.opt.line_prefix, #self.text)
end
if self.opt.trim_inner_spaces then
local text = ''
local literals = {}
local offset = self.offset
for i = 1, #self.text do
local char = self.text:sub(i, i)
local literal = self.literals[i]
if literal or not char:match('%s') or not text:match('%s$') then
text = text .. char
table.insert(literals, literal)
elseif offset and offset >= i then
self.offset = math.max(1, self.offset - 1)
end
end
self.text = text
self.literals = literals
end end
self.text = self.text:match('^%s*(.-)%s*$')
return #self.text > 0 return #self.text > 0
end end
@ -262,9 +331,10 @@ end
local ParamList = {} local ParamList = {}
ParamList.__index = ParamList ParamList.__index = ParamList
function ParamList.new(range) function ParamList.new(range, opt)
local params = { local params = {
range = range, range = range,
opt = opt,
current = nil, current = nil,
parsed = {}, parsed = {},
} }
@ -272,33 +342,34 @@ function ParamList.new(range)
return setmetatable(params, ParamList) return setmetatable(params, ParamList)
end end
function ParamList:flush() function ParamList:flush(cursor)
if self.current then if self.current then
if self.current:flush() then if cursor then
self.current:terminate(cursor)
end
if self.current:trim() then
table.insert(self.parsed, self.current) table.insert(self.parsed, self.current)
end end
self.current = nil self.current = nil
end end
end end
function ParamList:update(char, brace_stack, cursor) function ParamList:update(char, brace_stack, cursor)
if not cursor:is_string() then if not cursor:is_literal() then
brace_stack:update(char) brace_stack:update(char)
if brace_stack:empty() and char == ',' then if brace_stack:empty() and char == ',' then
self:flush() self:flush(cursor)
return return
end end
end end
if self.current then if not self.current then
self.current:append(char) self.current = Param.new(self.range, self.opt)
else
self.current = Param.new(char, self.range)
end end
if cursor == Cursor.get_current() then self.current:append(char, cursor)
self.current:activate()
end
end end
function ParamList:parse() function ParamList:parse()
@ -320,10 +391,10 @@ function ParamList:parse()
for col = start_col, stop_col do for col = start_col, stop_col do
self:update(line:sub(col, col), brace_stack, Cursor.new(row, col)) self:update(line:sub(col, col), brace_stack, Cursor.new(row, col))
end end
end
self:flush() self:flush()
end end
end
-- --
-- Builder -- Builder
@ -376,7 +447,8 @@ WrapContext.__index = WrapContext
function WrapContext.new(opt) function WrapContext.new(opt)
local wrap_context = { local wrap_context = {
opt = opt, opt = nil,
base_opt = opt,
indent = '', indent = '',
prefix = '', prefix = '',
suffix = '', suffix = '',
@ -387,50 +459,71 @@ function WrapContext.new(opt)
return setmetatable(wrap_context, WrapContext) return setmetatable(wrap_context, WrapContext)
end end
function WrapContext:config_opt()
self.opt = {}
for key, value in pairs(self.base_opt) do
if type(value) == 'table' then
self.opt[key] = false
for _, brace in ipairs(value) do
if self.range.pair == BracePair.from_brace(brace) then
self.opt[key] = true
break
end
end
else
self.opt[key] = value
end
end
end
function WrapContext:config_indent(line)
local padding = #line:match('^(%s*)')
if vim.o.expandtab then
self.indent_level = math.floor(padding / vim.o.shiftwidth)
self.indent_block = string.rep(' ', vim.o.shiftwidth)
else
self.indent_level = padding
self.indent_block = '\t'
end
end
function WrapContext:parse() function WrapContext:parse()
self.range = BraceRange.find_closest_any() self.range = BraceRange.find_closest_any()
if not self.range then if not self.range then
return false return false
end end
local first_line = vim.fn.getline(self.range.start.row) self:config_opt()
local indent = #first_line:match('^(%s*)')
self.prefix = first_line:sub(indent + 1, self.range.start.col) if self.range:get_rows() > self.opt.line_max then
if vim.o.expandtab then return false
self.indent_level = indent / vim.o.shiftwidth
self.indent_block = string.rep(' ', vim.o.shiftwidth)
else
self.indent_level = indent
self.indent_block = '\t'
end end
local first_line = vim.fn.getline(self.range.start.row)
local last_line = vim.fn.getline(self.range.stop.row) local last_line = vim.fn.getline(self.range.stop.row)
self:config_indent(first_line)
self.prefix = first_line:sub(self.indent_level * #self.indent_block + 1, self.range.start.col)
self.suffix = last_line:sub(self.range.stop.col) self.suffix = last_line:sub(self.range.stop.col)
self.params = ParamList.new(self.range) self.params = ParamList.new(self.range, self.opt)
self.params:parse() self.params:parse()
return true return true
end end
function WrapContext:update_builder_param(builder, param, opt) function WrapContext:update_builder_param(builder, param)
local text = param.text
if #opt.line_prefix > 0 then
text = param.text:match('^%s*[' .. opt.line_prefix .. ']?%s*(.*)')
end
local cursor = nil local cursor = nil
if param:is_active() then if param:is_active() then
cursor = builder:get_offset() cursor = builder:get_offset()
cursor.row = cursor.row + self.range.start.row cursor.row = cursor.row + self.range.start.row
cursor.col = cursor.col + param.offset - (#param.text - #text) cursor.col = cursor.col + param.offset
end end
builder:update(text) builder:update(param.text)
return cursor return cursor
end end
function WrapContext:wrap(opt) function WrapContext:wrap()
local builder = Builder.new(self.indent_level, self.indent_block) local builder = Builder.new(self.indent_level, self.indent_block)
builder:update(self.prefix) builder:update(self.prefix)
builder:flush() builder:flush()
@ -441,36 +534,35 @@ function WrapContext:wrap(opt)
local is_first_param = i == 1 local is_first_param = i == 1
local is_last_param = i == #self.params.parsed local is_last_param = i == #self.params.parsed
if opt.comma_prefix then if self.opt.comma_prefix then
builder:update(opt.line_prefix) builder:update(self.opt.line_prefix)
if not is_first_param then if not is_first_param then
builder:update(', ') builder:update(', ')
elseif opt.comma_prefix_indent and not is_last_param then elseif self.opt.comma_prefix_indent and not is_last_param then
builder:update(' ') builder:update(' ')
end end
cursor = self:update_builder_param(builder, param) or cursor
cursor = self:update_builder_param(builder, param, opt) or cursor
else else
builder:update(opt.line_prefix) builder:update(self.opt.line_prefix)
cursor = self:update_builder_param(builder, param, opt) or cursor cursor = self:update_builder_param(builder, param) or cursor
if not is_last_param or self.opt.comma_last then
if not is_last_param or opt.comma_last then
builder:update(',') builder:update(',')
end end
end end
if is_last_param and not opt.brace_last_wrap then if is_last_param and not self.opt.brace_last_wrap then
builder:update(self.suffix) builder:update(self.suffix)
end end
builder:flush() builder:flush()
end end
if not opt.brace_last_indent then if not self.opt.brace_last_indent then
builder:unindent() builder:unindent()
end end
if opt.brace_last_wrap then if self.opt.brace_last_wrap then
builder:update(self.opt.line_prefix)
builder:update(self.suffix) builder:update(self.suffix)
builder:flush() builder:flush()
end end
@ -485,14 +577,16 @@ function WrapContext:wrap(opt)
end end
end end
if cursor then if not cursor then
cursor:set_current() cursor = self.range.start
end
end end
function WrapContext:unwrap(opt) cursor:set_current()
end
function WrapContext:unwrap()
local padding = '' local padding = ''
if opt.brace_pad then if self.opt.brace_pad then
padding = ' ' padding = ' '
end end
@ -502,7 +596,7 @@ function WrapContext:unwrap(opt)
local cursor = nil local cursor = nil
for i, param in ipairs(self.params.parsed) do for i, param in ipairs(self.params.parsed) do
cursor = self:update_builder_param(builder, param, opt) or cursor cursor = self:update_builder_param(builder, param) or cursor
if i < #self.params.parsed then if i < #self.params.parsed then
builder:update(', ') builder:update(', ')
end end
@ -513,45 +607,23 @@ function WrapContext:unwrap(opt)
builder:flush() builder:flush()
vim.fn.setline(self.range.start.row, builder.lines[1]) vim.fn.setline(self.range.start.row, builder.lines[1])
vim.fn.execute(string.format( vim.fn.execute(string.format('%d,%dd_', self.range.start.row + 1, self.range.stop.row))
'%d,%dd_',
self.range.start.row + 1,
self.range.stop.row
))
if cursor then if not cursor then
cursor:set_current() cursor = self.range.start
end end
cursor:set_current()
end end
function WrapContext:toggle() function WrapContext:toggle()
local opt = self:specialize_opt()
if self.range:is_wrapped() then if self.range:is_wrapped() then
self:unwrap(opt) self:unwrap()
else else
self:wrap(opt) self:wrap()
end end
end end
function WrapContext:specialize_opt()
local opt = {}
for key, value in pairs(self.opt) do
if type(value) == 'table' then
opt[key] = false
for _, brace in ipairs(value) do
if self.range.pair == BracePair.from_brace(brace) then
opt[key] = true
break
end
end
else
opt[key] = value
end
end
return opt
end
return { return {
WrapContext = WrapContext, WrapContext = WrapContext,
} }