Add linter select option

This commit is contained in:
Rob Garrison 2017-08-15 14:13:58 -05:00
parent 139d7ebb98
commit dfa71f699e
19 changed files with 177 additions and 159 deletions

View File

@ -665,8 +665,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "Проблеми, намерени от <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> при следните правила:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "Проблеми, намерени от $link$ при следните правила:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "Значка на иконката на лентата",

View File

@ -653,8 +653,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "Problémy nalezené aplikací <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> s těmito povolenými pravidly:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "Problémy nalezené aplikací $link$ s těmito povolenými pravidly:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "Ikona tlačítka na panelu",

View File

@ -633,8 +633,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "Die von <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> gefunden Fehler haben die folgenden Einstellungen:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "Die von $link$ gefunden Fehler haben die folgenden Einstellungen:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "Badge auf dem Toolbar-Icon",

View File

@ -135,6 +135,10 @@
"message": "Double-click to maximize/restore the height",
"description": "Tooltip for the resize grip in style editor"
},
"cm_linter": {
"message": "CSS Linter",
"description": "Select the linter to check for CSS issues"
},
"dysfunctional": {
"message": "Stylus cannot function because Firefox is either in private mode or is applying its website cookies policy to IndexedDB storage used by Stylus, which erroneously marks the secure moz-extension:// origin as insecure even though WebExtensions aren't websites and Stylus doesn't use cookies.\n\n1. Open Firefox options\n2. Go to 'Privacy & Security'\n3. Set 'History' mode to 'Use custom settings'\n4. Click 'Exceptions'\n5. Paste our manifest URL and click 'Allow'\n6. Click 'Save settings'\n7. Uncheck 'Always use private browsing mode'\n\nThe actual manifest URL is shown below.\nYou can also find it on about:debugging page.",
"description": "Displayed in Firefox when its settings make Stylus dysfunctional"
@ -342,8 +346,13 @@
"description": "Label for the stylelint issues block on the style edit page"
},
"issuesHelp": {
"message": "The issues found by <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> with these rules enabled:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "The issues found by $link$ with these rules enabled:",
"description": "Help popup message for the selected linter issues block on the style edit page",
"placeholders": {
"link": {
"content": "$1"
}
}
},
"manageFilters": {
"message": "Filters",

View File

@ -657,8 +657,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "Problemas encontrados por <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> con estas reglas aplicadas:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "Problemas encontrados por $link$ con estas reglas aplicadas:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "Distintivo en el icono de barra de herramientas",

View File

@ -653,8 +653,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "<a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> poolt leitud vead nende lubatud reeglitega:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "$link$ poolt leitud vead nende lubatud reeglitega:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "Number tööriistaribaikoonil",

View File

@ -649,8 +649,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "これらのルールを有効にして <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> で見つかった問題:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "これらのルールを有効にして $link$ で見つかった問題:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "ツールバーアイコンのバッジ",

View File

@ -345,8 +345,8 @@
"description": "Label for the button to check all styles for updates"
},
"issuesHelp": {
"message": "De door stylelint gevonden problemen, <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a>, met deze ingeschakelde regels:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "De door stylelint gevonden problemen, $link$, met deze ingeschakelde regels:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"confirmNo": {
"message": "Nee",

View File

@ -657,8 +657,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "Problemy znalezione przez <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> z tymi włączonymi regułami:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "Problemy znalezione przez $link$ z tymi włączonymi regułami:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "Emblemat na ikonie paska narzędzi",

View File

@ -657,8 +657,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "Проблемы и предупреждения по версии <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> с данными включенными правилами:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "Проблемы и предупреждения по версии $link$ с данными включенными правилами:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "Бейдж на пиктограмме в тулбаре",

View File

@ -357,8 +357,8 @@
"description": "Label for the button to check all styles for updates"
},
"issuesHelp": {
"message": "Проблем пронађен од стране <a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> са овим омогућеним правилима:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "Проблем пронађен од стране $link$ са овим омогућеним правилима:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"confirmNo": {
"message": "Не",

View File

@ -657,8 +657,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "<a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a> 在已启用的这些规则中找到问题:",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "$link$ 在已启用的这些规则中找到问题:",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "样式计数器",

View File

@ -661,8 +661,8 @@
"description": "Go to Options UI"
},
"issuesHelp": {
"message": "由<a href='https://stylelint.io/user-guide/rules/' target='_blank'>stylelint</a>發現啟用這些規則會產生衝突",
"description": "Help popup message for the stylelint issues block on the style edit page"
"message": "由$link$發現啟用這些規則會產生衝突",
"description": "Help popup message for the selected linter issues block on the style edit page"
},
"optionsCustomizeBadge": {
"message": "在工具列圖示上的徽章",

View File

@ -35,9 +35,12 @@
<link rel="stylesheet" href="vendor/codemirror/addon/lint/lint.css" />
<script src="vendor/codemirror/addon/lint/lint.js"></script>
<script src="vendor-overwrites/codemirror/addon/lint/linter.js"></script>
<!-- CSSLint -->
<script src="vendor/csslint/csslint-worker.js"></script>
<!-- stylelint -->
<script src="vendor-overwrites/stylelint/stylelint-bundle.min.js"></script>
<script src="vendor-overwrites/codemirror/addon/lint/stylelint-config.js"></script>
<script src="vendor-overwrites/codemirror/addon/lint/stylelint.js"></script>
<link rel="stylesheet" href="vendor/codemirror/addon/hint/show-hint.css" />
<script src="vendor/codemirror/addon/hint/show-hint.js"></script>
@ -187,6 +190,12 @@
<option i18n-text="genericDisabledLabel" value="">
</select>
</div>
<div class="option aligned">
<label id="linter-label" for="editor.linter" i18n-text="cm_linter"></label>
<select id="editor.linter">
<option value="csslint" selected>CSSLint</option>
<option value="stylelint">stylelint</option>
</select>
</section>
<section id="lint"><h2 i18n-text="issues">: <span id="issue-count"></span><svg id="lint-help" class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg></h2><div></div></section>
</div>

View File

@ -1,5 +1,5 @@
/* eslint brace-style: 0, operator-linebreak: 0 */
/* global CodeMirror parserlib */
/* global CodeMirror exports parserlib CSSLint */
'use strict';
let styleId = null;
@ -348,6 +348,16 @@ function acmeEventListener(event) {
default:
value = null;
}
break;
case 'linter':
if (value !== null && (editors.lastActive || editors[0])) {
if (prefs.get(el.id) !== value) {
prefs.set(el.id, value || 'csslint');
}
CodeMirror.signal(editors.lastActive || editors[0], "change");
// save();
}
break;
}
CodeMirror.setOption(option, value);
}
@ -1050,7 +1060,7 @@ function getEditorInSight(nearbyElement) {
function updateLintReport(cm, delay) {
if (delay === 0) {
// immediately show pending stylelint messages in onbeforeunload and save
// immediately show pending csslint/stylelint messages in onbeforeunload and save
update(cm);
return;
}
@ -1074,6 +1084,7 @@ function updateLintReport(cm, delay) {
let changed = false;
let fixedOldIssues = false;
scope.forEach(cm => {
const linter = prefs.get('editor.linter');
const scopedState = cm.state.lint || {};
const oldMarkers = scopedState.markedLast || {};
const newMarkers = {};
@ -1082,17 +1093,19 @@ function updateLintReport(cm, delay) {
const info = mark.__annotation;
const isActiveLine = info.from.line === cm.getCursor().line;
const pos = isActiveLine ? 'cursor' : (info.from.line + ',' + info.from.ch);
const rule = info.message.substring(info.message.lastIndexOf('('), info.message.length);
// stylelint rule added in parentheses at the end
const rule = linter === 'stylelint' ?
info.message.substring(info.message.lastIndexOf('('), info.message.length) :
/ at line \d.+$/;
// csslint
let message = escapeHtml(info.message.replace(rule, ''));
if (message.length > 100) {
message = message.substr(0, 100) + '...';
}
if (isActiveLine || oldMarkers[pos] === message) {
delete oldMarkers[pos];
}
newMarkers[pos] = message;
return `<tr class="${info.severity}">
<td role="severity" class="CodeMirror-lint-marker-${info.severity}" title="Rule: ${rule}">
<td role="severity" class="CodeMirror-lint-marker-${info.severity}"
${linter === 'stylelint' ? 'title="Rule: ' + rule + '"' : ''}>
${info.severity}
</td>
<td role="line">${info.from.line + 1}</td>
@ -1100,7 +1113,7 @@ function updateLintReport(cm, delay) {
<td role="col">${info.from.ch + 1}</td>
<td role="message" title="${message}">${message}</td>
</tr>`
}) + '</tbody>';
}).join('') + '</tbody>';
scopedState.markedLast = newMarkers;
fixedOldIssues |= scopedState.reportDisplayed && Object.keys(oldMarkers).length > 0;
if (scopedState.html !== html) {
@ -1866,17 +1879,25 @@ function showKeyMapHelp() {
}
function showLintHelp() {
let content = t('issuesHelp') + '<ul class="rules">',
rules = [];
$$('#lint td[role="severity"]').forEach(el => {
const rule = el.title.replace('Rule: (', '').replace(/[()]/g, '').trim();
if (!rules.includes(rule)) {
content += `<li>
<a target="_blank" href="https://stylelint.io/user-guide/rules/${rule}/">${rule}</a>
</li>`;
rules.push(rule);
}
});
let list = '<ul class="rules">';
let content = '';
if (prefs.get('editor.linter') === 'csslint') {
content = t('issuesHelp', '<a href="https://github.com/CSSLint/csslint" target="_blank">CSSLint</a>') + list +
CSSLint.getRules().map(rule =>
'<li><b>' + rule.name + '</b><br>' + rule.desc + '</li>'
).join('');
} else {
let rules = [];
const url = 'https://stylelint.io/user-guide/rules/';
content = t('issuesHelp', `<a href="${url}" target="_blank">stylelint</a>`) + list;
$$('#lint td[role="severity"]').forEach(el => {
const rule = el.title.replace('Rule: (', '').replace(/[()]/g, '').trim();
if (!rules.includes(rule)) {
content += `<li><a target="_blank" href="${url}${rule}/">${rule}</a></li>`;
rules.push(rule);
}
});
}
return showHelp(t('issues'), content + '</ul>');
}

View File

@ -42,6 +42,7 @@ var prefs = new function Prefs() {
indent_conditional: true,
},
'editor.lintDelay': 500, // lint gutter marker update delay, ms
'editor.linter': 'csslint', // Choose csslint or stylelint
'editor.lintReportDelay': 4500, // lint report update delay, ms
'editor.matchHighlight': 'token', // token = token/word under cursor even if nothing is selected
// selection = only when something is selected

View File

@ -1,64 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Depends on csslint.js from https://github.com/stubbornella/csslint
// declare global: CSSLint
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.registerHelper("lint", "css", function(text) {
var found = [];
if (!window.CSSLint) return found;
/* STYLISH: hack start (part 1) */
var rules = CSSLint.getRules();
var allowedRules = ["display-property-grouping", "duplicate-properties", "empty-rules", "errors", "known-properties"];
CSSLint.clearRules();
rules.forEach(function(rule) {
if (allowedRules.indexOf(rule.id) >= 0) {
CSSLint.addRule(rule);
}
});
/* STYLISH: hack end */
var results = CSSLint.verify(text), messages = results.messages, message = null;
for ( var i = 0; i < messages.length; i++) {
message = messages[i];
/* STYLISH: hack start (part 2) */
if (message.type === 'warning') {
// @font-face {font-family: 'Ampersand'; unicode-range: U+26;}
if (message.message.indexOf('unicode-range') !== -1) {
continue;
}
else if ( // color: hsl(210, 100%, 2.2%); or color: hsla(210, 100%, 2.2%, 0.3);
message.message.startsWith('Expected (<color>) but found \'hsl') &&
/hsla?\(\s*(-?\d+)%?\s*,\s*(-?\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%(\s*,\s*(-?\d+|-?\d*.\d+))?\s*\)/.test(message.message)
) {
continue;
}
//
}
/* STYLISH: hack end */
var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;
found.push({
from: CodeMirror.Pos(startLine, startCol),
to: CodeMirror.Pos(endLine, endCol),
message: message.message,
severity : message.type
});
}
return found;
});
});

View File

@ -0,0 +1,91 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Depends on csslint.js from https://github.com/stubbornella/csslint
// declare global: CSSLint
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.registerHelper("lint", "css", function(text) {
let found = [];
const linter = prefs.get('editor.linter');
if (linter === 'csslint' && window.CSSLint) {
/* STYLISH: hack start (part 1) */
var rules = CSSLint.getRules();
var allowedRules = ["display-property-grouping", "duplicate-properties", "empty-rules", "errors", "known-properties"];
CSSLint.clearRules();
rules.forEach(function(rule) {
if (allowedRules.indexOf(rule.id) >= 0) {
CSSLint.addRule(rule);
}
});
/* STYLISH: hack end */
var results = CSSLint.verify(text), messages = results.messages, message = null;
for ( var i = 0; i < messages.length; i++) {
message = messages[i];
/* STYLISH: hack start (part 2) */
if (message.type === 'warning') {
// @font-face {font-family: 'Ampersand'; unicode-range: U+26;}
if (message.message.indexOf('unicode-range') !== -1) {
continue;
}
else if ( // color: hsl(210, 100%, 2.2%); or color: hsla(210, 100%, 2.2%, 0.3);
message.message.startsWith('Expected (<color>) but found \'hsl') &&
/hsla?\(\s*(-?\d+)%?\s*,\s*(-?\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%(\s*,\s*(-?\d+|-?\d*.\d+))?\s*\)/.test(message.message)
) {
continue;
}
//
}
/* STYLISH: hack end */
var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;
found.push({
from: CodeMirror.Pos(startLine, startCol),
to: CodeMirror.Pos(endLine, endCol),
message: message.message,
severity : message.type
});
}
} else if (linter === 'stylelint') {
const stylelint = require('stylelint').lint;
if (stylelint) {
return stylelint({
code: text,
// stylelintConfig stored in stylelint-config.js & loaded by edit.html
config: stylelintConfig
}).then(output => {
const warnings = output.results.length ? output.results[0].warnings : [],
len = warnings.length;
let i, warning;
if (len) {
for (i = 0; i < len; i++) {
warning = warnings[i];
found.push({
from: CodeMirror.Pos(warning.line - 1, warning.column - 1),
to: CodeMirror.Pos(warning.line - 1, warning.column),
message: warning.text,
severity : warning.severity
});
}
}
return found;
});
}
}
return found;
});
});

View File

@ -1,49 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Depends on stylelint.js from https://github.com/...
// declare global: StyleLint
(function(mod) {
if (typeof exports == 'object' && typeof module == 'object') // CommonJS
mod(require('../../lib/codemirror'));
else if (typeof define == 'function' && define.amd) // AMD
define(['../../lib/codemirror'], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
'use strict';
CodeMirror.registerHelper('lint', 'css', text => {
let found = [];
const stylelint = require('stylelint').lint;
if (!stylelint) {
return found;
}
return stylelint({
code: text,
// stylelintConfig stored in stylelint-config.js & loaded by edit.html
config: stylelintConfig
}).then(output => {
const warnings = output.results.length ? output.results[0].warnings : [],
len = warnings.length;
let i, warning;
if (len) {
for (i = 0; i < len; i++) {
warning = warnings[i];
found.push({
from: CodeMirror.Pos(warning.line - 1, warning.column - 1),
to: CodeMirror.Pos(warning.line - 1, warning.column),
message: warning.text,
severity : warning.severity
});
}
}
return found;
});
});
});