2018-10-01 14:03:17 +00:00
|
|
|
/* global linter editors clipString createLinterHelpDialog makeSectionVisible */
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
// eslint-disable-next-line no-var
|
|
|
|
Object.assign(linter, (() => {
|
|
|
|
const tables = new Map();
|
|
|
|
const helpDialog = createLinterHelpDialog(getIssues);
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
$('#lint-help').addEventListener('click', helpDialog.show);
|
|
|
|
}, {once: true});
|
|
|
|
|
|
|
|
linter.onLintingUpdated((annotationsNotSorted, annotations, cm) => {
|
|
|
|
let table = tables.get(cm);
|
|
|
|
if (!table) {
|
|
|
|
table = createTable(cm);
|
|
|
|
tables.set(cm, table);
|
|
|
|
const container = $('.lint-report-container');
|
|
|
|
if (typeof editor === 'object') {
|
|
|
|
container.append(table.element);
|
|
|
|
} else {
|
|
|
|
const nextSibling = findNextSibling(tables, cm);
|
|
|
|
container.insertBefore(table.element, nextSibling && tables.get(nextSibling).element);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
table.updateCaption();
|
|
|
|
table.updateAnnotations(annotations);
|
|
|
|
updateCount();
|
|
|
|
});
|
|
|
|
|
|
|
|
linter.onUnhook(cm => {
|
|
|
|
const table = tables.get(cm);
|
|
|
|
if (table) {
|
|
|
|
table.element.remove();
|
|
|
|
tables.delete(cm);
|
|
|
|
}
|
|
|
|
updateCount();
|
|
|
|
});
|
|
|
|
|
|
|
|
return {refreshReport};
|
|
|
|
|
|
|
|
function updateCount() {
|
|
|
|
const issueCount = Array.from(tables.values())
|
|
|
|
.reduce((sum, table) => sum + table.trs.length, 0);
|
|
|
|
$('#lint').classList.toggle('hidden', issueCount === 0);
|
|
|
|
$('#issue-count').textContent = issueCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getIssues() {
|
|
|
|
const issues = new Set();
|
|
|
|
for (const table of tables.values()) {
|
|
|
|
for (const tr of table.trs) {
|
|
|
|
issues.add(tr.getAnnotation());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return issues;
|
|
|
|
}
|
|
|
|
|
|
|
|
function findNextSibling(tables, cm) {
|
|
|
|
let i = editors.indexOf(cm) + 1;
|
|
|
|
while (i < editors.length) {
|
|
|
|
if (tables.has(editors[i])) {
|
|
|
|
return editors[i];
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function refreshReport() {
|
|
|
|
for (const table of tables.values()) {
|
|
|
|
table.updateCaption();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function createTable(cm) {
|
|
|
|
const caption = $create('caption');
|
|
|
|
const tbody = $create('tbody');
|
|
|
|
const table = $create('table', [caption, tbody]);
|
|
|
|
const trs = [];
|
|
|
|
return {
|
|
|
|
element: table,
|
|
|
|
trs,
|
|
|
|
updateAnnotations,
|
|
|
|
updateCaption
|
|
|
|
};
|
|
|
|
|
|
|
|
function updateCaption() {
|
|
|
|
caption.textContent = typeof editor === 'object' ?
|
|
|
|
'' : `${t('sectionCode')} ${editors.indexOf(cm) + 1}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateAnnotations(lines) {
|
|
|
|
let i = 0;
|
|
|
|
for (const anno of getAnnotations()) {
|
|
|
|
let tr;
|
|
|
|
if (i < trs.length) {
|
|
|
|
tr = trs[i];
|
|
|
|
} else {
|
|
|
|
tr = createTr();
|
|
|
|
trs.push(tr);
|
|
|
|
tbody.append(tr.element);
|
|
|
|
}
|
|
|
|
tr.update(anno);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (i === 0) {
|
|
|
|
trs.length = 0;
|
|
|
|
tbody.textContent = '';
|
|
|
|
} else {
|
|
|
|
while (trs.length > i) {
|
|
|
|
trs.pop().element.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
table.classList.toggle('empty', trs.length === 0);
|
|
|
|
|
|
|
|
function *getAnnotations() {
|
|
|
|
for (const line of lines.filter(Boolean)) {
|
|
|
|
yield *line;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function createTr() {
|
|
|
|
let anno;
|
|
|
|
const severityIcon = $create('div');
|
|
|
|
const severity = $create('td', {attributes: {role: 'severity'}}, severityIcon);
|
|
|
|
const line = $create('td', {attributes: {role: 'line'}});
|
|
|
|
const col = $create('td', {attributes: {role: 'col'}});
|
|
|
|
const message = $create('td', {attributes: {role: 'message'}});
|
|
|
|
|
|
|
|
const trElement = $create('tr', {
|
|
|
|
onclick: () => gotoLintIssue(cm, anno)
|
|
|
|
}, [
|
|
|
|
severity,
|
|
|
|
line,
|
|
|
|
$create('td', {attributes: {role: 'sep'}}, ':'),
|
|
|
|
col,
|
|
|
|
message
|
|
|
|
]);
|
|
|
|
return {
|
|
|
|
element: trElement,
|
|
|
|
update,
|
|
|
|
getAnnotation: () => anno
|
|
|
|
};
|
|
|
|
|
|
|
|
function update(_anno) {
|
|
|
|
anno = _anno;
|
|
|
|
trElement.className = anno.severity;
|
|
|
|
severity.dataset.rule = anno.rule;
|
|
|
|
severityIcon.className = `CodeMirror-lint-marker-${anno.severity}`;
|
|
|
|
severityIcon.textContent = anno.severity;
|
|
|
|
line.textContent = anno.from.line + 1;
|
|
|
|
col.textContent = anno.from.ch + 1;
|
|
|
|
message.title = clipString(anno.message, 1000) + `\n(${anno.rule})`;
|
|
|
|
message.textContent = clipString(anno.message, 100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function gotoLintIssue(cm, anno) {
|
2018-10-09 15:38:29 +00:00
|
|
|
editor.scrollToEditor(cm);
|
2018-10-01 14:03:17 +00:00
|
|
|
cm.focus();
|
|
|
|
cm.setSelection(anno.from);
|
|
|
|
}
|
|
|
|
})());
|