recognize USO-variables /*[[foo]]*/ and provide autocomplete hints

This commit is contained in:
tophf 2017-11-23 16:28:55 +03:00
parent 3152a7ebfe
commit 80547aef70
3 changed files with 99 additions and 12 deletions

View File

@ -31,3 +31,6 @@
.CodeMirror-search-hint {
color: #888;
}
.cm-uso-variable {
font-weight: bold;
}

View File

@ -1,4 +1,4 @@
/* global CodeMirror prefs loadScript */
/* global CodeMirror prefs loadScript editor */
'use strict';
@ -132,3 +132,65 @@
return isBlank;
});
})();
(() => {
const USO_VAR = 'uso-variable';
const USO_VALID_VAR = 'variable-3 ' + USO_VAR;
const USO_INVALID_VAR = 'error ' + USO_VAR;
CodeMirror.registerHelper('hint', 'css', function (cm) {
const {line, ch} = cm.getCursor();
const {styles, text} = cm.getLineHandle(line);
if (!styles || !editor) {
return;
}
let prev = 0;
for (let i = 1; i < styles.length; i += 2) {
let end = styles[i];
if (prev <= ch && ch <= end &&
(styles[i + 1] || '').includes(USO_VAR)) {
const adjust = text[prev] === '/' ? 4 : 0;
prev += adjust;
end -= adjust;
const leftPart = text.slice(prev, ch);
const list = Object.keys(editor.getStyle().usercssData.vars)
.filter(name => name.startsWith(leftPart));
console.log(leftPart, ...list);
return {
list,
from: {line, ch: prev},
to: {line, ch: end},
};
}
prev = end;
}
});
const hooks = CodeMirror.mimeModes['text/css'].tokenHooks;
const originalCommentHook = hooks['/'];
hooks['/'] = tokenizeUsoVariables;
function tokenizeUsoVariables(stream) {
const token = originalCommentHook.apply(this, arguments);
if (token[1] !== 'comment') {
return token;
}
const {string, start, pos} = stream;
// /*[[install-key]]*/
// 01234 43210
if (string[start + 2] === '[' &&
string[start + 3] === '[' &&
string[pos - 3] === ']' &&
string[pos - 4] === ']') {
if (editor &&
Object.hasOwnProperty.call(
editor.getStyle().usercssData.vars,
string.slice(start + 4, pos - 4))) {
token[0] = USO_VALID_VAR;
} else {
token[0] = USO_INVALID_VAR;
}
}
return token;
}
})();

View File

@ -1,16 +1,38 @@
/* global CodeMirror CSSLint stylelint linterConfig */
/* global CodeMirror CSSLint parserlib stylelint linterConfig */
'use strict';
CodeMirror.registerHelper('lint', 'csslint', code =>
CSSLint.verify(code, deepCopy(linterConfig.getCurrent('csslint')))
.messages.map(message => ({
from: CodeMirror.Pos(message.line - 1, message.col - 1),
to: CodeMirror.Pos(message.line - 1, message.col),
message: message.message,
rule: message.rule.id,
severity : message.type
}))
);
CodeMirror.registerHelper('lint', 'csslint', code => {
if (!CSSLint.suppressUsoVarError) {
CSSLint.suppressUsoVarError = true;
parserlib.css.Tokens[parserlib.css.Tokens.COMMENT].hide = false;
const isUsoVar = ({value}) => value.startsWith('/*[[') && value.endsWith(']]*/');
CSSLint.addRule({
id: 'uso-vars',
init(parser, reporter) {
parser.addListener('error', function ({message, line, col}) {
if (!isUsoVar(this._tokenStream._token)) {
const {_lt, _ltIndex: i} = this._tokenStream;
if (i < 2 || !_lt.slice(0, i - 1).reverse().some(isUsoVar)) {
reporter.error(message, line, col);
}
}
});
},
});
}
const rules = deepCopy(linterConfig.getCurrent('csslint'));
Object.defineProperty(rules, 'errors', {get: () => 0, set: () => 0});
rules['uso-vars'] = 1;
return CSSLint.verify(code, rules).messages
.map(({line, col, message, rule, type}) => line && {
message,
from: {line: line - 1, ch: col - 1},
to: {line: line - 1, ch: col},
rule: rule.id,
severity: type
})
.filter(Boolean);
});
CodeMirror.registerHelper('lint', 'stylelint', code =>
stylelint.lint({