From c28ce5f6191d233228d1688de300727e1ae42831 Mon Sep 17 00:00:00 2001 From: Gabriel Holodak Date: Mon, 20 Nov 2017 00:19:08 -0500 Subject: Switch to processing in Lua --- runtime/lua/man.lua | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 runtime/lua/man.lua (limited to 'runtime/lua/man.lua') diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua new file mode 100644 index 0000000000..63c2c14480 --- /dev/null +++ b/runtime/lua/man.lua @@ -0,0 +1,75 @@ +local function highlight_backspaced(line, linenr) + local chars = {} + local prev_char = '' + local overstrike = false + local hls = {} -- Store highlight groups as { attr, start, end } + local NONE, BOLD, UNDERLINE = 0, 1, 2 + local attr = NONE + local byte = 0 -- byte offset + + -- Break input into UTF8 characters + for char in line:gmatch("[^\128-\191][\128-\191]*") do + if overstrike then + local last_hl = hls[#hls] + if char == prev_char then + if char == '_' and attr == UNDERLINE and last_hl and last_hl[3] == byte then + -- This underscore is in the middle of an underlined word + attr = UNDERLINE + else + attr = BOLD + end + elseif prev_char == '_' then + -- char is underlined + attr = UNDERLINE + elseif prev_char == '+' and char == 'o' then + -- bullet (overstrike text '+^Ho') + attr = BOLD + char = [[·]] + elseif prev_char == [[·]] and char == 'o' then + -- bullet (additional handling for '+^H+^Ho^Ho') + attr = BOLD + char = [[·]] + else + -- use plain char + attr = NONE + end + + -- Grow the previous highlight group if possible + if last_hl and last_hl[1] == attr and last_hl[3] == byte then + last_hl[3] = byte + #char + else + hls[#hls + 1] = {attr, byte, byte + #char} + end + + overstrike = false + prev_char = '' + byte = byte + #char + chars[#chars + 1] = char + elseif char == "\b" then + overstrike = true + prev_char = chars[#chars] + byte = byte - #prev_char + chars[#chars] = nil + else + byte = byte + #char + chars[#chars + 1] = char + end + end + + for i, hl in ipairs(hls) do + if hl[1] ~= NONE then + vim.api.nvim_buf_add_highlight( + 0, + -1, + hl[1] == BOLD and "manBold" or "manUnderline", + linenr - 1, + hl[2], + hl[3] + ) + end + end + + return table.concat(chars, '') +end + +return { highlight_backspaced = highlight_backspaced } -- cgit From 6740c94562cc1b271a6ea2458ebb847a6e3665e2 Mon Sep 17 00:00:00 2001 From: Gabriel Holodak Date: Thu, 30 Nov 2017 22:15:39 -0500 Subject: Add support for escape sequences --- runtime/lua/man.lua | 76 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 5 deletions(-) (limited to 'runtime/lua/man.lua') diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua index 63c2c14480..c3d7df2a2a 100644 --- a/runtime/lua/man.lua +++ b/runtime/lua/man.lua @@ -1,12 +1,60 @@ -local function highlight_backspaced(line, linenr) +local function highlight_formatted(line, linenr) local chars = {} local prev_char = '' - local overstrike = false + local overstrike, escape = false, false local hls = {} -- Store highlight groups as { attr, start, end } - local NONE, BOLD, UNDERLINE = 0, 1, 2 + local NONE, BOLD, UNDERLINE, ITALIC = 0, 1, 2, 3 + local hl_groups = {[BOLD]="manBold", [UNDERLINE]="manUnderline", [ITALIC]="manItalic"} local attr = NONE local byte = 0 -- byte offset + local function end_attr_hl(attr) + for i, hl in ipairs(hls) do + if hl[1] == attr and hl[3] == -1 then + hl[3] = byte + hls[i] = hl + end + end + end + + local function add_attr_hl(code) + local on = true + if code == 0 then + attr = NONE + on = false + elseif code == 1 then + attr = BOLD + elseif code == 21 or code == 22 then + attr = BOLD + on = false + elseif code == 3 then + attr = ITALIC + elseif code == 23 then + attr = ITALIC + on = false + elseif code == 4 then + attr = UNDERLINE + elseif code == 24 then + attr = UNDERLINE + on = false + else + attr = NONE + return + end + + if on then + hls[#hls + 1] = {attr, byte, -1} + else + if attr == NONE then + for a, _ in pairs(hl_groups) do + end_attr_hl(a) + end + else + end_attr_hl(attr) + end + end + end + -- Break input into UTF8 characters for char in line:gmatch("[^\128-\191][\128-\191]*") do if overstrike then @@ -45,6 +93,24 @@ local function highlight_backspaced(line, linenr) prev_char = '' byte = byte + #char chars[#chars + 1] = char + elseif escape then + -- Use prev_char to store the escape sequence + prev_char = prev_char .. char + local sgr = prev_char:match("^%[([\020-\063]*)m$") + if sgr then + local match = '' + while sgr and #sgr > 0 do + match, sgr = sgr:match("^(%d*);?(.*)") + add_attr_hl(match + 0) -- coerce to number + end + escape = false + elseif not prev_char:match("^%[[\020-\063]*$") then + -- Stop looking if this isn't a partial CSI sequence + escape = false + end + elseif char == "\027" then + escape = true + prev_char = '' elseif char == "\b" then overstrike = true prev_char = chars[#chars] @@ -61,7 +127,7 @@ local function highlight_backspaced(line, linenr) vim.api.nvim_buf_add_highlight( 0, -1, - hl[1] == BOLD and "manBold" or "manUnderline", + hl_groups[hl[1]], linenr - 1, hl[2], hl[3] @@ -72,4 +138,4 @@ local function highlight_backspaced(line, linenr) return table.concat(chars, '') end -return { highlight_backspaced = highlight_backspaced } +return { highlight_formatted = highlight_formatted } -- cgit From eb44519b5debf740f692bb4ea19ad83b29749484 Mon Sep 17 00:00:00 2001 From: Gabriel Holodak Date: Sun, 24 Dec 2017 12:16:58 -0500 Subject: Address PR comments --- runtime/lua/man.lua | 87 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 30 deletions(-) (limited to 'runtime/lua/man.lua') diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua index c3d7df2a2a..baa522f343 100644 --- a/runtime/lua/man.lua +++ b/runtime/lua/man.lua @@ -1,8 +1,10 @@ -local function highlight_formatted(line, linenr) +local buf_hls = {} + +local function highlight_line(line, linenr) local chars = {} local prev_char = '' local overstrike, escape = false, false - local hls = {} -- Store highlight groups as { attr, start, end } + local hls = {} -- Store highlight groups as { attr, start, final } local NONE, BOLD, UNDERLINE, ITALIC = 0, 1, 2, 3 local hl_groups = {[BOLD]="manBold", [UNDERLINE]="manUnderline", [ITALIC]="manItalic"} local attr = NONE @@ -10,40 +12,40 @@ local function highlight_formatted(line, linenr) local function end_attr_hl(attr) for i, hl in ipairs(hls) do - if hl[1] == attr and hl[3] == -1 then - hl[3] = byte + if hl.attr == attr and hl.final == -1 then + hl.final = byte hls[i] = hl end end end local function add_attr_hl(code) - local on = true + local continue_hl = true if code == 0 then attr = NONE - on = false + continue_hl = false elseif code == 1 then attr = BOLD - elseif code == 21 or code == 22 then + elseif code == 22 then attr = BOLD - on = false + continue_hl = false elseif code == 3 then attr = ITALIC elseif code == 23 then attr = ITALIC - on = false + continue_hl = false elseif code == 4 then attr = UNDERLINE elseif code == 24 then attr = UNDERLINE - on = false + continue_hl = false else attr = NONE return end - if on then - hls[#hls + 1] = {attr, byte, -1} + if continue_hl then + hls[#hls + 1] = {attr=attr, start=byte, final=-1} else if attr == NONE then for a, _ in pairs(hl_groups) do @@ -55,12 +57,15 @@ local function highlight_formatted(line, linenr) end end - -- Break input into UTF8 characters + -- Break input into UTF8 code points. ASCII code points (from 0x00 to 0x7f) + -- can be represented in one byte. Any code point above that is represented by + -- a leading byte (0xc0 and above) and continuation bytes (0x80 to 0xbf, or + -- decimal 128 to 191). for char in line:gmatch("[^\128-\191][\128-\191]*") do if overstrike then local last_hl = hls[#hls] if char == prev_char then - if char == '_' and attr == UNDERLINE and last_hl and last_hl[3] == byte then + if char == '_' and attr == UNDERLINE and last_hl and last_hl.final == byte then -- This underscore is in the middle of an underlined word attr = UNDERLINE else @@ -72,21 +77,21 @@ local function highlight_formatted(line, linenr) elseif prev_char == '+' and char == 'o' then -- bullet (overstrike text '+^Ho') attr = BOLD - char = [[·]] - elseif prev_char == [[·]] and char == 'o' then + char = '·' + elseif prev_char == '·' and char == 'o' then -- bullet (additional handling for '+^H+^Ho^Ho') attr = BOLD - char = [[·]] + char = '·' else -- use plain char attr = NONE end -- Grow the previous highlight group if possible - if last_hl and last_hl[1] == attr and last_hl[3] == byte then - last_hl[3] = byte + #char + if last_hl and last_hl.attr == attr and last_hl.final == byte then + last_hl.final = byte + #char else - hls[#hls + 1] = {attr, byte, byte + #char} + hls[#hls + 1] = {attr=attr, start=byte, final=byte + #char} end overstrike = false @@ -96,15 +101,19 @@ local function highlight_formatted(line, linenr) elseif escape then -- Use prev_char to store the escape sequence prev_char = prev_char .. char - local sgr = prev_char:match("^%[([\020-\063]*)m$") + -- We only want to match against SGR sequences, which consist of ESC + -- followed by '[', then a series of parameter and intermediate bytes in + -- the range 0x20 - 0x3f, then 'm'. (See ECMA-48, sections 5.4 & 8.3.117) + local sgr = prev_char:match("^%[([\032-\063]*)m$") if sgr then local match = '' while sgr and #sgr > 0 do + -- Match against SGR parameters, which may be separated by ';' match, sgr = sgr:match("^(%d*);?(.*)") add_attr_hl(match + 0) -- coerce to number end escape = false - elseif not prev_char:match("^%[[\020-\063]*$") then + elseif not prev_char:match("^%[[\032-\063]*$") then -- Stop looking if this isn't a partial CSI sequence escape = false end @@ -122,20 +131,38 @@ local function highlight_formatted(line, linenr) end end - for i, hl in ipairs(hls) do - if hl[1] ~= NONE then - vim.api.nvim_buf_add_highlight( + for _, hl in ipairs(hls) do + if hl.attr ~= NONE then + buf_hls[#buf_hls + 1] = { 0, -1, - hl_groups[hl[1]], + hl_groups[hl.attr], linenr - 1, - hl[2], - hl[3] - ) + hl.start, + hl.final + } end end return table.concat(chars, '') end -return { highlight_formatted = highlight_formatted } +local function highlight_man_page() + local mod = vim.api.nvim_eval("&modifiable") + vim.api.nvim_command("set modifiable") + + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) + for i, line in ipairs(lines) do + lines[i] = highlight_line(line, i) + end + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + + for _, args in ipairs(buf_hls) do + vim.api.nvim_buf_add_highlight(unpack(args)) + end + buf_hls = {} + + vim.api.nvim_command("let &modifiable = "..mod) +end + +return { highlight_man_page = highlight_man_page } -- cgit From 423d7af3df6de1ab38f9987cafc86499730da5dc Mon Sep 17 00:00:00 2001 From: Filip Szymański Date: Mon, 15 Jan 2018 20:14:27 +0100 Subject: man.lua: avoid float conversion on lua 5.3 (#7851) Error detected while processing function man#open_page[58]..54_put_page: line 8: E5105: Error while calling lua chunk: /usr/share/nvim/runtime/lua/man.lua:165: Vim(let):E805: Using a Float as a Number --- runtime/lua/man.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/man.lua') diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua index baa522f343..b0fbe9cc35 100644 --- a/runtime/lua/man.lua +++ b/runtime/lua/man.lua @@ -148,8 +148,8 @@ local function highlight_line(line, linenr) end local function highlight_man_page() - local mod = vim.api.nvim_eval("&modifiable") - vim.api.nvim_command("set modifiable") + local mod = vim.api.nvim_buf_get_option(0, "modifiable") + vim.api.nvim_buf_set_option(0, "modifiable", true) local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) for i, line in ipairs(lines) do @@ -162,7 +162,7 @@ local function highlight_man_page() end buf_hls = {} - vim.api.nvim_command("let &modifiable = "..mod) + vim.api.nvim_buf_set_option(0, "modifiable", mod) end return { highlight_man_page = highlight_man_page } -- cgit