coc.nvim
Version:
LSP based intellisense engine for neovim & vim8.
213 lines • 6.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const string_1 = require("./string");
const foregroundColors = {
30: 'black',
31: 'red',
32: 'green',
33: 'yellow',
34: 'blue',
35: 'magenta',
36: 'cyan',
37: 'white',
90: 'grey'
};
const backgroundColors = {
40: 'black',
41: 'red',
42: 'green',
43: 'yellow',
44: 'blue',
45: 'magenta',
46: 'cyan',
47: 'white'
};
const styles = {
1: 'bold',
3: 'italic',
4: 'underline'
};
function parseAnsiHighlights(line) {
let items = ansiparse(line);
let highlights = [];
let newLabel = '';
for (let item of items) {
if (!item.text)
continue;
let { foreground, background } = item;
let len = string_1.byteLength(newLabel);
if (foreground || background) {
let span = [len, len + string_1.byteLength(item.text)];
let hlGroup = '';
if (foreground && background) {
hlGroup = `CocList${string_1.upperFirst(foreground)}${string_1.upperFirst(background)}`;
}
else if (foreground) {
hlGroup = `CocListFg${string_1.upperFirst(foreground)}`;
}
else if (background) {
hlGroup = `CocListBg${string_1.upperFirst(background)}`;
}
highlights.push({ span, hlGroup });
}
newLabel = newLabel + item.text;
}
return { line: newLabel, highlights };
}
exports.parseAnsiHighlights = parseAnsiHighlights;
function ansiparse(str) {
//
// I'm terrible at writing parsers.
//
let matchingControl = null;
let matchingData = null;
let matchingText = '';
let ansiState = [];
let result = [];
let state = {};
let eraseChar;
//
// General workflow for this thing is:
// \033\[33mText
// | | |
// | | matchingText
// | matchingData
// matchingControl
//
// \033\[K or \033\[m
//
// In further steps we hope it's all going to be fine. It usually is.
//
//
// Erases a char from the output
//
eraseChar = () => {
let index;
let text;
if (matchingText.length) {
matchingText = matchingText.substr(0, matchingText.length - 1);
}
else if (result.length) {
index = result.length - 1;
text = result[index].text;
if (text.length === 1) {
//
// A result bit was fully deleted, pop it out to simplify the final output
//
result.pop();
}
else {
result[index].text = text.substr(0, text.length - 1);
}
}
};
for (let i = 0; i < str.length; i++) { // tslint:disable-line
if (matchingControl != null) {
if (matchingControl == '\x1b' && str[i] == '\[') {
//
// We've matched full control code. Lets start matching formating data.
//
//
// "emit" matched text with correct state
//
if (matchingText) {
state.text = matchingText;
result.push(state);
state = {};
matchingText = '';
}
if (matchingText == '' && (str[i + 1] == 'm' || str[i + 1] == 'K')) {
if (state.foreground || state.background) {
state.text = '';
result.push(state);
}
state = {};
}
matchingControl = null;
matchingData = '';
}
else {
//
// We failed to match anything - most likely a bad control code. We
// go back to matching regular strings.
//
matchingText += matchingControl + str[i];
matchingControl = null;
}
continue;
}
else if (matchingData != null) {
if (str[i] == ';') {
//
// `;` separates many formatting codes, for example: `\033[33;43m`
// means that both `33` and `43` should be applied.
//
// TODO: this can be simplified by modifying state here.
//
ansiState.push(matchingData);
matchingData = '';
}
else if (str[i] == 'm' || str[i] == 'K') {
//
// `m` finished whole formatting code. We can proceed to matching
// formatted text.
//
ansiState.push(matchingData);
matchingData = null;
matchingText = '';
//
// Convert matched formatting data into user-friendly state object.
//
// TODO: DRY.
//
ansiState.forEach(ansiCode => {
if (foregroundColors[ansiCode]) {
state.foreground = foregroundColors[ansiCode];
}
else if (backgroundColors[ansiCode]) {
state.background = backgroundColors[ansiCode];
}
else if (ansiCode == 39) {
delete state.foreground;
}
else if (ansiCode == 49) {
delete state.background;
}
else if (styles[ansiCode]) {
state[styles[ansiCode]] = true;
}
else if (ansiCode == 22) {
state.bold = false;
}
else if (ansiCode == 23) {
state.italic = false;
}
else if (ansiCode == 24) {
state.underline = false;
}
});
ansiState = [];
}
else {
matchingData += str[i];
}
continue;
}
if (str[i] == '\x1b') {
matchingControl = str[i];
}
else if (str[i] == '\u0008') {
eraseChar();
}
else {
matchingText += str[i];
}
}
if (matchingText) {
state.text = matchingText + (matchingControl ? matchingControl : '');
result.push(state);
}
return result;
}
exports.ansiparse = ansiparse;
//# sourceMappingURL=ansiparse.js.map