From 207fc803e1ceffb384ef9d0c6b2f2614bc8fdb67 Mon Sep 17 00:00:00 2001
From: "David B. Lamkins" <david@lamkins.net>
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