From f2a9043f2e330dbc5f509023621c0328f789276c Mon Sep 17 00:00:00 2001 From: Georgi Kirilov <> Date: Sat, 31 Oct 2020 11:50:54 +0200 Subject: [PATCH] allow other line comment opening delimiters --- edit.lua | 28 +++++++++++++--------------- input.lua | 10 ++++++---- parser/init.lua | 17 ++++++++++------- walker.lua | 15 +++++++-------- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/edit.lua b/edit.lua index 0c89007..b07a982 100644 --- a/edit.lua +++ b/edit.lua @@ -9,8 +9,6 @@ local function is_comment(node) return node.is_comment end function M.new(parser, walker, fmt, write, delete, eol_at) - local function is_line_comment(node) return node.is_comment and parser.opposite[node.d] == "\n" end - local function normalize_spacing(start, delta, list) if delta > 0 then table.insert(list, {start + delta, -delta}) @@ -109,7 +107,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) elseif i <= first_argument + 1 and s.is_comment then first_argument = first_argument + 1 end - local has_eol = is_line_comment(s) + local has_eol = s.is_line_comment adj = leading_space(s, deltas, adj, parent, i, pstart, has_eol) adj = trailing_space(s, deltas, adj, parent, i, has_eol, keep_electric_space) adj = indentation(s, deltas, adj, parent, i, pstart, base_indent, last_distinguished, first_argument, @@ -141,7 +139,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) end else local s = parent_at[#parent_at] - if not s or range.start >= s.finish + 1 + (is_line_comment(s) and 1 or 0) then + if not s or range.start >= s.finish + 1 + (s.is_line_comment and 1 or 0) then path = walker.sexp_path(parent_at) path.at_pfinish = true else @@ -204,11 +202,11 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local sexp = walker.sexp_at(skip, true) local start = sexp.start + (sexp.p and #sexp.p or 0) -- XXX: don't splice empty line comments _yet_. See _join_or_splice - local tosplice = action.splice or action.wrap or not is_line_comment(sexp) and sexp.is_empty + local tosplice = action.splice or action.wrap or not sexp.is_line_comment and sexp.is_empty local opening = (sexp.p or "")..sexp.d local closing = parser.opposite[sexp.d] local real_start = tosplice and sexp.start or start + #sexp.d - local splice_closing = closing ~= "\n" or sexp.is_empty + local splice_closing = not sexp.is_line_comment or sexp.is_empty local real_finish = sexp.finish + 1 - (tosplice and splice_closing and 0 or #closing) local first = backwards and {start = real_start, finish = math.max(pos, start + #sexp.d)} or @@ -244,7 +242,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local adj = 0 local eol = eol_at(pos) local on_empty_line = not nxt or eol and nxt.start > eol - local empty_line_after_comment = prev and is_line_comment(prev) + local empty_line_after_comment = prev and prev.is_line_comment and on_empty_line if nxt and nxt.indent then if backwards and prev then @@ -310,7 +308,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local node, parent = walker.sexp_at({start = range.finish, finish = range.finish}) -- if the range ends with a line comment, don't delete its closing newline: local drop_eol = action.kill and node and - node.finish + 1 == range.finish and is_line_comment(node) + node.finish + 1 == range.finish and node.is_line_comment local par = big_enough_parent(range.start, range.finish) local operator_changed = par[1] and par[1].finish >= range.start local refmt = #skips == 0 and delete_indentation(range, pos) or operator_changed and 0 @@ -405,7 +403,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local opening = (parent.p or "")..parent.d local closing = parser.opposite[parent.d] local finish = parent.finish + 1 - #closing - if closing ~= "\n" then + if not parent.is_line_comment then delete(finish, #closing) end -- TODO: (un)escape special characters, if necessary @@ -453,7 +451,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local opening = (parent.p or "")..parent.d local closing = parser.opposite[parent.d] write(new_start, opening) - local sep = is_line_comment(parent) and "" -- line comments already have a separator + local sep = parent.is_line_comment and "" -- line comments already have a separator or new_finish == new_start and " " -- only add a separator if there was none before or "" write(new_finish, closing..sep) @@ -472,7 +470,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local second = first ~= node and node or parent.after(range.start, startof) if not (first and second and first.d and -- don't join line comments to margin comments: - (not is_line_comment(first) or first.indent and second.indent) and + (not first.is_line_comment or first.indent and second.indent) and (first.d == second.d or -- join line comments even when their delimiters differ slightly -- (different number of semicolons, existence/lack of a space after them) @@ -583,7 +581,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local function _join_or_splice(parent, n, range, pos) local sexp = parent[n] local nxt = parent[n + 1] - local is_last = not nxt or not is_line_comment(nxt) + local is_last = not nxt or not nxt.is_line_comment local newpos = not (is_last and sexp.is_empty) and join_sexps(range) if not newpos and sexp.is_empty then newpos = splice_sexp({start = pos, finish = pos}, nil, true) @@ -661,7 +659,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) end local function newline(parent, range) - local line_comment = is_line_comment(parent) + local line_comment = parent.is_line_comment -- do not autoextend margin comments: if line_comment and range.start < parent.finish + (parent.indent and 1 or 0) then local newpos = split_sexp(range) @@ -685,7 +683,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local last_nonblank_in_list = not parent.is_empty and parent[#parent].finish - (line_comment and 1 or 0) local nxt = parent.after(range.start, startof) local last_on_line = not nxt or nxt and nxt.indent and nxt.start > range.start - local margin = nxt and not nxt.indent and is_line_comment(nxt) and nxt.finish + local margin = nxt and not nxt.indent and nxt.is_line_comment and nxt.finish local after_last = last_nonblank_in_list and range.start > last_nonblank_in_list local in_indent = nxt and nxt.indent and range.start <= nxt.start and range.start >= (nxt.start - nxt.indent) local placeholder = "asdf" @@ -719,7 +717,7 @@ function M.new(parser, walker, fmt, write, delete, eol_at) local opening = closing and parser.opposite[closing] local parent = walker.quasilist_at(range, opening) if parent then - local has_eol = is_line_comment(parent) + local has_eol = parent.is_line_comment local r = {start = parent.finish, finish = parent.finish} local newpos = refmt_at(parent, r) r = {start = newpos + (has_eol and 0 or 1), finish = newpos + (has_eol and 0 or 1)} diff --git a/input.lua b/input.lua index 8794d33..b2addf9 100644 --- a/input.lua +++ b/input.lua @@ -94,7 +94,9 @@ local function make_insert(parser, d1, D2, walker, edit, write, eol_at, bol_at) end end - local function semicolon(range, seek, char) + local comment_start = parser.opposite["\n"] + + local function open_comment(range, seek, char) local escaped = walker.escaped_at(range) if escaped and escaped.is_char then return true end local datum, sexp, parent @@ -115,9 +117,9 @@ local function make_insert(parser, d1, D2, walker, edit, write, eol_at, bol_at) and ((nxt and nxt.start or parent.finish or range.start + 1) > eol) if on_empty_line or next_safe == range.start and next_safe ~= parent.finish then if parent.is_root then - char = ";;; " + char = char:rep(3) .. " " else - char = "\n;; " + char = "\n" .. char:rep(2) .. " " end elseif nxt and nxt.start > eol or range.start == eol then local tabwidth = 8 @@ -153,7 +155,7 @@ local function make_insert(parser, d1, D2, walker, edit, write, eol_at, bol_at) D2:match(char) and close or char == " " and spacekey or char == "\n" and enterkey or - char == ";" and semicolon + char == comment_start and open_comment if handler then return handler(range, seek, char, shiftless, auto_square) else diff --git a/parser/init.lua b/parser/init.lua index 900526d..2b51332 100644 --- a/parser/init.lua +++ b/parser/init.lua @@ -19,6 +19,7 @@ local function _finish(patt) return Cg(patt, "finish") end local function _string(patt) return Cg(patt / function() return true end, "is_string") end local function _char(patt) return Cg(patt / function() return true end, "is_char") end local function _comment(patt) return Cg(patt / function() return true end, "is_comment") end +local function _line_comment(patt) return Cg(patt / function() return true end, "is_line_comment") end local function delimited_range(d) return Cg(d, "d") * (P(1) - "\\" - d + P"\\" * 1)^0 * d end @@ -69,13 +70,13 @@ local function make_driver(read, parse, before, sexps) if sexps.tree.first_invalid < last_parsed then local nearest, n = before(sexps.tree, sexps.tree.first_invalid, startof) local second_nearest = n and sexps.tree[n - 1] - local has_eol = second_nearest and second_nearest.is_comment and second_nearest.d:find"^;" + local has_eol = second_nearest and second_nearest.is_line_comment local nearest_finish = second_nearest and second_nearest.finish + (has_eol and 0 or 1) local nearest_start = nearest and nearest.start base = nearest_finish or nearest_start or sexps.tree.first_invalid else local last = sexps.tree[#sexps.tree] - local has_eol = last and last.is_comment and last.d:find"^;" + local has_eol = last and last.is_line_comment base = has_eol and last.finish or sexps.tree.first_invalid end end @@ -124,7 +125,7 @@ local function make_parser(prefix, opposite, d1, d2, D1, D2, atom_node, list_nod if type(node) == "number" then tag_next_node(t, i, node) table.remove(t, i) - elseif node.is_comment and opposite[node.d] == "\n" then + elseif node.is_line_comment then tag_next_node(t, i, node[1]) table.remove(node) end @@ -155,11 +156,12 @@ local function make_parser(prefix, opposite, d1, d2, D1, D2, atom_node, list_nod local multi_esc = delimited_range("|") * _string(P(true)) local nline = I * newline local blank = nline + hspace + "\f" - local semicolons = ";" * #-P";" + P";"^1 * hspace^-1 - local line_comment = Cg(semicolons, "d") * (1 - nline)^0 * nline * _comment(P(true)) + local lcd = opposite["\n"] + local lc_level = lcd * #-P(lcd) + P(lcd)^1 * hspace^-1 + local line_comment = Cg(lc_level, "d") * (1 - nline)^0 * nline * _comment(P(true)) * _line_comment(P(true)) local block_comment = nested_pair("#|", "|#") * _comment(P(true)) local comment = opposite["#|"] and (line_comment + block_comment) or line_comment - local incomplete_comment = opposite["#|"] and (semicolons + "#|") or semicolons + local incomplete_comment = opposite["#|"] and (lc_level + "#|") or lc_level local atom = Ct(_start(I) * ( comment + Cg(prefix^1, "p")^-1 * ( @@ -187,7 +189,8 @@ end local opposite_fallback = { __index = function(t, delimiter) - return delimiter and delimiter:find("^;") and t[";"] + local opening = t["\n"] + return delimiter and delimiter:find("^" .. opening) and t[opening] end } diff --git a/walker.lua b/walker.lua index 6374dd5..30d37d4 100644 --- a/walker.lua +++ b/walker.lua @@ -6,8 +6,6 @@ local function is_comment(node) return node.is_comment end function M.new(parser, eol_at, bol_at) - local function is_line_comment(node) return node.is_comment and parser.opposite[node.d] == "\n" end - local function in_quasilist(t, range) return t and t.d and not t.is_list and range.start >= t.start + #t.d and range.finish <= t.finish + 1 - #parser.opposite[t.d] @@ -213,7 +211,7 @@ function M.new(parser, eol_at, bol_at) else local _, parent, n = sexp_at(range, true) local cur, nxt = parent[n], parent[n + 1] - if nxt and is_line_comment(cur) and is_line_comment(nxt) then + if nxt and cur.is_line_comment and nxt.is_line_comment then return nxt.start_after(range.start) end end @@ -227,7 +225,7 @@ function M.new(parser, eol_at, bol_at) else local _, parent, n = sexp_at(range, true) local cur, nxt = parent[n], parent[n + 1] - if nxt and is_line_comment(cur) and is_line_comment(nxt) then + if nxt and cur.is_line_comment and nxt.is_line_comment then return nxt.finish_after(range.start) end end @@ -241,7 +239,7 @@ function M.new(parser, eol_at, bol_at) else local _, parent, n = sexp_at(range, true) local cur, prev = parent[n], parent[n - 1] - if prev and is_line_comment(cur) and is_line_comment(prev) then + if prev and cur.is_line_comment and prev.is_line_comment then return prev.start_before(range.start) end end @@ -255,7 +253,7 @@ function M.new(parser, eol_at, bol_at) else local _, parent, n = sexp_at(range, true) local cur, prev = parent[n], parent[n - 1] - if prev and is_line_comment(cur) and is_line_comment(prev) then + if prev and cur.is_line_comment and prev.is_line_comment then return prev.finish_before(range.start) end end @@ -296,7 +294,7 @@ function M.new(parser, eol_at, bol_at) return prev and prev.start end local pprev = n and parser.tree[n - 1] - local has_eol = pprev and is_line_comment(pprev) + local has_eol = pprev and pprev.is_line_comment local adjacent = pprev and prev and prev.start - (pprev.finish + (has_eol and 0 or 1)) <= 1 return prev and prev.start - ((adjacent or prev.start == 0) and 0 or 1) end, @@ -350,7 +348,8 @@ function M.new(parser, eol_at, bol_at) -- opening: nil - bracketed list, false - any quasilist quasilist_at = function(range, opening) - if opening and opening:match'[%;%"]' then + local lcd = parser.opposite["\n"] + if opening and opening:match('[%' .. lcd .. '%"]') then local escaped = escaped_at(range) return escaped and escaped.d:find("^"..opening) and escaped else -- 2.11.4.GIT