aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/autoload/man.vim14
-rw-r--r--runtime/lua/man.lua87
-rw-r--r--runtime/syntax/man.vim15
3 files changed, 62 insertions, 54 deletions
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
index 0a502be4c7..d20b8c05b0 100644
--- a/runtime/autoload/man.vim
+++ b/runtime/autoload/man.vim
@@ -161,7 +161,7 @@ function! s:put_page(page) abort
while getline(1) =~# '^\s*$'
silent keepjumps 1delete _
endwhile
- call man#highlight_formatted_text()
+ lua require("man").highlight_man_page()
setlocal filetype=man
endfunction
@@ -375,7 +375,7 @@ function! man#init_pager() abort
else
keepjumps 1
endif
- call man#highlight_formatted_text()
+ lua require("man").highlight_man_page()
" This is not perfect. See `man glDrawArraysInstanced`. Since the title is
" all caps it is impossible to tell what the original capitilization was.
let ref = substitute(matchstr(getline(1), '^[^)]\+)'), ' ', '_', 'g')
@@ -387,14 +387,4 @@ function! man#init_pager() abort
execute 'silent file man://'.fnameescape(ref)
endfunction
-function! man#highlight_formatted_text() abort
- let l:modifiable = &modifiable
- set modifiable
-
- lua man = require("man")
- luado return man.highlight_formatted(line, linenr)
-
- let &modifiable = l:modifiable
-endfunction
-
call s:init()
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 }
diff --git a/runtime/syntax/man.vim b/runtime/syntax/man.vim
index 0544fb29e2..b8e605cb9a 100644
--- a/runtime/syntax/man.vim
+++ b/runtime/syntax/man.vim
@@ -18,18 +18,9 @@ highlight default link manOptionDesc Constant
highlight default link manReference PreProc
highlight default link manSubHeading Function
-function! s:init_highlight_groups()
- highlight default manUnderline cterm=underline gui=underline
- highlight default manBold cterm=bold gui=bold
- highlight default manItalic cterm=italic gui=italic
-endfunction
-
-augroup man_init_highlight_groups
- autocmd!
- autocmd ColorScheme * call s:init_highlight_groups()
-augroup END
-
-call s:init_highlight_groups()
+highlight default manUnderline cterm=underline gui=underline
+highlight default manBold cterm=bold gui=bold
+highlight default manItalic cterm=italic gui=italic
if &filetype != 'man'
" May have been included by some other filetype.