vis-config
lua scripts to configure vis editor
git clone https://9o.is/git/vis-config.git
commentary.lua
(4520B)
1 --
2 -- vis-commentary
3 --
4
5 local vis = _G.vis
6
7 local comment_string = {
8 actionscript='//', ada='--', ansi_c='/*|*/', antlr='//', apdl='!', apl='#',
9 applescript='--', asp='\'', autoit=';', awk='#', b_lang='//', bash='#',
10 batch=':', bibtex='%', boo='#', chuck='//', cmake='#', coffeescript='#',
11 context='%', cpp='//', crystal='#', csharp='//', css='/*|*/', cuda='//',
12 dart='//', desktop='#', django='{#|#}', dmd='//', dockerfile='#', dot='//',
13 eiffel='--', elixir='#', erlang='%', faust='//', fennel=';;', fish='#',
14 forth='|\\', fortran='!', fsharp='//', gap='#', gettext='#', gherkin='#',
15 glsl='//', gnuplot='#', go='//', groovy='//', gtkrc='#', haskell='--',
16 html='<!--|-->', icon='#', idl='//', inform='!', ini='#', Io='#',
17 java='//', javascript='//', json='/*|*/', jsp='//', latex='%', ledger='#',
18 less='//', lilypond='%', lisp=';', logtalk='%', lua='--', makefile='#',
19 markdown='<!--|-->', matlab='#', moonscript='--', myrddin='//',
20 nemerle='//', nsis='#', objective_c='//', pascal='//', perl='#', php='//',
21 pico8='//', pike='//', pkgbuild='#', prolog='%', props='#', protobuf='//',
22 ps='%', pure='//', python='#', rails='#', rc='#', rebol=';', rest='.. ',
23 rexx='--', rhtml='<!--|-->', rstats='#', ruby='#', rust='//', sass='//',
24 scala='//', scheme=';', smalltalk='"|"', sml='(*)', snobol4='#', sql='#',
25 tcl='#', tex='%', text='', toml='#', vala='//', vb='\'', vbscript='\'',
26 verilog='//', vhdl='--', wsf='<!--|-->', xml='<!--|-->', yaml='#', zig='//',
27 nim='#', julia='#', rpmspec='#', caml='(*|*)'
28 }
29
30 -- escape all magic characters with a '%'
31 local function esc(str)
32 if not str then return "" end
33 return (str:gsub('[[.+*?$^()%%%]-]', '%%%0'))
34 end
35
36 -- escape '%'
37 local function pesc(str)
38 if not str then return "" end
39 return str:gsub('%%', '%%%%')
40 end
41
42 local function rtrim(s)
43 local n = #s
44 while n > 0 and s:find("^%s", n) do n = n - 1 end
45 return s:sub(1, n)
46 end
47
48 local function comment_line(lines, lnum, prefix, suffix)
49 if suffix ~= "" then suffix = " " .. suffix end
50 lines[lnum] = string.gsub(lines[lnum],
51 "(%s*)(.*)",
52 "%1" .. pesc(prefix) .. " %2" .. pesc(suffix))
53 end
54
55 local function uncomment_line(lines, lnum, prefix, suffix)
56 local match_str = "^(%s*)" .. esc(prefix) .. "%s?(.*)" .. esc(suffix)
57 local m = table.pack(lines[lnum]:match(match_str))
58 lines[lnum] = m[1] .. rtrim(m[2])
59 end
60
61 local function is_comment(line, prefix)
62 return (line:match("^%s*(.+)"):sub(0, #prefix) == prefix)
63 end
64
65 local function toggle_line_comment(lines, lnum, prefix, suffix)
66 if not lines or not lines[lnum] then return end
67 if not lines[lnum]:match("^%s*(.+)") then return end -- ignore empty lines
68 if is_comment(lines[lnum], prefix) then
69 uncomment_line(lines, lnum, prefix, suffix)
70 else
71 comment_line(lines, lnum, prefix, suffix)
72 end
73 end
74
75 -- if one line inside the block is not a comment, comment the block.
76 -- only uncomment, if every single line is comment.
77 local function block_comment(lines, a, b, prefix, suffix)
78 local uncomment = true
79 for i=a,b do
80 if lines[i]:match("^%s*(.+)") and not is_comment(lines[i], prefix) then
81 uncomment = false
82 end
83 end
84
85 if uncomment then
86 for i=a,b do
87 if lines[i]:match("^%s*(.+)") then
88 uncomment_line(lines, i, prefix, suffix)
89 end
90 end
91 else
92 for i=a,b do
93 if lines[i]:match("^%s*(.+)") then
94 comment_line(lines, i, prefix, suffix)
95 end
96 end
97 end
98 end
99
100 vis:operator_new("gc", function(file, range, pos)
101 local comment = comment_string[vis.win.syntax]
102 local prefix, suffix = comment:match('^([^|]+)|?([^|]*)$')
103 if not prefix then return end
104
105 local c = 0
106 local i = 1
107 local a = -1
108 local b = -1
109 for line in file:lines_iterator() do
110 local line_start = c
111 local line_finish = c + #line + 1
112 if line_start < range.finish and line_finish > range.start then
113 if a == -1 then
114 a = i
115 b = i
116 else
117 b = i
118 end
119 end
120 c = line_finish
121 if c > range.finish then break end
122 i = i + 1
123 end
124 block_comment(file.lines, a, b, prefix, suffix)
125
126 return range.start
127 end, "Toggle comment on selected lines")
128
129 vis:map(vis.modes.NORMAL, "gcc", function()
130 local win = vis.win
131 local lines = win.file.lines
132 local comment = comment_string[win.syntax]
133 if not comment then return end
134 local prefix, suffix = comment:match('^([^|]+)|?([^|]*)$')
135 if not prefix then return end
136
137 for sel in win:selections_iterator() do
138 local lnum = sel.line
139 local col = sel.col
140
141 toggle_line_comment(lines, lnum, prefix, suffix)
142 sel:to(lnum, col) -- restore cursor position
143 end
144
145 win:draw()
146 end, "Toggle comment on a the current line")
147