vis
a vi-like editor based on Plan 9's structural regular expressions
git clone https://9o.is/git/vis.git
number-inc-dec.lua
(1917B)
1 -- increment/decrement number in dec/hex/oct format
2 local lexer = vis.lexers
3 local lpeg = vis.lpeg
4 if not lexer.load or not lpeg then return end
5
6 local Cp = lpeg.Cp()
7 local dec_num = lpeg.S('+-')^-1 * lexer.dec_num
8 local pattern = lpeg.P{ Cp * (lexer.hex_num + lexer.oct_num + dec_num) * Cp + 1 * lpeg.V(1) }
9
10 local change = function(delta)
11
12 local win = vis.win
13 local file = win.file
14 local count = vis.count
15 if not count then count = 1 end
16 vis.count = nil -- reset count, otherwise it affects next motion
17
18 for selection in win:selections_iterator() do
19 local pos = selection.pos
20 if not pos then goto continue end
21 local word = file:text_object_word(pos);
22 if not word then goto continue end
23 local data = file:content(word.start, 1024)
24 if not data then goto continue end
25 local s, e = pattern:match(data)
26 if not s then goto continue end
27 data = string.sub(data, s, e-1)
28 if #data == 0 then goto continue end
29 -- align start and end for fileindex
30 s = word.start + s - 1
31 e = word.start + e - 1
32 local base, format, padding = 10, 'd', 0
33 if lexer.oct_num:match(data) then
34 base = 8
35 format = 'o'
36 padding = #data
37 elseif lexer.hex_num:match(data) then
38 base = 16
39 format = 'x'
40 padding = #data - #"0x"
41 end
42 local number = tonumber(data, base == 8 and 8 or nil)
43 if not number then goto continue end
44 number = number + delta * count
45 -- string.format does not support negative hex/oct values
46 if base ~= 10 and number < 0 then number = 0 end
47 number = string.format((base == 16 and "0x" or "") .. "%0"..padding..format, number)
48 if base == 8 and string.sub(number, 0, 1) ~= "0" then
49 number = '0' .. number
50 end
51 file:delete(s, e - s)
52 file:insert(s, number)
53 selection.pos = s
54 ::continue::
55 end
56 end
57
58 vis:map(vis.modes.NORMAL, "<C-a>", function() change( 1) end, "Increment number")
59 vis:map(vis.modes.NORMAL, "<C-x>", function() change(-1) end, "Decrement number")