coc.nvim
Version:
LSP based intellisense engine for neovim & vim8.
254 lines • 9.56 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol");
const callSequence_1 = tslib_1.__importDefault(require("../util/callSequence"));
const object_1 = require("../util/object");
const workspace_1 = tslib_1.__importDefault(require("../workspace"));
const util_1 = require("./util");
const logger = require('../util/logger')('diagnostic-buffer');
const severityNames = ['CocError', 'CocWarning', 'CocInfo', 'CocHint'];
// maintains sign and highlightId
class DiagnosticBuffer {
constructor(doc, config) {
this.config = config;
this.signIds = new Set();
this.sequence = null;
this._onDidRefresh = new vscode_languageserver_protocol_1.Emitter();
this.matchIds = new Set();
this.diagnostics = [];
this.onDidRefresh = this._onDidRefresh.event;
this.bufnr = doc.bufnr;
this.uri = doc.uri;
this.srdId = workspace_1.default.createNameSpace('coc-diagnostic');
let timer = null;
let time = Date.now();
this.refresh = (diagnostics) => {
time = Date.now();
if (timer)
clearTimeout(timer);
timer = setTimeout(async () => {
let current = time;
if (this.sequence) {
await this.sequence.cancel();
}
// staled
if (current != time)
return;
this._refresh(diagnostics);
}, global.hasOwnProperty('__TEST__') ? 30 : 50);
};
}
get nvim() {
return workspace_1.default.nvim;
}
_refresh(diagnostics) {
if (object_1.equals(this.diagnostics, diagnostics))
return;
let { nvim, bufnr } = this;
let sequence = this.sequence = new callSequence_1.default();
let winid;
sequence.addFunction(async () => {
let [valid, id] = await nvim.eval(`[coc#util#valid_state(), bufwinid(${bufnr})]`);
if (valid == 0)
return false;
winid = id;
});
sequence.addFunction(async () => {
nvim.pauseNotification();
this.setDiagnosticInfo(diagnostics);
this.addSigns(diagnostics);
this.setLocationlist(diagnostics, winid);
this.addHighlight(diagnostics, winid);
this.addDiagnosticVText(diagnostics);
let [, err] = await this.nvim.resumeNotification();
if (err)
logger.error('Diagnostic error:', err);
});
sequence.start().then(async (canceled) => {
if (!canceled) {
this.diagnostics = diagnostics;
this._onDidRefresh.fire(void 0);
}
}, e => {
logger.error(e);
});
}
setLocationlist(diagnostics, winid) {
if (!this.config.locationlist)
return;
let { nvim, bufnr } = this;
// not shown
if (winid == -1)
return;
let items = [];
for (let diagnostic of diagnostics) {
let item = util_1.getLocationListItem(diagnostic.source, bufnr, diagnostic);
items.push(item);
}
nvim.call('setloclist', [winid, [], ' ', { title: 'Diagnostics of coc', items }], true);
}
clearSigns() {
let { nvim, signIds, bufnr } = this;
if (signIds.size > 0) {
nvim.call('coc#util#unplace_signs', [bufnr, Array.from(signIds)], true);
signIds.clear();
}
}
async checkSigns() {
let { nvim, bufnr, signIds } = this;
try {
let content = await this.nvim.call('execute', [`sign place buffer=${bufnr}`]);
let lines = content.split('\n');
let ids = [];
for (let line of lines) {
let ms = line.match(/^\s*line=\d+\s+id=(\d+)\s+name=(\w+)/);
if (!ms)
continue;
let [, id, name] = ms;
if (!signIds.has(Number(id)) && severityNames.indexOf(name) != -1) {
ids.push(id);
}
}
await nvim.call('coc#util#unplace_signs', [bufnr, ids]);
}
catch (e) {
// noop
}
}
addSigns(diagnostics) {
if (!this.config.enableSign)
return;
this.clearSigns();
let { nvim, bufnr, signIds } = this;
let signId = this.config.signOffset;
signIds.clear();
let lines = new Set();
for (let diagnostic of diagnostics) {
let { range, severity } = diagnostic;
let line = range.start.line;
if (lines.has(line))
continue;
lines.add(line);
let name = util_1.getNameFromSeverity(severity);
nvim.command(`sign place ${signId} line=${line + 1} name=${name} buffer=${bufnr}`, true);
signIds.add(signId);
signId = signId + 1;
}
}
setDiagnosticInfo(diagnostics) {
let info = { error: 0, warning: 0, information: 0, hint: 0 };
for (let diagnostic of diagnostics) {
switch (diagnostic.severity) {
case vscode_languageserver_protocol_1.DiagnosticSeverity.Warning:
info.warning = info.warning + 1;
break;
case vscode_languageserver_protocol_1.DiagnosticSeverity.Information:
info.information = info.information + 1;
break;
case vscode_languageserver_protocol_1.DiagnosticSeverity.Hint:
info.hint = info.hint + 1;
break;
default:
info.error = info.error + 1;
}
}
this.nvim.call('coc#util#set_buf_var', [this.bufnr, 'coc_diagnostic_info', info], true);
if (!workspace_1.default.getDocument(this.bufnr))
return;
if (workspace_1.default.bufnr == this.bufnr)
this.nvim.command('redraws', true);
this.nvim.call('coc#util#do_autocmd', ['CocDiagnosticChange'], true);
}
addDiagnosticVText(diagnostics) {
let { bufnr, nvim } = this;
if (!this.config.virtualText)
return;
if (!nvim.hasFunction('nvim_buf_set_virtual_text'))
return;
let buffer = this.nvim.createBuffer(bufnr);
let lines = new Set();
let srcId = this.config.virtualTextSrcId;
let prefix = this.config.virtualTextPrefix;
buffer.clearNamespace(srcId);
for (let diagnostic of diagnostics) {
let { line } = diagnostic.range.start;
if (lines.has(line))
continue;
lines.add(line);
let highlight = util_1.getNameFromSeverity(diagnostic.severity) + 'VirtualText';
let msg = diagnostic.message.split(/\n/)
.map((l) => l.trim())
.filter((l) => l.length > 0)
.slice(0, this.config.virtualTextLines)
.join(this.config.virtualTextLineSeparator);
buffer.setVirtualText(srcId, line, [[prefix + msg, highlight]], {}).logError();
}
}
clearHighlight() {
let { bufnr, nvim, matchIds } = this;
let doc = workspace_1.default.getDocument(bufnr);
if (!doc)
return;
doc.clearMatchIds(matchIds);
this.matchIds.clear();
}
addHighlight(diagnostics, winid) {
this.clearHighlight();
if (diagnostics.length == 0)
return;
if (winid == -1 && workspace_1.default.isVim && !workspace_1.default.env.textprop)
return;
let document = workspace_1.default.getDocument(this.bufnr);
if (!document)
return;
const highlights = new Map();
for (let diagnostic of diagnostics) {
let { range, severity } = diagnostic;
let hlGroup = util_1.getNameFromSeverity(severity) + 'Highlight';
let ranges = highlights.get(hlGroup) || [];
ranges.push(range);
highlights.set(hlGroup, ranges);
}
for (let [hlGroup, ranges] of highlights.entries()) {
let matchIds = document.highlightRanges(ranges, hlGroup, this.srdId);
for (let id of matchIds)
this.matchIds.add(id);
}
}
/**
* Used on buffer unload
*
* @public
* @returns {Promise<void>}
*/
async clear() {
if (this.sequence)
await this.sequence.cancel();
let { nvim } = this;
nvim.pauseNotification();
this.clearHighlight();
this.clearSigns();
if (this.config.virtualText && workspace_1.default.isNvim) {
let buffer = this.nvim.createBuffer(this.bufnr);
buffer.clearNamespace(this.config.virtualTextSrcId);
}
if (workspace_1.default.bufnr == this.bufnr) {
nvim.command('unlet b:coc_diagnostic_info', true);
}
else {
this.setDiagnosticInfo([]);
}
await nvim.resumeNotification(false, true);
}
dispose() {
if (this.sequence) {
this.sequence.cancel().catch(_e => {
// noop
});
}
this._onDidRefresh.dispose();
}
}
exports.DiagnosticBuffer = DiagnosticBuffer;
//# sourceMappingURL=buffer.js.map