aboutsummaryrefslogtreecommitdiffstats
path: root/vis-commentary.lua
blob: 1c4cc1a1ca199779498a8f94d681ec5d5591a753 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
local comment_string = {
    actionscript='//', ada='--', adpl='!', ansi_c='/*|*/', antlr='//', apl='#',
    applescript='--', asp='\'', autoit=';', awk='#', b_lang='//', bash='#',
    batch=':', bibtex='%', boo='#', chuck='//', cmake='#', coffeescript='#',
    context='%', cpp='//', crystal='#', csharp='//', css='/*|*/', cuda='//',
    desktop='#', django='{#|#}', dmd='//', dockerfile='#', dot='//',
    eiffel='--', elixir='#', erlang='%', faust='//', fish='#', forth='|\\',
    fortran='!', fsharp='//', gap='#', gettext='#', gherkin='#', glsl='//',
    gnuplot='#', go='//', groovy='//', gtkrc='#', haskell='--', html='<!--|-->',
    icon='#', idl='//', inform='!', ini='#', Io='#', java='//', javascript='//',
    json='/*|*/', jsp='//', latex='%', ledger='#', less='//', lilypond='%',
    lisp=';', logtalk='%', lua='--', makefile='#', matlab='#', moonscript='--',
    myrddin='//', nemerle='//', nsis='#', objective_c='//', pascal='//',
    perl='#', php='//', pico8='//', pike='//', pkgbuild='#', prolog='%',
    props='#', protobuf='//', ps='%', pure='//', python='#', rails='#', rc='#',
    rebol=';', rest='.. ', rexx='--', rhtml='<!--|-->', rstats='#', ruby='#',
    rust='//', sass='//', scala='//', scheme=';', smalltalk='"|"', sml='(*)',
    snobol4='#', sql='#', tcl='#', tex='%', text='', toml='#', vala='//',
    vb='\'', vbscript='\'', verilog='//', vhdl='--', wsf='<!--|-->',
    xml='<!--|-->', yaml='#'
}

-- escape all magic characters with a '%'
local function esc(str)
    if not str then return "" end
    return (str:gsub('%%', '%%%%')
        :gsub('^%^', '%%^')
        :gsub('%$$', '%%$')
        :gsub('%(', '%%(')
        :gsub('%)', '%%)')
        :gsub('%.', '%%.')
        :gsub('%[', '%%[')
        :gsub('%]', '%%]')
        :gsub('%*', '%%*')
        :gsub('%+', '%%+')
        :gsub('%-', '%%-')
        :gsub('%?', '%%?'))
end

-- escape only '%' as it is the only magic character in string.format
local function f_esc(str)
    if not str then return "" end
    return str:gsub('%%', '%%%%')
end

local function toggle_line_comment(lines, lnum, prefix, suffix)
    if not lines or not lines[lnum] then return end

    local stripped = lines[lnum]:match("^%s*(.+)") -- empty lines: nil
    if not stripped then return end

    -- remove comment
    if lines[lnum]:match("^%s*(.+)"):sub(0, #prefix) == prefix then
        local match_str = "^(%s*)" .. esc(prefix) .. "%s?(.*)" .. esc(suffix)
        lines[lnum] = table.concat(table.pack(lines[lnum]:match(match_str)))

    -- add comment
    else
        if suffix ~= "" then suffix = " " .. suffix end
        local format_str = f_esc(prefix) .. " %s" .. f_esc(suffix)
        lines[lnum] = string.format(format_str, lines[lnum])
    end
end

vis:map(vis.modes.NORMAL, "gcc", function()
    local win = vis.win
    local lines = win.file.lines
    local lnum = win.selection.line
    local col = win.selection.col

    local comment = comment_string[win.syntax]
    if not comment then return end

    local prefix, suffix = comment:match('^([^|]+)|?([^|]*)$')
    if not prefix then return end

    toggle_line_comment(lines, lnum, prefix, suffix)
    win:draw()
    win.selection:to(lnum, col)  -- restore cursor position
end, "Toggle comment on a the current line")

local function visual_f(i)
    return function()
        local win = vis.win
        local r = win.selection.range
        local lnum = win.selection.line     -- line number of cursor
        local col = win.selection.col       -- column of cursor

        local comment = comment_string[win.syntax]
        if not comment then return end

        local prefix, suffix = comment:match('^([^|]+)|?([^|]*)$')
        if not prefix then return end

        if win.selection.anchored and r then
            win.selection.pos = r.start
            local a = win.selection.line
            win.selection.pos = r.finish
            local b = win.selection.line - i

            local lines = win.file.lines

            for i = a,b do
                if not lines[i]:match("^%s*$") then -- ignore empty lines
                    toggle_line_comment(lines, i, prefix, suffix)
                end
            end

            win:draw()
            win.selection:to(lnum, col)     -- restore cursor position
            vis.mode = vis.modes.NORMAL     -- go to normal mode
        end
    end
end

vis:map(vis.modes.VISUAL_LINE, "gc", visual_f(1), "Toggle comment on the selected lines")
vis:map(vis.modes.VISUAL, "gc", visual_f(0), "Toggle comment on the selected lines")