try to show applicable values in autocomplete for props (#1211)
+ restore proper toggling of autocompleteOnTyping
This commit is contained in:
parent
9531698dd7
commit
692d3c9826
|
@ -2,6 +2,7 @@
|
||||||
/* global cmFactory */
|
/* global cmFactory */
|
||||||
/* global debounce */// toolbox.js
|
/* global debounce */// toolbox.js
|
||||||
/* global editor */
|
/* global editor */
|
||||||
|
/* global linterMan */
|
||||||
/* global prefs */
|
/* global prefs */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -11,30 +12,37 @@
|
||||||
const USO_VAR = 'uso-variable';
|
const USO_VAR = 'uso-variable';
|
||||||
const USO_VALID_VAR = 'variable-3 ' + USO_VAR;
|
const USO_VALID_VAR = 'variable-3 ' + USO_VAR;
|
||||||
const USO_INVALID_VAR = 'error ' + USO_VAR;
|
const USO_INVALID_VAR = 'error ' + USO_VAR;
|
||||||
|
const rxPROP = /^(prop(erty)?|variable-2)\b/;
|
||||||
const rxVAR = /(^|[^-.\w\u0080-\uFFFF])var\(/iyu;
|
const rxVAR = /(^|[^-.\w\u0080-\uFFFF])var\(/iyu;
|
||||||
const rxCONSUME = /([-\w]*\s*:\s?)?/yu;
|
const rxCONSUME = /([-\w]*\s*:\s?)?/yu;
|
||||||
const cssMime = CodeMirror.mimeModes['text/css'];
|
const cssMime = CodeMirror.mimeModes['text/css'];
|
||||||
|
const cssGlobalValues = [
|
||||||
|
'inherit',
|
||||||
|
'initial',
|
||||||
|
'revert',
|
||||||
|
'unset',
|
||||||
|
];
|
||||||
const docFuncs = addSuffix(cssMime.documentTypes, '(');
|
const docFuncs = addSuffix(cssMime.documentTypes, '(');
|
||||||
const {tokenHooks} = cssMime;
|
const {tokenHooks} = cssMime;
|
||||||
const originalCommentHook = tokenHooks['/'];
|
const originalCommentHook = tokenHooks['/'];
|
||||||
const originalHelper = CodeMirror.hint.css || (() => {});
|
const originalHelper = CodeMirror.hint.css || (() => {});
|
||||||
let cssProps, cssMedia;
|
let cssMedia, cssProps, cssPropsValues;
|
||||||
|
|
||||||
const aot = prefs.get('editor.autocompleteOnTyping');
|
const AOT_ID = 'autocompleteOnTyping';
|
||||||
CodeMirror.defineOption('autocompleteOnTyping', aot, aotToggled);
|
const AOT_PREF_ID = 'editor.' + AOT_ID;
|
||||||
if (aot) cmFactory.globalSetOption('autocompleteOnTyping', true);
|
const aot = prefs.get(AOT_PREF_ID);
|
||||||
|
CodeMirror.defineOption(AOT_ID, aot, (cm, value) => {
|
||||||
|
cm[value ? 'on' : 'off']('changes', autocompleteOnTyping);
|
||||||
|
cm[value ? 'on' : 'off']('pick', autocompletePicked);
|
||||||
|
});
|
||||||
|
prefs.subscribe(AOT_PREF_ID, (key, val) => cmFactory.globalSetOption(AOT_ID, val), {runNow: aot});
|
||||||
|
|
||||||
CodeMirror.registerHelper('hint', 'css', helper);
|
CodeMirror.registerHelper('hint', 'css', helper);
|
||||||
CodeMirror.registerHelper('hint', 'stylus', helper);
|
CodeMirror.registerHelper('hint', 'stylus', helper);
|
||||||
|
|
||||||
tokenHooks['/'] = tokenizeUsoVariables;
|
tokenHooks['/'] = tokenizeUsoVariables;
|
||||||
|
|
||||||
function aotToggled(cm, value) {
|
async function helper(cm) {
|
||||||
cm[value ? 'on' : 'off']('changes', autocompleteOnTyping);
|
|
||||||
cm[value ? 'on' : 'off']('pick', autocompletePicked);
|
|
||||||
}
|
|
||||||
|
|
||||||
function helper(cm) {
|
|
||||||
const pos = cm.getCursor();
|
const pos = cm.getCursor();
|
||||||
const {line, ch} = pos;
|
const {line, ch} = pos;
|
||||||
const {styles, text} = cm.getLineHandle(line);
|
const {styles, text} = cm.getLineHandle(line);
|
||||||
|
@ -64,7 +72,7 @@
|
||||||
const str = text.slice(prev, end);
|
const str = text.slice(prev, end);
|
||||||
const left = text.slice(prev, ch).trim();
|
const left = text.slice(prev, ch).trim();
|
||||||
let leftLC = left.toLowerCase();
|
let leftLC = left.toLowerCase();
|
||||||
let list = [];
|
let list;
|
||||||
switch (leftLC[0]) {
|
switch (leftLC[0]) {
|
||||||
|
|
||||||
case '!':
|
case '!':
|
||||||
|
@ -125,8 +133,29 @@
|
||||||
// fallthrough to `default`
|
// fallthrough to `default`
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
// property values
|
||||||
|
if (isStylusLang || getTokenState() === 'prop') {
|
||||||
|
while (i > 0 && !rxPROP.test(styles[i + 1])) i -= 2;
|
||||||
|
const propEnd = styles[i];
|
||||||
|
let prop;
|
||||||
|
if (propEnd > text.lastIndexOf(';', ch - 1)) {
|
||||||
|
while (i > 0 && rxPROP.test(styles[i + 1])) i -= 2;
|
||||||
|
prop = text.slice(styles[i] || 0, propEnd).match(/([-\w]+)?$/u)[1];
|
||||||
|
}
|
||||||
|
if (prop) {
|
||||||
|
if (/[^-\w]/.test(leftLC)) {
|
||||||
|
prev += execAt(/[\s:()]*/y, prev, text)[0].length;
|
||||||
|
leftLC = leftLC.replace(/^[^\w\s]\s*/, '');
|
||||||
|
}
|
||||||
|
if (prop.startsWith('--')) prop = 'color'; // assuming 90% of variables are colors
|
||||||
|
if (!cssPropsValues) cssPropsValues = await linterMan.worker.getCssPropsValues();
|
||||||
|
list = [...new Set([...cssPropsValues[prop] || [], ...cssGlobalValues])];
|
||||||
|
end = prev + execAt(/(\s*[-a-z(]+)?/y, prev, text)[0].length;
|
||||||
|
}
|
||||||
|
}
|
||||||
// properties and media features
|
// properties and media features
|
||||||
if (/^(prop(erty|\?)|atom|error)/.test(type) &&
|
if (!list &&
|
||||||
|
/^(prop(erty|\?)|atom|error)/.test(type) &&
|
||||||
/^(block|atBlock_parens|maybeprop)/.test(getTokenState())) {
|
/^(block|atBlock_parens|maybeprop)/.test(getTokenState())) {
|
||||||
if (!cssProps) initCssProps();
|
if (!cssProps) initCssProps();
|
||||||
if (type === 'prop?') {
|
if (type === 'prop?') {
|
||||||
|
@ -136,7 +165,9 @@
|
||||||
list = state === 'atBlock_parens' ? cssMedia : cssProps;
|
list = state === 'atBlock_parens' ? cssMedia : cssProps;
|
||||||
end -= /\W$/u.test(str); // e.g. don't consume ) when inside ()
|
end -= /\W$/u.test(str); // e.g. don't consume ) when inside ()
|
||||||
end += execAt(rxCONSUME, end, text)[0].length;
|
end += execAt(rxCONSUME, end, text)[0].length;
|
||||||
} else {
|
|
||||||
|
}
|
||||||
|
if (!list) {
|
||||||
return isStylusLang
|
return isStylusLang
|
||||||
? CodeMirror.hint.fromList(cm, {words: CodeMirror.hintWords.stylus})
|
? CodeMirror.hint.fromList(cm, {words: CodeMirror.hintWords.stylus})
|
||||||
: originalHelper(cm);
|
: originalHelper(cm);
|
||||||
|
|
|
@ -16,6 +16,34 @@
|
||||||
.map(m => Object.assign(m, {rule: {id: m.rule.id}}));
|
.map(m => Object.assign(m, {rule: {id: m.rule.id}}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCssPropsValues() {
|
||||||
|
require(['/js/csslint/parserlib']); /* global parserlib */
|
||||||
|
const {css: {Colors, Properties}, util: {describeProp}} = parserlib;
|
||||||
|
const namedColors = Object.keys(Colors);
|
||||||
|
const rxNonWord = /(?:<.+?>|[^-\w<(]+\d*)+/g;
|
||||||
|
const res = {};
|
||||||
|
// moving vendor-prefixed props to the end
|
||||||
|
const cmp = (a, b) => a[0] === '-' && b[0] !== '-' ? 1 : a < b ? -1 : a > b;
|
||||||
|
for (const [k, v] of Object.entries(Properties)) {
|
||||||
|
if (typeof v === 'string') {
|
||||||
|
let last = '';
|
||||||
|
const uniq = [];
|
||||||
|
// strip definitions of function arguments
|
||||||
|
const desc = describeProp(v).replace(/([-\w]+)\(.*?\)/g, 'z-$1');
|
||||||
|
const descNoColors = desc.replace(/<named-color>/g, '');
|
||||||
|
// add a prefix to functions to group them at the end
|
||||||
|
const words = descNoColors.split(rxNonWord).sort(cmp);
|
||||||
|
for (let w of words) {
|
||||||
|
if (w.startsWith('z-')) w = w.slice(2) + '(';
|
||||||
|
if (w !== last) uniq.push(last = w);
|
||||||
|
}
|
||||||
|
if (desc !== descNoColors) uniq.push(...namedColors);
|
||||||
|
if (uniq.length) res[k] = uniq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
getRules(linter) {
|
getRules(linter) {
|
||||||
return ruleRetriever[linter](); // eslint-disable-line no-use-before-define
|
return ruleRetriever[linter](); // eslint-disable-line no-use-before-define
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,7 +34,7 @@ self.parserlib = (() => {
|
||||||
'align-items': 'normal | stretch | <baseline-position> | [ <overflow-position>? <self-position> ]',
|
'align-items': 'normal | stretch | <baseline-position> | [ <overflow-position>? <self-position> ]',
|
||||||
'align-content': '<align-content>',
|
'align-content': '<align-content>',
|
||||||
'align-self': '<align-self>',
|
'align-self': '<align-self>',
|
||||||
'all': 'initial | inherit | unset',
|
'all': 'initial | inherit | revert | unset',
|
||||||
'alignment-adjust': 'auto | baseline | before-edge | text-before-edge | middle | central | ' +
|
'alignment-adjust': 'auto | baseline | before-edge | text-before-edge | middle | central | ' +
|
||||||
'after-edge | text-after-edge | ideographic | alphabetic | hanging | ' +
|
'after-edge | text-after-edge | ideographic | alphabetic | hanging | ' +
|
||||||
'mathematical | <length-pct>',
|
'mathematical | <length-pct>',
|
||||||
|
@ -745,9 +745,9 @@ self.parserlib = (() => {
|
||||||
'emoji | math | fangsong | ui-serif | ui-sans-serif | ui-monospace | ui-rounded',
|
'emoji | math | fangsong | ui-serif | ui-sans-serif | ui-monospace | ui-rounded',
|
||||||
'<geometry-box>': '<shape-box> | fill-box | stroke-box | view-box',
|
'<geometry-box>': '<shape-box> | fill-box | stroke-box | view-box',
|
||||||
'<glyph-angle>': p => p.type === 'angle' && p.units === 'deg',
|
'<glyph-angle>': p => p.type === 'angle' && p.units === 'deg',
|
||||||
'<gradient>': p =>
|
'<gradient>': 'radial-gradient() | linear-gradient() | conic-gradient() | gradient() | ' +
|
||||||
p.type === 'function' &&
|
'repeating-radial-gradient() | repeating-linear-gradient() | repeating-conic-gradient() | ' +
|
||||||
/^(?:-(?:webkit|moz|ms|o)-)?(?:repeating-)?(?:radial-|linear-|conic-)?gradient/i.test(p),
|
'repeating-gradient()',
|
||||||
'<hex-color>': p => p.tokenType === Tokens.HASH, //eslint-disable-line no-use-before-define
|
'<hex-color>': p => p.tokenType === Tokens.HASH, //eslint-disable-line no-use-before-define
|
||||||
'<icccolor>': 'cielab() | cielch() | cielchab() | icc-color() | icc-named-color()',
|
'<icccolor>': 'cielab() | cielch() | cielchab() | icc-color() | icc-named-color()',
|
||||||
'<ident>': vtIsIdent,
|
'<ident>': vtIsIdent,
|
||||||
|
@ -778,7 +778,7 @@ self.parserlib = (() => {
|
||||||
'<nonnegative-num-pct>': p =>
|
'<nonnegative-num-pct>': p =>
|
||||||
p.value >= 0 && (p.type === 'number' || p.type === 'percentage') || p.isCalc,
|
p.value >= 0 && (p.type === 'number' || p.type === 'percentage') || p.isCalc,
|
||||||
//eslint-disable-next-line no-use-before-define
|
//eslint-disable-next-line no-use-before-define
|
||||||
'<named-color>': p => p.text in Colors || lower(p.text) in Colors,
|
'<named-color>': p => p.text in Colors || ColorsLC.has(lower(p.text)),
|
||||||
'<number>': p => p.type === 'number' || p.isCalc,
|
'<number>': p => p.type === 'number' || p.isCalc,
|
||||||
'<number-pct>': p => p.type === 'number' || p.type === 'percentage' || p.isCalc,
|
'<number-pct>': p => p.type === 'number' || p.type === 'percentage' || p.isCalc,
|
||||||
'<opacity-value>': p => p.type === 'number' && p.value >= 0 && p.value <= 1 || p.isCalc,
|
'<opacity-value>': p => p.type === 'number' && p.value >= 0 && p.value <= 1 || p.isCalc,
|
||||||
|
@ -979,7 +979,12 @@ self.parserlib = (() => {
|
||||||
//#endregion
|
//#endregion
|
||||||
//#region Colors
|
//#region Colors
|
||||||
|
|
||||||
const Colors = {
|
const Colors = Object.assign(Object.create(null), {
|
||||||
|
// 'currentColor' color keyword
|
||||||
|
// https://www.w3.org/TR/css3-color/#currentcolor
|
||||||
|
currentColor: '',
|
||||||
|
transparent: '#0000',
|
||||||
|
|
||||||
aliceblue: '#f0f8ff',
|
aliceblue: '#f0f8ff',
|
||||||
antiquewhite: '#faebd7',
|
antiquewhite: '#faebd7',
|
||||||
aqua: '#00ffff',
|
aqua: '#00ffff',
|
||||||
|
@ -1128,56 +1133,49 @@ self.parserlib = (() => {
|
||||||
whitesmoke: '#f5f5f5',
|
whitesmoke: '#f5f5f5',
|
||||||
yellow: '#ffff00',
|
yellow: '#ffff00',
|
||||||
yellowgreen: '#9acd32',
|
yellowgreen: '#9acd32',
|
||||||
// 'currentColor' color keyword
|
|
||||||
// https://www.w3.org/TR/css3-color/#currentcolor
|
|
||||||
currentcolor: '',
|
|
||||||
transparent: '#0000',
|
|
||||||
|
|
||||||
// CSS2 system colors
|
// old = CSS2 system colors: https://www.w3.org/TR/css3-color/#css2-system
|
||||||
// https://www.w3.org/TR/css3-color/#css2-system
|
// new = CSS4 system colors: https://drafts.csswg.org/css-color-4/#css-system-colors
|
||||||
activeborder: '',
|
ActiveBorder: '',
|
||||||
activecaption: '',
|
ActiveCaption: '',
|
||||||
appworkspace: '',
|
ActiveText: '', // new
|
||||||
background: '',
|
AppWorkspace: '',
|
||||||
buttonface: '',
|
Background: '',
|
||||||
buttonhighlight: '',
|
ButtonBorder: '', // new
|
||||||
buttonshadow: '',
|
ButtonFace: '', // old+new
|
||||||
buttontext: '',
|
ButtonHighlight: '',
|
||||||
captiontext: '',
|
ButtonShadow: '',
|
||||||
graytext: '',
|
ButtonText: '', // old+new
|
||||||
greytext: '',
|
Canvas: '', // new
|
||||||
highlight: '',
|
CanvasText: '', // new
|
||||||
highlighttext: '',
|
CaptionText: '',
|
||||||
inactiveborder: '',
|
Field: '', // new
|
||||||
inactivecaption: '',
|
FieldText: '', // new
|
||||||
inactivecaptiontext: '',
|
GrayText: '', // old+new
|
||||||
infobackground: '',
|
Highlight: '', // old+new
|
||||||
infotext: '',
|
HighlightText: '', // old+new
|
||||||
menu: '',
|
InactiveBorder: '',
|
||||||
menutext: '',
|
InactiveCaption: '',
|
||||||
scrollbar: '',
|
InactiveCaptionText: '',
|
||||||
threeddarkshadow: '',
|
InfoBackground: '',
|
||||||
threedface: '',
|
InfoText: '',
|
||||||
threedhighlight: '',
|
LinkText: '', // new
|
||||||
threedlightshadow: '',
|
Mark: '', // new
|
||||||
threedshadow: '',
|
MarkText: '', // new
|
||||||
window: '',
|
Menu: '',
|
||||||
windowframe: '',
|
MenuText: '',
|
||||||
windowtext: '',
|
Scrollbar: '',
|
||||||
|
ThreeDDarkShadow: '',
|
||||||
// CSS4 system colors, only additions to the above
|
ThreeDFace: '',
|
||||||
// https://drafts.csswg.org/css-color-4/#css-system-colors
|
ThreeDHighlight: '',
|
||||||
activetext: '',
|
ThreeDLightShadow: '',
|
||||||
buttonborder: '',
|
ThreeDShadow: '',
|
||||||
canvas: '',
|
VisitedText: '', // new
|
||||||
canvastext: '',
|
Window: '',
|
||||||
field: '',
|
WindowFrame: '',
|
||||||
fieldtext: '',
|
WindowText: '',
|
||||||
linktext: '',
|
});
|
||||||
mark: '',
|
const ColorsLC = new Set(Object.keys(Colors).map(lower));
|
||||||
marktext: '',
|
|
||||||
visitedtext: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
//#region Tokens
|
//#region Tokens
|
||||||
|
@ -4175,10 +4173,12 @@ self.parserlib = (() => {
|
||||||
if (asText) {
|
if (asText) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
const m = rxVendorPrefix.exec(name) || [];
|
||||||
return SyntaxUnit.addFuncInfo(
|
return SyntaxUnit.addFuncInfo(
|
||||||
new SyntaxUnit(text, start, 'function', {
|
new SyntaxUnit(text, start, 'function', {
|
||||||
expr,
|
expr,
|
||||||
name,
|
name: m[2] || name,
|
||||||
|
prefix: m[1] || '',
|
||||||
tokenType: Tokens.FUNCTION,
|
tokenType: Tokens.FUNCTION,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -4647,6 +4647,7 @@ self.parserlib = (() => {
|
||||||
Colors,
|
Colors,
|
||||||
Combinator,
|
Combinator,
|
||||||
Parser,
|
Parser,
|
||||||
|
Properties,
|
||||||
PropertyName,
|
PropertyName,
|
||||||
PropertyValue,
|
PropertyValue,
|
||||||
PropertyValuePart,
|
PropertyValuePart,
|
||||||
|
@ -4662,12 +4663,13 @@ self.parserlib = (() => {
|
||||||
ValidationError,
|
ValidationError,
|
||||||
},
|
},
|
||||||
util: {
|
util: {
|
||||||
|
EventTarget,
|
||||||
StringReader,
|
StringReader,
|
||||||
SyntaxError,
|
SyntaxError,
|
||||||
SyntaxUnit,
|
SyntaxUnit,
|
||||||
EventTarget,
|
|
||||||
TokenStreamBase,
|
TokenStreamBase,
|
||||||
rxVendorPrefix,
|
rxVendorPrefix,
|
||||||
|
describeProp: vtExplode,
|
||||||
},
|
},
|
||||||
cache: parserCache,
|
cache: parserCache,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user