From 207fc803e1ceffb384ef9d0c6b2f2614bc8fdb67 Mon Sep 17 00:00:00 2001 From: "David B. Lamkins" Date: Sun, 1 Oct 2017 10:43:56 -0700 Subject: [PATCH] Add vis-highlight command. --- README.md | 2 + man/vis-highlight.1 | 41 +++++++++++++++++++++++ vis-highlight | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 man/vis-highlight.1 create mode 100755 vis-highlight --- a/README.md +++ b/README.md @@ -53,6 +53,8 @@ compatible environment as well as: * [Lua](http://www.lua.org/) >= 5.2 (optional) * [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/) >= 0.12 (optional runtime dependency required for syntax highlighting) + * [lua-term](https://github.com/hoelzro/lua-term) >= 0.07 + (optional runtime dependency required for CLI highlighting using vis-highlight) * [TRE](http://laurikari.net/tre/) (optional for more memory efficient regex search) Assuming these dependencies are met, execute: --- /dev/null +++ b/man/vis-highlight.1 @@ -0,0 +1,41 @@ +.Dd October 1, 2017 +.Dt VIS-HIGHLIGHT 1 +.Os Vis VERSION +. +.Sh NAME +.Nm vis-highlight +.Nd Highlight files using vis' lexers +. +.Sh SYNOPSIS +.Nm vis-highlight +.Ar lexer +.Ar files +. +.Sh DESCRIPTION +.Nm vis-highlight +applies a vis lexer to highlight one or more files to standard output. +. +.Sh ENVIRONMENT +. +The following environment variables affect the operation of +.Nm vis-highlight : +. +.Bl -tag -width Ev +.It Ev VIS_PATH +The default path to use to load Lua support files. +.El +. +.Sh EXIT STATUS +.Ex -std vis-highlight +. +.Sh EXAMPLES +Highlight the visrc.lua file: +.Bd -literal -offset indent +vis-highlight lua ~/.config/vis/visrc.lua +.Ed +. +.Sh BUGS +An ANSI-compatible terminal is assumed. +. +.Sh SEE ALSO +.Xr vis 1 --- /dev/null +++ b/vis-highlight @@ -0,0 +1,89 @@ +#! /usr/bin/env lua + +-- Standalone syntax highlighter uses the lexers provided by `vis`. + +if #arg < 2 then + print('usage: ' .. arg[0] .. ' LEXER-NAME FILE...') + return 1 +end + +vis_path = os.getenv('VIS_PATH') +if vis_path ~= nil then + package.path = package.path .. ';' .. vis_path .. '/?.lua' +end +package.path = package.path .. ';/usr/local/share/vis/?.lua' +package.path = package.path .. ';/usr/share/vis/?.lua' + +local syntax = arg[1] +local lexers = require('lexer') +local lexer = lexers.load(syntax) + +if not lexer then + print(string.format('Failed to load lexer: `%s`', syntax)) + return 1 +end + +local term = require('term') +local colors = term.colors + +local token_styles = { + -- bold => bright + -- italics => underscore + ['default'] = colors.default .. colors.onblack .. colors.white, + ['nothing'] = colors.default .. colors.onblack, + ['class'] = colors.default .. colors.yellow .. colors.bright, + ['comment'] = colors.default .. colors.blue .. colors.bright, + ['constant'] = colors.default .. colors.cyan .. colors.bright, + ['definition'] = colors.default .. colors.blue .. colors.bright, + ['error'] = colors.default .. colors.red .. colors.underscore, + ['function'] = colors.default .. colors.blue .. colors.bright, + ['keyword'] = colors.default .. colors.yellow .. colors.bright, + ['label'] = colors.default .. colors.green .. colors.bright, + ['number'] = colors.default .. colors.red .. colors.bright, + ['operator'] = colors.default .. colors.cyan .. colors.bright, + ['regex'] = colors.default .. colors.green .. colors.bright, + ['string'] = colors.default .. colors.red .. colors.bright, + ['preprocessor'] = colors.default .. colors.magenta .. colors.bright, + ['tag'] = colors.default .. colors.red .. colors.bright, + ['type'] = colors.default .. colors.green .. colors.bright, + ['variable'] = colors.default .. colors.blue .. colors.bright, + ['whitespace'] = '', + ['embedded'] = colors.default .. colors.onblue .. colors.bright, + ['identifier'] = colors.default .. colors.white, +} + +for i = 2, #arg do + local filename = arg[i] + local file = assert(io.open(filename, 'r')) + local text = file:read('*all') + file:close() + local tokens = lexer:lex(text, 1) + local token_start = 1 + local last = '' + + for i = 1, #tokens, 2 do + local token_end = tokens[i+1] - 1 + local name = tokens[i] + local style = token_styles[name] + if style ~= nil then + -- Whereas the lexer reports all other syntaxes over + -- the entire span of a token, it reports 'default' + -- byte-by-byte. We emit only the first 'default' of + -- a series in order to properly display multibyte + -- UTF-8 characters. + if not (last == 'default' and name == 'default') then + io.write(tostring(style)) + end + last = name + end + local token = text:sub(token_start, token_end) + if style ~= nil then + -- Replicate the style after every newline within + -- the token, because less -R forgets attributes + -- with each newline. + token = token:gsub("\n", "\n" .. tostring(style)) + end + io.write(token) + token_start = token_end + 1 + end +end