dotfiles

configuration files for shell, text editor, graphical environment, etc.
git clone git://src.adamsgaard.dk/dotfiles
Log | Files | Refs | README | LICENSE

vis-commentary.lua (5509B)


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