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")