From c960131a40f35ddcd163a4511bbc54787338cadb Mon Sep 17 00:00:00 2001 From: truckershitch Date: Thu, 1 Sep 2022 03:51:36 -0400 Subject: [PATCH 01/22] First hacky attempt at jinja2 parsing in klipper configs --- .vscode/settings.json | 20 +++++++++ src/components/inputs/Codemirror.vue | 4 +- src/plugins/StreamParserJinja2.ts | 55 ++++++++++++------------ src/plugins/StreamParserKlipperConfig.ts | 50 +++++++++++++++------ 4 files changed, 89 insertions(+), 40 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..29819fc51 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,20 @@ +{ + "MicroPython.executeButton": [ + { + "text": "▶", + "tooltip": "Run", + "alignment": "left", + "command": "extension.executeFile", + "priority": 3.5 + } + ], + "MicroPython.syncButton": [ + { + "text": "$(sync)", + "tooltip": "sync", + "alignment": "left", + "command": "extension.execute", + "priority": 4 + } + ] +} \ No newline at end of file diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 3db86d78b..49da2bd09 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -1,5 +1,5 @@ @@ -15,6 +15,7 @@ import { EditorState } from '@codemirror/state' import { mainsailTheme } from '@/plugins/codemirrorTheme' import { StreamLanguage } from '@codemirror/language' import { klipper_config } from '@/plugins/StreamParserKlipperConfig' +// import { jinja2 } from '@/plugins/StreamParserJinja2' import { gcode } from '@/plugins/StreamParserGcode' import { indentWithTab } from '@codemirror/commands' import { json } from '@codemirror/lang-json' @@ -94,6 +95,7 @@ export default class Codemirror extends Mixins(BaseMixin) { if (['cfg', 'conf'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(klipper_config)) else if (['gcode'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(gcode)) + // else if (['jinja2'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(jinja2)) else if (['json'].includes(this.fileExtension)) extensions.push(json()) else if (['css'].includes(this.fileExtension)) extensions.push(css()) diff --git a/src/plugins/StreamParserJinja2.ts b/src/plugins/StreamParserJinja2.ts index f515b3ba9..8d0940f0e 100644 --- a/src/plugins/StreamParserJinja2.ts +++ b/src/plugins/StreamParserJinja2.ts @@ -1,28 +1,27 @@ -/* import {StringStream} from "@codemirror/language"; -let keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif", - "extends", "filter", "endfilter", "firstof", "for", - "endfor", "if", "endif", "ifchanged", "endifchanged", - "ifequal", "endifequal", "ifnotequal", - "endifnotequal", "in", "include", "load", "not", "now", "or", - "parsed", "regroup", "reversed", "spaceless", - "endspaceless", "ssi", "templatetag", "openblock", - "closeblock", "openvariable", "closevariable", - "openbrace", "closebrace", "opencomment", - "closecomment", "widthratio", "url", "with", "endwith", - "get_current_language", "trans", "endtrans", "noop", "blocktrans", - "endblocktrans", "get_available_languages", - "get_current_language_bidi", "plural"]; -const operator = /^[+\-*&%=<>!?|~^]/; +// const keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif", +// "extends", "filter", "endfilter", "firstof", "for", +// "endfor", "if", "endif", "ifchanged", "endifchanged", +// "ifequal", "endifequal", "ifnotequal", +// "endifnotequal", "in", "include", "load", "not", "now", "or", +// "parsed", "regroup", "reversed", "spaceless", +// "endspaceless", "ssi", "templatetag", "openblock", +// "closeblock", "openvariable", "closevariable", +// "openbrace", "closebrace", "opencomment", +// "closecomment", "widthratio", "url", "with", "endwith", +// "get_current_language", "trans", "endtrans", "noop", "blocktrans", +// "endblocktrans", "get_available_languages", +// "get_current_language_bidi", "plural"]; + const sign = /^[:[({]/; -let atom = ["true", "false"]; const number = /^(\d[+\-*!/])?\d+(\.\d+)?/; - -keywords = new RegExp("((" + keywords.join(")|(") + "))\\b"); -atom = new RegExp("((" + atom.join(")|(") + "))\\b"); - +const keywords = ["if", "endif", "endfor", "for", "loop\\.index", "loop\\.revindex", "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", "and", "or", "not", "in", "is"]; +const reKeyword = new RegExp("^" + keywords.join("|")); +const reAtom = /^true|false/; +const operators = ["\\+", "-", "\\/\\/", "\\/", "%", "\\*\\*", "\\*", "\\(", "\\)", "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~"]; +const reOperator = new RegExp("^" + operators.join("|")); export const jinja2 = { - token: function(stream: StringStream, state: StreamParserJinja2State): string { + token: function(stream: StringStream, state: StreamParserJinja2State): string | null { let ch: string | void = stream.peek(); //Comment @@ -39,7 +38,7 @@ export const jinja2 = { //After operator if(state.operator) { state.operator = false; - if(stream.match(atom)) { + if(stream.match(reAtom)) { return "atom"; } if(stream.match(number)) { @@ -49,7 +48,7 @@ export const jinja2 = { //After sign if(state.sign) { state.sign = false; - if(stream.match(atom)) { + if(stream.match(reAtom)) { return "atom"; } if(stream.match(number)) { @@ -70,17 +69,17 @@ export const jinja2 = { } else if(stream.match(state.intag + "}") || stream.eat("-") && stream.match(state.intag + "}")) { state.intag = false; return "tag"; - } else if(stream.match(operator)) { + } else if(stream.match(reOperator)) { state.operator = true; return "operator"; } else if(stream.match(sign)) { state.sign = true; } else { if(stream.eat(" ") || stream.sol()) { - if(stream.match(keywords)) { + if(stream.match(reKeyword)) { return "keyword"; } - if(stream.match(atom)) { + if(stream.match(reAtom)) { return "atom"; } if(stream.match(number)) { @@ -116,8 +115,11 @@ export const jinja2 = { stream.eat("-"); return "tag"; } + return 'tag' } stream.next(); + // TODO: not sure about returning null here + return null; }, startState: function(): StreamParserJinja2State { return { @@ -141,4 +143,3 @@ export interface StreamParserJinja2State { sign: boolean, instring: boolean | string, } -*/ diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 8b3a28e75..fb1f8eb04 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -1,5 +1,6 @@ -import { StreamParser, StringStream } from '@codemirror/language' +import { StreamLanguage, StreamParser, StringStream } from '@codemirror/language' import { gcode } from '@/plugins/StreamParserGcode' +import { jinja2 } from '@/plugins/StreamParserJinja2' export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { @@ -60,16 +61,28 @@ export const klipper_config: StreamParser = { state.klipperMacroJinjaPercent = false stream.eatSpace() state.gcodeZeroPos = stream.pos - return null + // return null + return 'tag' } - stream.next() - return 'string' + // stream.next() + // return 'string' + stream.eatWhile(/^\s+\S/) + const jinjaState = { + incomment: false, + intag: true, + operator: false, + sign: false, + instring: false + } + return jinja2.token(stream, jinjaState) } - - if (stream.match(/^\s*{[%{]?/)) { + const jinjaMatch: any = stream.match(/^\s*{[%#{]?/) + if (jinjaMatch) { state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true - return null + stream.backUp(jinjaMatch[0].trimStart().length) + // return null + return jinja2.token(stream, jinja2.startState()) } return gcode.token(stream, state, state.gcodeZeroPos ?? 0) } @@ -89,16 +102,29 @@ export const klipper_config: StreamParser = { state.klipperMacroJinjaPercent = false stream.eatSpace() state.gcodeZeroPos = stream.pos - return null + // return null + return 'tag' } - stream.next() - return 'string' + // stream.next() + // return 'string' + stream.eatWhile(/^\s+\S/) + const jinjaState = { + incomment: false, + intag: true, + operator: false, + sign: false, + instring: false + } + return jinja2.token(stream, jinjaState) } - if (stream.match(/^\s*{[%{]?/)) { + const jinjaMatch: any = stream.match(/^\s*{[%#{]?/) + if (jinjaMatch) { state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true - return null + stream.backUp(jinjaMatch[0].trimStart().length) + // return null + return jinja2.token(stream, jinja2.startState()) } return gcode.token(stream, state, state.gcodeZeroPos ?? stream.pos) } else if (state.pair) { From 39155ced208d37310a39a5e5bd895fae978a29d5 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Thu, 1 Sep 2022 04:56:56 -0400 Subject: [PATCH 02/22] jinja2 string fix --- src/plugins/StreamParserKlipperConfig.ts | 28 ++++++++---------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index fb1f8eb04..4a114b25a 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -1,6 +1,6 @@ import { StreamLanguage, StreamParser, StringStream } from '@codemirror/language' import { gcode } from '@/plugins/StreamParserGcode' -import { jinja2 } from '@/plugins/StreamParserJinja2' +import { jinja2, StreamParserJinja2State } from '@/plugins/StreamParserJinja2' export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { @@ -64,16 +64,11 @@ export const klipper_config: StreamParser = { // return null return 'tag' } - // stream.next() - // return 'string' - stream.eatWhile(/^\s+\S/) - const jinjaState = { - incomment: false, - intag: true, - operator: false, - sign: false, - instring: false + if (stream.match(/^"[^"]+"/)) { + return 'string' } + stream.eatWhile(/^\s+\S/) + const jinjaState = {...jinja2.startState(), intag: true} return jinja2.token(stream, jinjaState) } const jinjaMatch: any = stream.match(/^\s*{[%#{]?/) @@ -105,16 +100,11 @@ export const klipper_config: StreamParser = { // return null return 'tag' } - // stream.next() - // return 'string' - stream.eatWhile(/^\s+\S/) - const jinjaState = { - incomment: false, - intag: true, - operator: false, - sign: false, - instring: false + if (stream.match(/^"[^"]+"/)) { + return 'string' } + stream.eatWhile(/^\s+\S/) + const jinjaState = {...jinja2.startState(), intag: true} return jinja2.token(stream, jinjaState) } From 8de8c0b16be50ae63410b4008be3aab42ceb9ce8 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Thu, 1 Sep 2022 08:14:25 -0400 Subject: [PATCH 03/22] cleaner jinja2 parsing fix, new tags / colors --- .gitignore | 1 + src/plugins/StreamParserJinja2.ts | 55 +++++++++++---------- src/plugins/StreamParserKlipperConfig.ts | 61 ++++++++++++++++-------- src/plugins/codemirrorTheme.ts | 2 + 4 files changed, 71 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index fbf2a4fa2..0af695f31 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ temp package-lock.json *.local .env +.vscode cypress/videos/ components.d.ts diff --git a/src/plugins/StreamParserJinja2.ts b/src/plugins/StreamParserJinja2.ts index 8d0940f0e..f515b3ba9 100644 --- a/src/plugins/StreamParserJinja2.ts +++ b/src/plugins/StreamParserJinja2.ts @@ -1,27 +1,28 @@ +/* import {StringStream} from "@codemirror/language"; -// const keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif", -// "extends", "filter", "endfilter", "firstof", "for", -// "endfor", "if", "endif", "ifchanged", "endifchanged", -// "ifequal", "endifequal", "ifnotequal", -// "endifnotequal", "in", "include", "load", "not", "now", "or", -// "parsed", "regroup", "reversed", "spaceless", -// "endspaceless", "ssi", "templatetag", "openblock", -// "closeblock", "openvariable", "closevariable", -// "openbrace", "closebrace", "opencomment", -// "closecomment", "widthratio", "url", "with", "endwith", -// "get_current_language", "trans", "endtrans", "noop", "blocktrans", -// "endblocktrans", "get_available_languages", -// "get_current_language_bidi", "plural"]; - +let keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif", + "extends", "filter", "endfilter", "firstof", "for", + "endfor", "if", "endif", "ifchanged", "endifchanged", + "ifequal", "endifequal", "ifnotequal", + "endifnotequal", "in", "include", "load", "not", "now", "or", + "parsed", "regroup", "reversed", "spaceless", + "endspaceless", "ssi", "templatetag", "openblock", + "closeblock", "openvariable", "closevariable", + "openbrace", "closebrace", "opencomment", + "closecomment", "widthratio", "url", "with", "endwith", + "get_current_language", "trans", "endtrans", "noop", "blocktrans", + "endblocktrans", "get_available_languages", + "get_current_language_bidi", "plural"]; +const operator = /^[+\-*&%=<>!?|~^]/; const sign = /^[:[({]/; +let atom = ["true", "false"]; const number = /^(\d[+\-*!/])?\d+(\.\d+)?/; -const keywords = ["if", "endif", "endfor", "for", "loop\\.index", "loop\\.revindex", "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", "and", "or", "not", "in", "is"]; -const reKeyword = new RegExp("^" + keywords.join("|")); -const reAtom = /^true|false/; -const operators = ["\\+", "-", "\\/\\/", "\\/", "%", "\\*\\*", "\\*", "\\(", "\\)", "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~"]; -const reOperator = new RegExp("^" + operators.join("|")); + +keywords = new RegExp("((" + keywords.join(")|(") + "))\\b"); +atom = new RegExp("((" + atom.join(")|(") + "))\\b"); + export const jinja2 = { - token: function(stream: StringStream, state: StreamParserJinja2State): string | null { + token: function(stream: StringStream, state: StreamParserJinja2State): string { let ch: string | void = stream.peek(); //Comment @@ -38,7 +39,7 @@ export const jinja2 = { //After operator if(state.operator) { state.operator = false; - if(stream.match(reAtom)) { + if(stream.match(atom)) { return "atom"; } if(stream.match(number)) { @@ -48,7 +49,7 @@ export const jinja2 = { //After sign if(state.sign) { state.sign = false; - if(stream.match(reAtom)) { + if(stream.match(atom)) { return "atom"; } if(stream.match(number)) { @@ -69,17 +70,17 @@ export const jinja2 = { } else if(stream.match(state.intag + "}") || stream.eat("-") && stream.match(state.intag + "}")) { state.intag = false; return "tag"; - } else if(stream.match(reOperator)) { + } else if(stream.match(operator)) { state.operator = true; return "operator"; } else if(stream.match(sign)) { state.sign = true; } else { if(stream.eat(" ") || stream.sol()) { - if(stream.match(reKeyword)) { + if(stream.match(keywords)) { return "keyword"; } - if(stream.match(reAtom)) { + if(stream.match(atom)) { return "atom"; } if(stream.match(number)) { @@ -115,11 +116,8 @@ export const jinja2 = { stream.eat("-"); return "tag"; } - return 'tag' } stream.next(); - // TODO: not sure about returning null here - return null; }, startState: function(): StreamParserJinja2State { return { @@ -143,3 +141,4 @@ export interface StreamParserJinja2State { sign: boolean, instring: boolean | string, } +*/ diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 4a114b25a..f26d2e106 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -1,9 +1,13 @@ import { StreamLanguage, StreamParser, StringStream } from '@codemirror/language' import { gcode } from '@/plugins/StreamParserGcode' -import { jinja2, StreamParserJinja2State } from '@/plugins/StreamParserJinja2' export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { + const operators = ["\\+", "-", "\\/\\/", "\\/", "%", "\\*\\*", "\\*", "\\(", "\\)", "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~"] + const reOperator = new RegExp("^" + operators.join("|")) + const keywords = ["if", "endif", "endfor", "for", "loop\\.index", "loop\\.revindex", "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", "and", "or", "not", "in", "is"] + const reKeyword = new RegExp("^" + keywords.join("\\s|") + "\\s") + const ch = stream.peek() /* comments */ if ( @@ -61,23 +65,32 @@ export const klipper_config: StreamParser = { state.klipperMacroJinjaPercent = false stream.eatSpace() state.gcodeZeroPos = stream.pos - // return null return 'tag' } + /* string, operator, keyword, atom, number */ if (stream.match(/^"[^"]+"/)) { return 'string' } - stream.eatWhile(/^\s+\S/) - const jinjaState = {...jinja2.startState(), intag: true} - return jinja2.token(stream, jinjaState) + if (stream.match(reOperator)) { + return 'number' + } + if (stream.match(reKeyword)) { + return 'keyword' + } + if (stream.match(/^true\s|false\s/)) { + return 'atom' + } + if (stream.match(/^\d+/)) { + return 'number' + } + stream.next() + stream.eatSpace() + return 'propertyName' } - const jinjaMatch: any = stream.match(/^\s*{[%#{]?/) - if (jinjaMatch) { + if (stream.match(/^\s*{[%#{]?/)) { state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true - stream.backUp(jinjaMatch[0].trimStart().length) - // return null - return jinja2.token(stream, jinja2.startState()) + return 'tag' } return gcode.token(stream, state, state.gcodeZeroPos ?? 0) } @@ -97,24 +110,32 @@ export const klipper_config: StreamParser = { state.klipperMacroJinjaPercent = false stream.eatSpace() state.gcodeZeroPos = stream.pos - // return null return 'tag' } + /* string, operator, keyword, atom, number */ if (stream.match(/^"[^"]+"/)) { return 'string' } - stream.eatWhile(/^\s+\S/) - const jinjaState = {...jinja2.startState(), intag: true} - return jinja2.token(stream, jinjaState) + if (stream.match(reOperator)) { + return 'number' + } + if (stream.match(reKeyword)) { + return 'keyword' + } + if (stream.match(/^true\s|false\s/)) { + return 'atom' + } + if (stream.match(/^\d+/)) { + return 'number' + } + stream.next() + stream.eatSpace() + return 'propertyName' } - - const jinjaMatch: any = stream.match(/^\s*{[%#{]?/) - if (jinjaMatch) { + if (stream.match(/^\s*{[%#{]?/)) { state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true - stream.backUp(jinjaMatch[0].trimStart().length) - // return null - return jinja2.token(stream, jinja2.startState()) + return 'tag' } return gcode.token(stream, state, state.gcodeZeroPos ?? stream.pos) } else if (state.pair) { diff --git a/src/plugins/codemirrorTheme.ts b/src/plugins/codemirrorTheme.ts index fe92840b5..f1d3decd4 100644 --- a/src/plugins/codemirrorTheme.ts +++ b/src/plugins/codemirrorTheme.ts @@ -51,6 +51,8 @@ const mainsailHighlightStyle = HighlightStyle.define([ { tag: t.className, color: '#c586c0' }, { tag: t.name, color: '#e40', fontWeight: 'bold' }, { tag: t.propertyName, color: '#e56735' }, + { tag: t.keyword, color: '#fcbe03'}, + { tag: t.operator, color: '#fc03fc'} ]) const fn0 = mainsailHighlightStyle.style // noinspection JSConstantReassignment From 9ac42255149fbf6a9699a8adaf5362a34e5df2e4 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Thu, 1 Sep 2022 16:19:26 -0400 Subject: [PATCH 04/22] added filter highlighting, some RegExp cleanup, refractoring --- src/plugins/StreamParserKlipperConfig.ts | 128 ++++++++++++----------- src/plugins/codemirrorTheme.ts | 1 + 2 files changed, 68 insertions(+), 61 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index f26d2e106..63bf8d4b3 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -3,10 +3,67 @@ import { gcode } from '@/plugins/StreamParserGcode' export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { - const operators = ["\\+", "-", "\\/\\/", "\\/", "%", "\\*\\*", "\\*", "\\(", "\\)", "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~"] + const operators = [ + "\\+\\(", "-\\(", "\\/\\/\\(", "\\/\\(", "%\\(", "\\*\\*", "\\*", "\\(", "\\)", + "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~" + ] const reOperator = new RegExp("^" + operators.join("|")) - const keywords = ["if", "endif", "endfor", "for", "loop\\.index", "loop\\.revindex", "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", "and", "or", "not", "in", "is"] - const reKeyword = new RegExp("^" + keywords.join("\\s|") + "\\s") + const keywords = [ + "if", "elif", "else", "endif", "endfor", "for", "loop\\.index", "loop\\.revindex", + "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", + "and", "or", "not", "in", "is", "endmacro", "macro" + ] + const reKeyword = new RegExp("^" + keywords.join("\\s+|") + "\\s+") + const filters = [ + "abs", "attr", "batch", "capitalize", "center", "default", "dictsort", "escape", + "filesizeformat", "first", "float", "forceescape", "format", "groupby", "indent", + "int", "join", "last", "length", "list", "lower", "map", "max", "min", "pprint", + "random", "reject", "rejectattr", "replace", "reverse", "round", "tojson", "safe", + "select", "selectattr", "slice", "sort", "string", "striptags", "sum", "title", + "trim", "truncate", "unique", "upper", "urlencode", "urlize", "wordcount", + "wordwrap", "xmlattr" + ] + // This RegExp may be useful: + // const reFilter = new RegExp("^" + filters.join("\\([^(]*\\)|") + "\\([^(]*\\)") + const reFilter = new RegExp("^" + filters.join("|")) + + function jinja2Element(stream:StringStream): string { + if ( + (state.klipperMacroJinjaPercent && stream.match(/^%}/)) || + (!state.klipperMacroJinjaPercent && stream.match(/^}/), false) + ) { + state.klipperMacroJinja = false + state.klipperMacroJinjaPercent = false + stream.eatSpace() + state.gcodeZeroPos = stream.pos + return 'tag' + } + /* string, operator, keyword, atom, number */ + if (stream.match(/^"[^"]+"/)) { + return 'string' + } + if (stream.match(reKeyword)) { + return 'keyword' + } + if (stream.match(reFilter)) { + if (stream.peek() === "(") { + return 'updateOperator' + } + } + if (stream.match(reOperator)) { + return 'number' + } + if (stream.match(/^true\s|false\s/)) { + return 'atom' + } + if (stream.match(/^\d+/)) { + return 'number' + } + stream.next() + stream.eatSpace() + state.indent = stream.indentation() + return 'propertyName' + } const ch = stream.peek() /* comments */ @@ -53,43 +110,17 @@ export const klipper_config: StreamParser = { if (!state.gcodeZeroPos) { stream.eatSpace() + state.indent = stream.indentation() state.gcodeZeroPos = stream.pos } if (state.klipperMacroJinja) { - if ( - (state.klipperMacroJinjaPercent && stream.match(/^%}/)) || - (!state.klipperMacroJinjaPercent && stream.match(/^}/)) - ) { - state.klipperMacroJinja = false - state.klipperMacroJinjaPercent = false - stream.eatSpace() - state.gcodeZeroPos = stream.pos - return 'tag' - } - /* string, operator, keyword, atom, number */ - if (stream.match(/^"[^"]+"/)) { - return 'string' - } - if (stream.match(reOperator)) { - return 'number' - } - if (stream.match(reKeyword)) { - return 'keyword' - } - if (stream.match(/^true\s|false\s/)) { - return 'atom' - } - if (stream.match(/^\d+/)) { - return 'number' - } - stream.next() - stream.eatSpace() - return 'propertyName' + return jinja2Element(stream) } if (stream.match(/^\s*{[%#{]?/)) { state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true + state.indent = stream.indentation() return 'tag' } return gcode.token(stream, state, state.gcodeZeroPos ?? 0) @@ -99,38 +130,11 @@ export const klipper_config: StreamParser = { if (state.gcode) { if (stream.sol()) { stream.eatSpace() + state.indent = stream.indentation() state.gcodeZeroPos = stream.pos } if (state.klipperMacroJinja) { - if ( - (state.klipperMacroJinjaPercent && stream.match(/^%}/)) || - (!state.klipperMacroJinjaPercent && stream.match(/^}/)) - ) { - state.klipperMacroJinja = false - state.klipperMacroJinjaPercent = false - stream.eatSpace() - state.gcodeZeroPos = stream.pos - return 'tag' - } - /* string, operator, keyword, atom, number */ - if (stream.match(/^"[^"]+"/)) { - return 'string' - } - if (stream.match(reOperator)) { - return 'number' - } - if (stream.match(reKeyword)) { - return 'keyword' - } - if (stream.match(/^true\s|false\s/)) { - return 'atom' - } - if (stream.match(/^\d+/)) { - return 'number' - } - stream.next() - stream.eatSpace() - return 'propertyName' + return jinja2Element(stream) } if (stream.match(/^\s*{[%#{]?/)) { state.klipperMacroJinjaPercent = stream.string.includes('{%') @@ -202,6 +206,7 @@ export const klipper_config: StreamParser = { gcode: false, klipperMacro: false, gcodeZeroPos: null, + indent: 0, klipperMacroJinja: false, klipperMacroJinjaPercent: false, } @@ -217,6 +222,7 @@ interface StreamParserKlipperConfigState { was: boolean gcode: boolean gcodeZeroPos: number | null + indent: number | null klipperMacro: boolean klipperMacroJinja: boolean klipperMacroJinjaPercent: boolean diff --git a/src/plugins/codemirrorTheme.ts b/src/plugins/codemirrorTheme.ts index f1d3decd4..01dfd312a 100644 --- a/src/plugins/codemirrorTheme.ts +++ b/src/plugins/codemirrorTheme.ts @@ -52,6 +52,7 @@ const mainsailHighlightStyle = HighlightStyle.define([ { tag: t.name, color: '#e40', fontWeight: 'bold' }, { tag: t.propertyName, color: '#e56735' }, { tag: t.keyword, color: '#fcbe03'}, + { tag: t.updateOperator, color: '#b525d0'}, { tag: t.operator, color: '#fc03fc'} ]) const fn0 = mainsailHighlightStyle.style From fde46e5c15eaa918416596a1fb6fe91f3fbac6f1 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Fri, 2 Sep 2022 00:01:11 -0400 Subject: [PATCH 05/22] clean up cruft --- .gitignore | 2 +- src/plugins/StreamParserKlipperConfig.ts | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 0af695f31..449a0bb74 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ temp package-lock.json *.local .env -.vscode +.vscode/ cypress/videos/ components.d.ts diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 63bf8d4b3..89f114492 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -11,7 +11,7 @@ export const klipper_config: StreamParser = { const keywords = [ "if", "elif", "else", "endif", "endfor", "for", "loop\\.index", "loop\\.revindex", "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", - "and", "or", "not", "in", "is", "endmacro", "macro" + "and", "or", "not", "in", "is", "endmacro", "macro", "endcall", "call" ] const reKeyword = new RegExp("^" + keywords.join("\\s+|") + "\\s+") const filters = [ @@ -23,7 +23,6 @@ export const klipper_config: StreamParser = { "trim", "truncate", "unique", "upper", "urlencode", "urlize", "wordcount", "wordwrap", "xmlattr" ] - // This RegExp may be useful: // const reFilter = new RegExp("^" + filters.join("\\([^(]*\\)|") + "\\([^(]*\\)") const reFilter = new RegExp("^" + filters.join("|")) @@ -61,7 +60,6 @@ export const klipper_config: StreamParser = { } stream.next() stream.eatSpace() - state.indent = stream.indentation() return 'propertyName' } @@ -110,7 +108,6 @@ export const klipper_config: StreamParser = { if (!state.gcodeZeroPos) { stream.eatSpace() - state.indent = stream.indentation() state.gcodeZeroPos = stream.pos } @@ -120,7 +117,6 @@ export const klipper_config: StreamParser = { if (stream.match(/^\s*{[%#{]?/)) { state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true - state.indent = stream.indentation() return 'tag' } return gcode.token(stream, state, state.gcodeZeroPos ?? 0) @@ -130,7 +126,6 @@ export const klipper_config: StreamParser = { if (state.gcode) { if (stream.sol()) { stream.eatSpace() - state.indent = stream.indentation() state.gcodeZeroPos = stream.pos } if (state.klipperMacroJinja) { @@ -206,7 +201,6 @@ export const klipper_config: StreamParser = { gcode: false, klipperMacro: false, gcodeZeroPos: null, - indent: 0, klipperMacroJinja: false, klipperMacroJinjaPercent: false, } @@ -222,7 +216,6 @@ interface StreamParserKlipperConfigState { was: boolean gcode: boolean gcodeZeroPos: number | null - indent: number | null klipperMacro: boolean klipperMacroJinja: boolean klipperMacroJinjaPercent: boolean From 985f984d8e7c44705427a9f96ddfd3b346ee6496 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Fri, 2 Sep 2022 00:14:52 -0400 Subject: [PATCH 06/22] clean up cruft #2 --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 449a0bb74..fbf2a4fa2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ temp package-lock.json *.local .env -.vscode/ cypress/videos/ components.d.ts From 698fbb90c3dc1c97bfaecbb8b274adfc90730ba0 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Sun, 11 Sep 2022 02:52:13 -0400 Subject: [PATCH 07/22] more jinja2 keywords, better regex --- .gitignore | 1 + .vscode/settings.json | 20 ------------- src/plugins/StreamParserKlipperConfig.ts | 36 +++++++++++++++++++----- 3 files changed, 30 insertions(+), 27 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index fbf2a4fa2..0af695f31 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ temp package-lock.json *.local .env +.vscode cypress/videos/ components.d.ts diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 29819fc51..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "MicroPython.executeButton": [ - { - "text": "▶", - "tooltip": "Run", - "alignment": "left", - "command": "extension.executeFile", - "priority": 3.5 - } - ], - "MicroPython.syncButton": [ - { - "text": "$(sync)", - "tooltip": "sync", - "alignment": "left", - "command": "extension.execute", - "priority": 4 - } - ] -} \ No newline at end of file diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 89f114492..3a01713e2 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -3,17 +3,19 @@ import { gcode } from '@/plugins/StreamParserGcode' export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { + /* see https://tedboy.github.io/jinja2/off_doc.templates.html */ const operators = [ "\\+\\(", "-\\(", "\\/\\/\\(", "\\/\\(", "%\\(", "\\*\\*", "\\*", "\\(", "\\)", - "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~" + "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~", "," ] - const reOperator = new RegExp("^" + operators.join("|")) + const reOperator = new RegExp("^\\(" + operators.join("|") + "\\)") + const keywords = [ - "if", "elif", "else", "endif", "endfor", "for", "loop\\.index", "loop\\.revindex", + "elif", "else", "endif", "if", "endfor", "for", "loop\\.index", "loop\\.revindex", "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", - "and", "or", "not", "in", "is", "endmacro", "macro", "endcall", "call" + "and", "or", "not", "in", "is", "endmacro", "macro", "endcall", "call", "endfilter", + "filter", "endset", "set", "extends", "block", "endblock", "include", "import" ] - const reKeyword = new RegExp("^" + keywords.join("\\s+|") + "\\s+") const filters = [ "abs", "attr", "batch", "capitalize", "center", "default", "dictsort", "escape", "filesizeformat", "first", "float", "forceescape", "format", "groupby", "indent", @@ -23,8 +25,28 @@ export const klipper_config: StreamParser = { "trim", "truncate", "unique", "upper", "urlencode", "urlize", "wordcount", "wordwrap", "xmlattr" ] + const tests = [ + "callable", "defined", "divisibleby", "equalto", "escaped", "even", "iterable", + "lower", "mapping", "none", "number", "odd", "sameas", "sequence", "string", + "undefined", "upper" + ] + const globalFns = [ + "range", "lipsum", "dict", "cycler", "joiner" + ] + const cyclerMethods = [ + "\\.reset\\(\\)", "\\.next\\(\\)" + ] + // const reFilter = new RegExp("^" + filters.join("\\([^(]*\\)|") + "\\([^(]*\\)") - const reFilter = new RegExp("^" + filters.join("|")) + const reKeyword = new RegExp( + "^\\(" + keywords.join("\\s+|") + "|" + + cyclerMethods.join("|") + "\\)\\s+" + ) + const reUpdateOps = new RegExp( + "^\\(" + filters.join("|") + "|" + + tests.join("|") + "|" + + globalFns.join("|") + "\\)\\s+" + ) function jinja2Element(stream:StringStream): string { if ( @@ -44,7 +66,7 @@ export const klipper_config: StreamParser = { if (stream.match(reKeyword)) { return 'keyword' } - if (stream.match(reFilter)) { + if (stream.match(reUpdateOps)) { if (stream.peek() === "(") { return 'updateOperator' } From 670e9f866389aefc17b877c2281f9683dca0d5d4 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Sun, 11 Sep 2022 04:26:27 -0400 Subject: [PATCH 08/22] regex fix --- src/plugins/StreamParserKlipperConfig.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 3a01713e2..381bbc522 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -39,13 +39,13 @@ export const klipper_config: StreamParser = { // const reFilter = new RegExp("^" + filters.join("\\([^(]*\\)|") + "\\([^(]*\\)") const reKeyword = new RegExp( - "^\\(" + keywords.join("\\s+|") + "|" + - cyclerMethods.join("|") + "\\)\\s+" + "^" + keywords.join("\\s+|") + "|" + + cyclerMethods.join("|") + "\\s+" ) const reUpdateOps = new RegExp( - "^\\(" + filters.join("|") + "|" + + "^" + filters.join("|") + "|" + tests.join("|") + "|" + - globalFns.join("|") + "\\)\\s+" + globalFns.join("|") + "\\s+" ) function jinja2Element(stream:StringStream): string { From 1eda82d412cbc91bea4c717ef325b0c2d9c848e4 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Mon, 12 Sep 2022 02:50:31 -0400 Subject: [PATCH 09/22] SPKConfig: regex fix in klipper_config(), jinja2Element() --- src/plugins/StreamParserKlipperConfig.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 381bbc522..3973922c2 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -6,7 +6,7 @@ export const klipper_config: StreamParser = { /* see https://tedboy.github.io/jinja2/off_doc.templates.html */ const operators = [ "\\+\\(", "-\\(", "\\/\\/\\(", "\\/\\(", "%\\(", "\\*\\*", "\\*", "\\(", "\\)", - "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~", "," + "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~", "," //, "{%", "%}", "{", "}" ] const reOperator = new RegExp("^\\(" + operators.join("|") + "\\)") @@ -51,7 +51,7 @@ export const klipper_config: StreamParser = { function jinja2Element(stream:StringStream): string { if ( (state.klipperMacroJinjaPercent && stream.match(/^%}/)) || - (!state.klipperMacroJinjaPercent && stream.match(/^}/), false) + (!state.klipperMacroJinjaPercent && stream.match(/^}/)) ) { state.klipperMacroJinja = false state.klipperMacroJinjaPercent = false @@ -136,7 +136,7 @@ export const klipper_config: StreamParser = { if (state.klipperMacroJinja) { return jinja2Element(stream) } - if (stream.match(/^\s*{[%#{]?/)) { + if (stream.match(/^\s*{[%#]?/)) { state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true return 'tag' @@ -153,7 +153,7 @@ export const klipper_config: StreamParser = { if (state.klipperMacroJinja) { return jinja2Element(stream) } - if (stream.match(/^\s*{[%#{]?/)) { + if (stream.match(/^\s*{[%#]?/)) { state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true return 'tag' From d1171f7e0486e19683b4434ee9edf4287e21fbed Mon Sep 17 00:00:00 2001 From: truckershitch Date: Mon, 12 Sep 2022 11:10:34 -0400 Subject: [PATCH 10/22] fix: added eatWhile() to jinja2Element() --- src/plugins/StreamParserKlipperConfig.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 3973922c2..703722c9f 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -1,5 +1,6 @@ import { StreamLanguage, StreamParser, StringStream } from '@codemirror/language' import { gcode } from '@/plugins/StreamParserGcode' +import { SlowBuffer } from 'buffer' export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { @@ -14,7 +15,7 @@ export const klipper_config: StreamParser = { "elif", "else", "endif", "if", "endfor", "for", "loop\\.index", "loop\\.revindex", "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", "and", "or", "not", "in", "is", "endmacro", "macro", "endcall", "call", "endfilter", - "filter", "endset", "set", "extends", "block", "endblock", "include", "import" + "filter", "endset", "set", "extends", "block", "endblock", "include", "import", "do" ] const filters = [ "abs", "attr", "batch", "capitalize", "center", "default", "dictsort", "escape", @@ -60,7 +61,7 @@ export const klipper_config: StreamParser = { return 'tag' } /* string, operator, keyword, atom, number */ - if (stream.match(/^"[^"]+"/)) { + if (stream.match(/^"[^"]+"/) || stream.match(/^'[^']+'/)) { return 'string' } if (stream.match(reKeyword)) { @@ -80,8 +81,9 @@ export const klipper_config: StreamParser = { if (stream.match(/^\d+/)) { return 'number' } + stream.eatWhile(/^[a-z0-9_]/i) stream.next() - stream.eatSpace() + return 'propertyName' } From b9cf9261ea7dcfa5efda92c5c25f54dd83578af0 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Tue, 13 Sep 2022 03:54:06 -0400 Subject: [PATCH 11/22] refactored jinja2Element, reOperator tweak --- src/plugins/StreamParserKlipperConfig.ts | 40 ++++++++++++++++-------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 703722c9f..659f5f4b7 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -6,10 +6,10 @@ export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { /* see https://tedboy.github.io/jinja2/off_doc.templates.html */ const operators = [ - "\\+\\(", "-\\(", "\\/\\/\\(", "\\/\\(", "%\\(", "\\*\\*", "\\*", "\\(", "\\)", - "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~", "," //, "{%", "%}", "{", "}" + "\\+", "-", "\\/\\/", "\\/", "%", "\\*\\*", "\\*", "\\(", "\\)", + "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~", "," ] - const reOperator = new RegExp("^\\(" + operators.join("|") + "\\)") + const reOperator = new RegExp("^" + operators.join("|")) const keywords = [ "elif", "else", "endif", "if", "endfor", "for", "loop\\.index", "loop\\.revindex", @@ -37,8 +37,6 @@ export const klipper_config: StreamParser = { const cyclerMethods = [ "\\.reset\\(\\)", "\\.next\\(\\)" ] - - // const reFilter = new RegExp("^" + filters.join("\\([^(]*\\)|") + "\\([^(]*\\)") const reKeyword = new RegExp( "^" + keywords.join("\\s+|") + "|" + cyclerMethods.join("|") + "\\s+" @@ -60,30 +58,44 @@ export const klipper_config: StreamParser = { state.gcodeZeroPos = stream.pos return 'tag' } - /* string, operator, keyword, atom, number */ if (stream.match(/^"[^"]+"/) || stream.match(/^'[^']+'/)) { + state.klipperMacroJinjaWillHighlight = false return 'string' } - if (stream.match(reKeyword)) { - return 'keyword' + if (state.klipperMacroJinjaWillHighlight) { + if (stream.match(reKeyword)) { + state.klipperMacroJinjaWillHighlight = false + return 'keyword' + } } - if (stream.match(reUpdateOps)) { - if (stream.peek() === "(") { - return 'updateOperator' + if (state.klipperMacroJinjaWillHighlight) { + if (stream.match(reUpdateOps)) { + // adding '}' for filters at end of template line without trailing parentheses + if (['(', '}'].includes(stream.peek() ?? '')) { + state.klipperMacroJinjaWillHighlight = false + return 'updateOperator' + } } } if (stream.match(reOperator)) { + state.klipperMacroJinjaWillHighlight = true return 'number' } if (stream.match(/^true\s|false\s/)) { + state.klipperMacroJinjaWillHighlight = false return 'atom' } if (stream.match(/^\d+/)) { + state.klipperMacroJinjaWillHighlight = false return 'number' } - stream.eatWhile(/^[a-z0-9_]/i) + if (stream.eatSpace()) { + state.klipperMacroJinjaWillHighlight = true + return 'propertyName' + } stream.next() - + + state.klipperMacroJinjaWillHighlight = false return 'propertyName' } @@ -227,6 +239,7 @@ export const klipper_config: StreamParser = { gcodeZeroPos: null, klipperMacroJinja: false, klipperMacroJinjaPercent: false, + klipperMacroJinjaWillHighlight: false, } }, languageData: { @@ -243,4 +256,5 @@ interface StreamParserKlipperConfigState { klipperMacro: boolean klipperMacroJinja: boolean klipperMacroJinjaPercent: boolean + klipperMacroJinjaWillHighlight: boolean } From 53dd652d5bfd150259b20c5b7d7f82671e96e622 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Tue, 13 Sep 2022 04:09:28 -0400 Subject: [PATCH 12/22] added space to updateOperator "peek" check array --- src/plugins/StreamParserKlipperConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 659f5f4b7..6a53a8b45 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -71,7 +71,7 @@ export const klipper_config: StreamParser = { if (state.klipperMacroJinjaWillHighlight) { if (stream.match(reUpdateOps)) { // adding '}' for filters at end of template line without trailing parentheses - if (['(', '}'].includes(stream.peek() ?? '')) { + if (['(', '}', ' '].includes(stream.peek() ?? '')) { state.klipperMacroJinjaWillHighlight = false return 'updateOperator' } From 5f92f907980ac250e756e6ca259cd41724d11621 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Tue, 13 Sep 2022 09:11:19 -0400 Subject: [PATCH 13/22] added a comma to updateOperator "peek" check array - may need more chars (tokens?) --- src/plugins/StreamParserKlipperConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 6a53a8b45..223bb3c58 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -71,7 +71,7 @@ export const klipper_config: StreamParser = { if (state.klipperMacroJinjaWillHighlight) { if (stream.match(reUpdateOps)) { // adding '}' for filters at end of template line without trailing parentheses - if (['(', '}', ' '].includes(stream.peek() ?? '')) { + if (['(', '}', ',', ' '].includes(stream.peek() ?? '')) { state.klipperMacroJinjaWillHighlight = false return 'updateOperator' } From ba86a4b941c36e2ba1ca5b865846eff3fca55846 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Tue, 13 Sep 2022 09:38:20 -0400 Subject: [PATCH 14/22] Amended number regex for better tagging --- src/plugins/StreamParserKlipperConfig.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 223bb3c58..a51cd7dc7 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -85,8 +85,9 @@ export const klipper_config: StreamParser = { state.klipperMacroJinjaWillHighlight = false return 'atom' } - if (stream.match(/^\d+/)) { - state.klipperMacroJinjaWillHighlight = false + // if (stream.match(/^\d+/)) { + if (stream.match(/^[-+]?[0-9]*\.?[0-9]+/)) { + state.klipperMacroJinjaWillHighlight = false return 'number' } if (stream.eatSpace()) { From e4ab241d20039d5a9406dc69b92c4b05e2245aa8 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Thu, 15 Sep 2022 01:47:38 -0400 Subject: [PATCH 15/22] Refactored jinja tags (stacks) / variables / strings, other fixes --- src/plugins/StreamParserGcode.ts | 21 +++- src/plugins/StreamParserKlipperConfig.ts | 150 +++++++++++++++++------ 2 files changed, 131 insertions(+), 40 deletions(-) diff --git a/src/plugins/StreamParserGcode.ts b/src/plugins/StreamParserGcode.ts index adebead5d..e5f5bc311 100644 --- a/src/plugins/StreamParserGcode.ts +++ b/src/plugins/StreamParserGcode.ts @@ -9,11 +9,22 @@ export const gcode = { /* Klipper macro attributes */ if (stream.pos > zeroPos && state.klipperMacro) { stream.eatSpace() - if (stream.match(/^(".+"|true|false)/i)) { + if (stream.match(/^{/)) { + return 'tag' + } + // else if (stream.match(/^'|"/)) { + else if (stream.match(/^"[^{]+"/) || stream.match(/^'[^{]+'/)) { return 'string' - } else if (stream.match(/^\d+/)) return 'number' - else if (stream.match(/^[A-Za-z\d_]+/)) return 'propertyName' - else if (zeroPos === 0 && stream.match(/^{[^%]+}/)) return 'variable' + } + else if (stream.match(/^[-+]?[0-9]*\.?[0-9]+/)) { + return 'number' + } + else if (stream.match(/^[A-Za-z\d_]+/)) { + return 'propertyName' + } + else if (zeroPos === 0 && stream.match(/^{[^%]+}/)) { + return 'variable' + } } /* comments */ @@ -29,7 +40,7 @@ export const gcode = { return 'namespace' } - if (stream.string.substr(zeroPos).toLowerCase().startsWith('m117')) { + if (stream.string.substring(zeroPos).toLowerCase().startsWith('m117')) { stream.skipToEnd() return 'string' } diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index a51cd7dc7..8ec9b8cfe 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -1,6 +1,8 @@ import { StreamLanguage, StreamParser, StringStream } from '@codemirror/language' import { gcode } from '@/plugins/StreamParserGcode' import { SlowBuffer } from 'buffer' +import { StateField } from '@codemirror/state' +import { toInteger } from 'cypress/types/lodash' export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { @@ -48,55 +50,74 @@ export const klipper_config: StreamParser = { ) function jinja2Element(stream:StringStream): string { - if ( - (state.klipperMacroJinjaPercent && stream.match(/^%}/)) || - (!state.klipperMacroJinjaPercent && stream.match(/^}/)) - ) { - state.klipperMacroJinja = false - state.klipperMacroJinjaPercent = false + const pctMatch: any = stream.match(/^%}/) + const braceMatch: any = stream.match(/^}/) + function notJinja(): boolean { + return ( + state.klipperMacroJinjaBraceStack.length === 0 && + state.klipperMacroJinjaPctStack.length === 0 + ) + } + + if (pctMatch || braceMatch) { + if (pctMatch) { + state.klipperMacroJinjaPctStack.pop() + if (notJinja()) { + state.klipperMacroJinja = false + } + } + else { // brace match + state.klipperMacroJinjaBraceStack.pop() + if (notJinja()) { + state.klipperMacroJinja = false + } + } stream.eatSpace() state.gcodeZeroPos = stream.pos return 'tag' } if (stream.match(/^"[^"]+"/) || stream.match(/^'[^']+'/)) { - state.klipperMacroJinjaWillHighlight = false + state.klipperMacroJinjaHighlightNext = true return 'string' } - if (state.klipperMacroJinjaWillHighlight) { + if (stream.eol() && stream.match(/^"/)) { + state.klipperMacroJinjaHighlightNext = false + return 'string' + } + if (state.klipperMacroJinjaHighlightNext) { if (stream.match(reKeyword)) { - state.klipperMacroJinjaWillHighlight = false + state.klipperMacroJinjaHighlightNext = false return 'keyword' } } - if (state.klipperMacroJinjaWillHighlight) { + if (state.klipperMacroJinjaHighlightNext) { if (stream.match(reUpdateOps)) { - // adding '}' for filters at end of template line without trailing parentheses - if (['(', '}', ',', ' '].includes(stream.peek() ?? '')) { - state.klipperMacroJinjaWillHighlight = false + // check character after "updateOp" element -- might not be a "(" + if (['(', '}', ',', '|', ' '].includes(stream.peek() ?? '')) { + state.klipperMacroJinjaHighlightNext = false return 'updateOperator' } } } if (stream.match(reOperator)) { - state.klipperMacroJinjaWillHighlight = true + state.klipperMacroJinjaHighlightNext = true return 'number' } - if (stream.match(/^true\s|false\s/)) { - state.klipperMacroJinjaWillHighlight = false + if (stream.match(/^true\s|false\s/i)) { + state.klipperMacroJinjaHighlightNext = false return 'atom' } - // if (stream.match(/^\d+/)) { if (stream.match(/^[-+]?[0-9]*\.?[0-9]+/)) { - state.klipperMacroJinjaWillHighlight = false + state.klipperMacroJinjaHighlightNext = false return 'number' } if (stream.eatSpace()) { - state.klipperMacroJinjaWillHighlight = true + state.klipperMacroJinjaHighlightNext = true return 'propertyName' } stream.next() - state.klipperMacroJinjaWillHighlight = false + state.klipperMacroJinjaHighlightNext = false return 'propertyName' } @@ -147,33 +168,59 @@ export const klipper_config: StreamParser = { stream.eatSpace() state.gcodeZeroPos = stream.pos } - - if (state.klipperMacroJinja) { - return jinja2Element(stream) - } if (stream.match(/^\s*{[%#]?/)) { - state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true + if (stream.string.includes('{%')) { + state.klipperMacroJinjaPctStack.push('{%') + } + else { + state.klipperMacroJinjaBraceStack.push('{') + } return 'tag' } + if (state.klipperMacroJinja) { + return jinja2Element(stream) + } return gcode.token(stream, state, state.gcodeZeroPos ?? 0) } - } else { + } else { // stream.indentation > 0 state.was = true if (state.gcode) { if (stream.sol()) { stream.eatSpace() state.gcodeZeroPos = stream.pos } + if (stream.match(/^\s*{[%#]?/)) { + state.klipperMacroJinja = true + if (stream.string.includes('{%')) { + state.klipperMacroJinjaPctStack.push('{%') + } + else { + state.klipperMacroJinjaBraceStack.push('{') + } + return 'tag' + } if (state.klipperMacroJinja) { return jinja2Element(stream) } + return gcode.token(stream, state, state.gcodeZeroPos ?? stream.pos) + } else if (state.variable) { + if (stream.sol()) { + stream.eatSpace() + } if (stream.match(/^\s*{[%#]?/)) { - state.klipperMacroJinjaPercent = stream.string.includes('{%') state.klipperMacroJinja = true + if (stream.string.includes('{%')) { + state.klipperMacroJinjaPctStack.push('{%') + } + else { + state.klipperMacroJinjaBraceStack.push('{') + } return 'tag' } - return gcode.token(stream, state, state.gcodeZeroPos ?? stream.pos) + if (state.klipperMacroJinja) { + return jinja2Element(stream) + } } else if (state.pair) { stream.eatSpace() if (ch !== ',') { @@ -191,13 +238,18 @@ export const klipper_config: StreamParser = { if (state.was && stream.indentation() === 0) { state.pair = false state.gcode = false + state.variable = false state.was = false } - if (!state.pair && !state.gcode && stream.sol()) { + if (!state.pair && !state.gcode && !state.variable && stream.sol()) { if (stream.match(/^(?:[A-Za-z]*_?gcode|enable):/)) { state.gcode = true - } else { + } + else if (stream.match(/^variable_[a-zA-Z]+:/)) { + state.variable = true + } + else { stream.match(/^.+?:\s*/) state.pair = !stream.eol() } @@ -205,6 +257,31 @@ export const klipper_config: StreamParser = { return 'atom' } + if (state.variable) { + if (stream.sol() || stream.eol()) { + state.variable = false + return null + } + if (stream.match(/^\s*{[%#]?/)) { + state.klipperMacroJinja = true + if (stream.string.includes('{%')) { + state.klipperMacroJinjaPctStack.push('{%') + } + else { + state.klipperMacroJinjaBraceStack.push('{') + } + return 'tag' + } + else { // no Jinja in variable + state.pair = true + // state.variable = false + } + if (state.klipperMacroJinja) { + stream.eatSpace() + return jinja2Element(stream) + } + } + if (state.pair) { if (ch === ':') { stream.next() @@ -216,7 +293,6 @@ export const klipper_config: StreamParser = { state.pair = false return null } - if (stream.match(/^(-?\d*\.?(?:\d+)?(,|$|\s))+/)) { state.pair = false return 'number' @@ -236,11 +312,13 @@ export const klipper_config: StreamParser = { pair: false, was: false, gcode: false, + variable: false, klipperMacro: false, gcodeZeroPos: null, klipperMacroJinja: false, - klipperMacroJinjaPercent: false, - klipperMacroJinjaWillHighlight: false, + klipperMacroJinjaHighlightNext: false, + klipperMacroJinjaBraceStack: [], + klipperMacroJinjaPctStack: [], } }, languageData: { @@ -253,9 +331,11 @@ interface StreamParserKlipperConfigState { pair: boolean was: boolean gcode: boolean + variable: boolean gcodeZeroPos: number | null klipperMacro: boolean klipperMacroJinja: boolean - klipperMacroJinjaPercent: boolean - klipperMacroJinjaWillHighlight: boolean + klipperMacroJinjaHighlightNext: boolean // Highlight next element if no space follows curent keyword + klipperMacroJinjaBraceStack: string[] // Should these two stacks be combined for overhead / aesthetics? + klipperMacroJinjaPctStack: string[] } From d7ab4b48e7667abca08434b430e2f3c7c73fe690 Mon Sep 17 00:00:00 2001 From: truckershitch Date: Mon, 26 Sep 2022 17:23:51 -0400 Subject: [PATCH 16/22] Fix for enquoted escaped quotes --- src/plugins/StreamParserKlipperConfig.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 8ec9b8cfe..be6b5d468 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -76,8 +76,9 @@ export const klipper_config: StreamParser = { state.gcodeZeroPos = stream.pos return 'tag' } - if (stream.match(/^"[^"]+"/) || stream.match(/^'[^']+'/)) { - state.klipperMacroJinjaHighlightNext = true + if (stream.match(/^"(?!\\")|[^"]+"/) || stream.match(/^'(?!\\')|[^']+'/)) { + // if (stream.match(/^"[^"]+"/) || stream.match(/^'[^']+'/)) { + state.klipperMacroJinjaHighlightNext = true return 'string' } if (stream.eol() && stream.match(/^"/)) { From 3b3c0209e02c067a89e8e371f69d22f3a6cf6eed Mon Sep 17 00:00:00 2001 From: truckershitch Date: Tue, 27 Sep 2022 03:12:02 -0400 Subject: [PATCH 17/22] Better fix for enquoted escaped quotes --- src/plugins/StreamParserKlipperConfig.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index be6b5d468..4174d3501 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -76,9 +76,9 @@ export const klipper_config: StreamParser = { state.gcodeZeroPos = stream.pos return 'tag' } - if (stream.match(/^"(?!\\")|[^"]+"/) || stream.match(/^'(?!\\')|[^']+'/)) { - // if (stream.match(/^"[^"]+"/) || stream.match(/^'[^']+'/)) { - state.klipperMacroJinjaHighlightNext = true + // https://www.metaltoad.com/blog/regex-quoted-string-escapable-quotes + if (stream.match(/^((? Date: Sat, 18 Feb 2023 15:20:58 +0100 Subject: [PATCH 18/22] style: run prettier to format code Signed-off-by: Stefan Dej --- src/plugins/StreamParserGcode.ts | 9 +- src/plugins/StreamParserKlipperConfig.ts | 193 ++++++++++++++++------- src/plugins/codemirrorTheme.ts | 6 +- 3 files changed, 145 insertions(+), 63 deletions(-) diff --git a/src/plugins/StreamParserGcode.ts b/src/plugins/StreamParserGcode.ts index e5f5bc311..721286b50 100644 --- a/src/plugins/StreamParserGcode.ts +++ b/src/plugins/StreamParserGcode.ts @@ -15,14 +15,11 @@ export const gcode = { // else if (stream.match(/^'|"/)) { else if (stream.match(/^"[^{]+"/) || stream.match(/^'[^{]+'/)) { return 'string' - } - else if (stream.match(/^[-+]?[0-9]*\.?[0-9]+/)) { + } else if (stream.match(/^[-+]?[0-9]*\.?[0-9]+/)) { return 'number' - } - else if (stream.match(/^[A-Za-z\d_]+/)) { + } else if (stream.match(/^[A-Za-z\d_]+/)) { return 'propertyName' - } - else if (zeroPos === 0 && stream.match(/^{[^%]+}/)) { + } else if (zeroPos === 0 && stream.match(/^{[^%]+}/)) { return 'variable' } } diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index 4174d3501..c058e82eb 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -8,55 +8,145 @@ export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { /* see https://tedboy.github.io/jinja2/off_doc.templates.html */ const operators = [ - "\\+", "-", "\\/\\/", "\\/", "%", "\\*\\*", "\\*", "\\(", "\\)", - "==", "!=", ">=", ">", "<=", "<", "=", "\\|", "~", "," + '\\+', + '-', + '\\/\\/', + '\\/', + '%', + '\\*\\*', + '\\*', + '\\(', + '\\)', + '==', + '!=', + '>=', + '>', + '<=', + '<', + '=', + '\\|', + '~', + ',', ] - const reOperator = new RegExp("^" + operators.join("|")) - + const reOperator = new RegExp('^' + operators.join('|')) + const keywords = [ - "elif", "else", "endif", "if", "endfor", "for", "loop\\.index", "loop\\.revindex", - "loop\\.first", "loop\\.last", "loop\\.length", "loop\\.cycle", "loop\\.depth", - "and", "or", "not", "in", "is", "endmacro", "macro", "endcall", "call", "endfilter", - "filter", "endset", "set", "extends", "block", "endblock", "include", "import", "do" + 'elif', + 'else', + 'endif', + 'if', + 'endfor', + 'for', + 'loop\\.index', + 'loop\\.revindex', + 'loop\\.first', + 'loop\\.last', + 'loop\\.length', + 'loop\\.cycle', + 'loop\\.depth', + 'and', + 'or', + 'not', + 'in', + 'is', + 'endmacro', + 'macro', + 'endcall', + 'call', + 'endfilter', + 'filter', + 'endset', + 'set', + 'extends', + 'block', + 'endblock', + 'include', + 'import', + 'do', ] const filters = [ - "abs", "attr", "batch", "capitalize", "center", "default", "dictsort", "escape", - "filesizeformat", "first", "float", "forceescape", "format", "groupby", "indent", - "int", "join", "last", "length", "list", "lower", "map", "max", "min", "pprint", - "random", "reject", "rejectattr", "replace", "reverse", "round", "tojson", "safe", - "select", "selectattr", "slice", "sort", "string", "striptags", "sum", "title", - "trim", "truncate", "unique", "upper", "urlencode", "urlize", "wordcount", - "wordwrap", "xmlattr" + 'abs', + 'attr', + 'batch', + 'capitalize', + 'center', + 'default', + 'dictsort', + 'escape', + 'filesizeformat', + 'first', + 'float', + 'forceescape', + 'format', + 'groupby', + 'indent', + 'int', + 'join', + 'last', + 'length', + 'list', + 'lower', + 'map', + 'max', + 'min', + 'pprint', + 'random', + 'reject', + 'rejectattr', + 'replace', + 'reverse', + 'round', + 'tojson', + 'safe', + 'select', + 'selectattr', + 'slice', + 'sort', + 'string', + 'striptags', + 'sum', + 'title', + 'trim', + 'truncate', + 'unique', + 'upper', + 'urlencode', + 'urlize', + 'wordcount', + 'wordwrap', + 'xmlattr', ] const tests = [ - "callable", "defined", "divisibleby", "equalto", "escaped", "even", "iterable", - "lower", "mapping", "none", "number", "odd", "sameas", "sequence", "string", - "undefined", "upper" - ] - const globalFns = [ - "range", "lipsum", "dict", "cycler", "joiner" + 'callable', + 'defined', + 'divisibleby', + 'equalto', + 'escaped', + 'even', + 'iterable', + 'lower', + 'mapping', + 'none', + 'number', + 'odd', + 'sameas', + 'sequence', + 'string', + 'undefined', + 'upper', ] - const cyclerMethods = [ - "\\.reset\\(\\)", "\\.next\\(\\)" - ] - const reKeyword = new RegExp( - "^" + keywords.join("\\s+|") + "|" + - cyclerMethods.join("|") + "\\s+" - ) + const globalFns = ['range', 'lipsum', 'dict', 'cycler', 'joiner'] + const cyclerMethods = ['\\.reset\\(\\)', '\\.next\\(\\)'] + const reKeyword = new RegExp('^' + keywords.join('\\s+|') + '|' + cyclerMethods.join('|') + '\\s+') const reUpdateOps = new RegExp( - "^" + filters.join("|") + "|" + - tests.join("|") + "|" + - globalFns.join("|") + "\\s+" + '^' + filters.join('|') + '|' + tests.join('|') + '|' + globalFns.join('|') + '\\s+' ) - function jinja2Element(stream:StringStream): string { + function jinja2Element(stream: StringStream): string { const pctMatch: any = stream.match(/^%}/) const braceMatch: any = stream.match(/^}/) function notJinja(): boolean { - return ( - state.klipperMacroJinjaBraceStack.length === 0 && - state.klipperMacroJinjaPctStack.length === 0 - ) + return state.klipperMacroJinjaBraceStack.length === 0 && state.klipperMacroJinjaPctStack.length === 0 } if (pctMatch || braceMatch) { @@ -65,8 +155,8 @@ export const klipper_config: StreamParser = { if (notJinja()) { state.klipperMacroJinja = false } - } - else { // brace match + } else { + // brace match state.klipperMacroJinjaBraceStack.pop() if (notJinja()) { state.klipperMacroJinja = false @@ -109,7 +199,7 @@ export const klipper_config: StreamParser = { return 'atom' } if (stream.match(/^[-+]?[0-9]*\.?[0-9]+/)) { - state.klipperMacroJinjaHighlightNext = false + state.klipperMacroJinjaHighlightNext = false return 'number' } if (stream.eatSpace()) { @@ -173,8 +263,7 @@ export const klipper_config: StreamParser = { state.klipperMacroJinja = true if (stream.string.includes('{%')) { state.klipperMacroJinjaPctStack.push('{%') - } - else { + } else { state.klipperMacroJinjaBraceStack.push('{') } return 'tag' @@ -184,7 +273,8 @@ export const klipper_config: StreamParser = { } return gcode.token(stream, state, state.gcodeZeroPos ?? 0) } - } else { // stream.indentation > 0 + } else { + // stream.indentation > 0 state.was = true if (state.gcode) { if (stream.sol()) { @@ -195,8 +285,7 @@ export const klipper_config: StreamParser = { state.klipperMacroJinja = true if (stream.string.includes('{%')) { state.klipperMacroJinjaPctStack.push('{%') - } - else { + } else { state.klipperMacroJinjaBraceStack.push('{') } return 'tag' @@ -213,8 +302,7 @@ export const klipper_config: StreamParser = { state.klipperMacroJinja = true if (stream.string.includes('{%')) { state.klipperMacroJinjaPctStack.push('{%') - } - else { + } else { state.klipperMacroJinjaBraceStack.push('{') } return 'tag' @@ -246,11 +334,9 @@ export const klipper_config: StreamParser = { if (!state.pair && !state.gcode && !state.variable && stream.sol()) { if (stream.match(/^(?:[A-Za-z]*_?gcode|enable):/)) { state.gcode = true - } - else if (stream.match(/^variable_[a-zA-Z]+:/)) { + } else if (stream.match(/^variable_[a-zA-Z]+:/)) { state.variable = true - } - else { + } else { stream.match(/^.+?:\s*/) state.pair = !stream.eol() } @@ -267,13 +353,12 @@ export const klipper_config: StreamParser = { state.klipperMacroJinja = true if (stream.string.includes('{%')) { state.klipperMacroJinjaPctStack.push('{%') - } - else { + } else { state.klipperMacroJinjaBraceStack.push('{') } return 'tag' - } - else { // no Jinja in variable + } else { + // no Jinja in variable state.pair = true // state.variable = false } diff --git a/src/plugins/codemirrorTheme.ts b/src/plugins/codemirrorTheme.ts index 888cd32dc..0b937f2c7 100644 --- a/src/plugins/codemirrorTheme.ts +++ b/src/plugins/codemirrorTheme.ts @@ -120,9 +120,9 @@ const mainsailHighlightStyle = HighlightStyle.define([ { tag: t.className, color: '#c586c0' }, { tag: t.name, color: '#e40', fontWeight: 'bold' }, { tag: t.propertyName, color: '#e56735' }, - { tag: t.keyword, color: '#fcbe03'}, - { tag: t.updateOperator, color: '#b525d0'}, - { tag: t.operator, color: '#fc03fc'} + { tag: t.keyword, color: '#fcbe03' }, + { tag: t.updateOperator, color: '#b525d0' }, + { tag: t.operator, color: '#fc03fc' }, ]) const fn0 = mainsailHighlightStyle.style // noinspection JSConstantReassignment From a779fc510a4f23bffb07d1554b35226a3d983125 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Tue, 4 Apr 2023 22:19:30 +0200 Subject: [PATCH 19/22] refactor: remove unused comments/code Signed-off-by: Stefan Dej --- src/components/inputs/Codemirror.vue | 3 +-- src/plugins/StreamParserKlipperConfig.ts | 5 +---- src/plugins/codemirrorTheme.ts | 4 ---- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 026e481da..2e4d2dab5 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -1,5 +1,5 @@ @@ -15,7 +15,6 @@ import { EditorState } from '@codemirror/state' import { mainsailTheme } from '@/plugins/codemirrorTheme' import { StreamLanguage } from '@codemirror/language' import { klipper_config } from '@/plugins/StreamParserKlipperConfig' -// import { jinja2 } from '@/plugins/StreamParserJinja2' import { gcode } from '@/plugins/StreamParserGcode' import { indentWithTab } from '@codemirror/commands' import { json } from '@codemirror/lang-json' diff --git a/src/plugins/StreamParserKlipperConfig.ts b/src/plugins/StreamParserKlipperConfig.ts index c058e82eb..d1b7ce9ed 100644 --- a/src/plugins/StreamParserKlipperConfig.ts +++ b/src/plugins/StreamParserKlipperConfig.ts @@ -1,8 +1,5 @@ -import { StreamLanguage, StreamParser, StringStream } from '@codemirror/language' +import { StreamParser, StringStream } from '@codemirror/language' import { gcode } from '@/plugins/StreamParserGcode' -import { SlowBuffer } from 'buffer' -import { StateField } from '@codemirror/state' -import { toInteger } from 'cypress/types/lodash' export const klipper_config: StreamParser = { token: function (stream: StringStream, state: StreamParserKlipperConfigState): string | null { diff --git a/src/plugins/codemirrorTheme.ts b/src/plugins/codemirrorTheme.ts index 0b937f2c7..0cb6bc993 100644 --- a/src/plugins/codemirrorTheme.ts +++ b/src/plugins/codemirrorTheme.ts @@ -124,10 +124,6 @@ const mainsailHighlightStyle = HighlightStyle.define([ { tag: t.updateOperator, color: '#b525d0' }, { tag: t.operator, color: '#fc03fc' }, ]) -const fn0 = mainsailHighlightStyle.style -// noinspection JSConstantReassignment -// @ts-ignore -mainsailHighlightStyle.style = (tags) => fn0(tags || []) /// Extension to enable the Mox theme (both the editor theme and /// the highlight style). From 1fa03e815f72c26e966321c6d97a3fff3a9ee95a Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Tue, 4 Apr 2023 22:54:11 +0200 Subject: [PATCH 20/22] feat: add new theme Signed-off-by: Stefan Dej --- package-lock.json | 42 ++++++++++++++++++++++++++++ package.json | 1 + src/components/inputs/Codemirror.vue | 5 ++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bd8b92ca8..188fbabb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@sindarius/gcodeviewer": "^3.2.2", "@types/node": "^18.0.0", "@types/overlayscrollbars": "^1.12.1", + "@uiw/codemirror-theme-vscode": "^4.19.11", "axios": "^0.27.0", "codemirror": "^6.0.1", "core-js": "^3.16.0", @@ -3105,6 +3106,29 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uiw/codemirror-theme-vscode": { + "version": "4.19.11", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-vscode/-/codemirror-theme-vscode-4.19.11.tgz", + "integrity": "sha512-/SAei4iiIizEOvJ1rvIUc8y8HZLkIgzEWiC9UOZTAOKVcxIE7SLt1nTG3XRmPrceSltPgfTb0dLrsXoHQIPYKw==", + "dependencies": { + "@uiw/codemirror-themes": "4.19.11" + } + }, + "node_modules/@uiw/codemirror-themes": { + "version": "4.19.11", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.19.11.tgz", + "integrity": "sha512-4bh0vfkqeVJ7L2aGimKXqQtaoSEe/1xZb9nkGn35V5daHXkxRhb+BRFMOSrMsjGm74hM+dvYi5iH8HXVsvjJrQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "peerDependencies": { + "@codemirror/language": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, "node_modules/@vue/babel-helper-vue-jsx-merge-props": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", @@ -12248,6 +12272,24 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@uiw/codemirror-theme-vscode": { + "version": "4.19.11", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-vscode/-/codemirror-theme-vscode-4.19.11.tgz", + "integrity": "sha512-/SAei4iiIizEOvJ1rvIUc8y8HZLkIgzEWiC9UOZTAOKVcxIE7SLt1nTG3XRmPrceSltPgfTb0dLrsXoHQIPYKw==", + "requires": { + "@uiw/codemirror-themes": "4.19.11" + } + }, + "@uiw/codemirror-themes": { + "version": "4.19.11", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.19.11.tgz", + "integrity": "sha512-4bh0vfkqeVJ7L2aGimKXqQtaoSEe/1xZb9nkGn35V5daHXkxRhb+BRFMOSrMsjGm74hM+dvYi5iH8HXVsvjJrQ==", + "requires": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "@vue/babel-helper-vue-jsx-merge-props": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", diff --git a/package.json b/package.json index 99c06e6cf..3c6b894d3 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@sindarius/gcodeviewer": "^3.2.2", "@types/node": "^18.0.0", "@types/overlayscrollbars": "^1.12.1", + "@uiw/codemirror-theme-vscode": "^4.19.11", "axios": "^0.27.0", "codemirror": "^6.0.1", "core-js": "^3.16.0", diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 2e4d2dab5..5c071588e 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -12,7 +12,7 @@ import BaseMixin from '../mixins/base' import { basicSetup } from 'codemirror' import { EditorView, keymap } from '@codemirror/view' import { EditorState } from '@codemirror/state' -import { mainsailTheme } from '@/plugins/codemirrorTheme' +import { vscodeDark } from '@uiw/codemirror-theme-vscode' import { StreamLanguage } from '@codemirror/language' import { klipper_config } from '@/plugins/StreamParserKlipperConfig' import { gcode } from '@/plugins/StreamParserGcode' @@ -81,8 +81,9 @@ export default class Codemirror extends Mixins(BaseMixin) { get cmExtensions() { const extensions = [ + EditorView.theme({}, { dark: true }), basicSetup, - mainsailTheme, + vscodeDark, keymap.of([indentWithTab]), EditorView.updateListener.of((update) => { this.content = update.state?.doc.toString() From 568c1271a1287710ea7b602b388fb58a6f12f4be Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Tue, 4 Apr 2023 22:54:30 +0200 Subject: [PATCH 21/22] refactor: remove unused files Signed-off-by: Stefan Dej --- src/components/inputs/Codemirror.vue | 1 - src/plugins/StreamParserJinja2.ts | 144 --------------------------- src/plugins/StreamParserYaml.ts | 140 -------------------------- src/plugins/codemirrorTheme.ts | 130 ------------------------ 4 files changed, 415 deletions(-) delete mode 100644 src/plugins/StreamParserJinja2.ts delete mode 100644 src/plugins/StreamParserYaml.ts delete mode 100644 src/plugins/codemirrorTheme.ts diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 5c071588e..4490c7db7 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -95,7 +95,6 @@ export default class Codemirror extends Mixins(BaseMixin) { if (['cfg', 'conf'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(klipper_config)) else if (['gcode'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(gcode)) - // else if (['jinja2'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(jinja2)) else if (['json'].includes(this.fileExtension)) extensions.push(json()) else if (['css', 'scss', 'sass'].includes(this.fileExtension)) extensions.push(css()) diff --git a/src/plugins/StreamParserJinja2.ts b/src/plugins/StreamParserJinja2.ts deleted file mode 100644 index f515b3ba9..000000000 --- a/src/plugins/StreamParserJinja2.ts +++ /dev/null @@ -1,144 +0,0 @@ -/* -import {StringStream} from "@codemirror/language"; -let keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif", - "extends", "filter", "endfilter", "firstof", "for", - "endfor", "if", "endif", "ifchanged", "endifchanged", - "ifequal", "endifequal", "ifnotequal", - "endifnotequal", "in", "include", "load", "not", "now", "or", - "parsed", "regroup", "reversed", "spaceless", - "endspaceless", "ssi", "templatetag", "openblock", - "closeblock", "openvariable", "closevariable", - "openbrace", "closebrace", "opencomment", - "closecomment", "widthratio", "url", "with", "endwith", - "get_current_language", "trans", "endtrans", "noop", "blocktrans", - "endblocktrans", "get_available_languages", - "get_current_language_bidi", "plural"]; -const operator = /^[+\-*&%=<>!?|~^]/; -const sign = /^[:[({]/; -let atom = ["true", "false"]; -const number = /^(\d[+\-*!/])?\d+(\.\d+)?/; - -keywords = new RegExp("((" + keywords.join(")|(") + "))\\b"); -atom = new RegExp("((" + atom.join(")|(") + "))\\b"); - -export const jinja2 = { - token: function(stream: StringStream, state: StreamParserJinja2State): string { - let ch: string | void = stream.peek(); - - //Comment - if (state.incomment) { - if(!stream.skipTo("#}")) { - stream.skipToEnd(); - } else { - stream.eatWhile(/[#}]/); - state.incomment = false; - } - return "comment"; - //Tag - } else if (state.intag) { - //After operator - if(state.operator) { - state.operator = false; - if(stream.match(atom)) { - return "atom"; - } - if(stream.match(number)) { - return "number"; - } - } - //After sign - if(state.sign) { - state.sign = false; - if(stream.match(atom)) { - return "atom"; - } - if(stream.match(number)) { - return "number"; - } - } - - if(state.instring) { - if(ch == state.instring) { - state.instring = false; - } - stream.next(); - return "string"; - } else if(ch == "'" || ch == '"') { - state.instring = ch; - stream.next(); - return "string"; - } else if(stream.match(state.intag + "}") || stream.eat("-") && stream.match(state.intag + "}")) { - state.intag = false; - return "tag"; - } else if(stream.match(operator)) { - state.operator = true; - return "operator"; - } else if(stream.match(sign)) { - state.sign = true; - } else { - if(stream.eat(" ") || stream.sol()) { - if(stream.match(keywords)) { - return "keyword"; - } - if(stream.match(atom)) { - return "atom"; - } - if(stream.match(number)) { - return "number"; - } - if(stream.sol()) { - stream.next(); - } - } else { - stream.next(); - } - - } - return "variable"; - } else if (stream.eat("{")) { - if (stream.eat("#")) { - state.incomment = true; - if(!stream.skipTo("#}")) { - stream.skipToEnd(); - } else { - stream.eatWhile(/[#}]/); - state.incomment = false; - } - return "comment"; - //Open tag - // eslint-disable-next-line no-cond-assign - } else if (ch = stream.eat(/[{%]/)) { - //Cache close tag - state.intag = ch; - if(ch == "{") { - state.intag = "}"; - } - stream.eat("-"); - return "tag"; - } - } - stream.next(); - }, - startState: function(): StreamParserJinja2State { - return { - incomment: false, - intag: false, - operator: false, - sign: false, - instring: false - }; - }, - languageData: { - blockCommentStart: "{#", - blockCommentEnd: "#}" - } -} - -export interface StreamParserJinja2State { - incomment: boolean, - intag: string | boolean, - operator: boolean, - sign: boolean, - instring: boolean | string, -} -*/ diff --git a/src/plugins/StreamParserYaml.ts b/src/plugins/StreamParserYaml.ts deleted file mode 100644 index f1ad68653..000000000 --- a/src/plugins/StreamParserYaml.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { StringStream } from '@codemirror/language' - -const cons = ['true', 'false', 'on', 'off', 'yes', 'no'] -const keywordRegex = new RegExp('\\b((' + cons.join(')|(') + '))$', 'i') - -export const yaml = { - token: function (stream: StringStream, state: StreamParserYamlState): string | null { - const ch = stream.peek() - const esc = state.escaped - - state.escaped = false - /* comments */ - if (ch == '#' && (stream.pos == 0 || /\s/.test(stream.string.charAt(stream.pos - 1)))) { - stream.skipToEnd() - return 'comment' - } - - if (stream.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/)) return 'string' - - if (state.literal && stream.indentation() > state.keyCol) { - stream.skipToEnd() - return 'string' - } else if (state.literal) { - state.literal = false - } - if (stream.sol()) { - state.keyCol = 0 - state.pair = false - state.pairStart = false - /* document start */ - if (stream.match('---')) { - return 'def' - } - /* document end */ - if (stream.match('...')) { - return 'def' - } - /* array list item */ - if (stream.match(/^\s*-\s+/)) { - return 'meta' - } - } - - if (stream.match(/^\[[a-zA-Z]\s/)) { - window.console.log('keys', stream) - return 'number' - } - - /* inline pairs/lists */ - if (stream.match(/^(\{|\}|\[|\])/)) { - if (ch == '{') state.inlinePairs++ - else if (ch == '}') state.inlinePairs-- - else if (ch == '[') state.inlineList++ - else state.inlineList-- - return 'meta' - } - - /* list separator */ - if (state.inlineList > 0 && !esc && ch == ',') { - stream.next() - return 'meta' - } - /* pairs separator */ - if (state.inlinePairs > 0 && !esc && ch == ',') { - state.keyCol = 0 - state.pair = false - state.pairStart = false - stream.next() - return 'meta' - } - - /* start of value of a pair */ - if (state.pairStart) { - /* block literals */ - if (stream.match(/^\s*(\||>)\s*/)) { - state.literal = true - return 'meta' - } - /* references */ - if (stream.match(/^\s*(&|\*)[a-z0-9._-]+\b/i)) { - return 'variable' - } - /* numbers */ - if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9.,]+\s?$/)) { - return 'number' - } - if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9.,]+\s?(?=(,|}))/)) { - return 'number' - } - /* keywords */ - if (stream.match(keywordRegex)) { - return 'keyword' - } - } - - /* pairs (associative arrays) -> key */ - if ( - !state.pair && - stream.match(/^\s*(?:[,[\]{}&*!|>'"%@`][^\s'":]|[^,[\]{}#&*!|>'"%@`])[^#]*?(?=\s*:($|\s))/) - ) { - state.pair = true - state.keyCol = stream.indentation() - return 'atom' - } - if (state.pair && stream.match(/^:\s*/)) { - state.pairStart = true - return 'meta' - } - - /* nothing found, continue */ - state.pairStart = false - state.escaped = ch == '\\' - stream.next() - return null - }, - startState: function (): StreamParserYamlState { - return { - pair: false, - pairStart: false, - keyCol: 0, - inlinePairs: 0, - inlineList: 0, - literal: false, - escaped: false, - } - }, - languageData: { - commentTokens: { line: '#' }, - }, -} - -interface StreamParserYamlState { - pair: boolean - pairStart: boolean - keyCol: number - inlinePairs: number - inlineList: number - literal: boolean - escaped: boolean -} diff --git a/src/plugins/codemirrorTheme.ts b/src/plugins/codemirrorTheme.ts deleted file mode 100644 index 0cb6bc993..000000000 --- a/src/plugins/codemirrorTheme.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { EditorView } from '@codemirror/view' -import { Extension } from '@codemirror/state' -import { tags as t } from '@lezer/highlight' -import { HighlightStyle, syntaxHighlighting } from '@codemirror/language' - -const ui = { - background: '#1e1e1e', - foreground: '#d4d4d4', -} - -const mainsailEditor = EditorView.theme( - { - '&': { - color: '#d4d4d4', - backgroundColor: ui.background, - }, - '.cm-activeLine.cm-line': { - caretColor: '#d4d4d4 !important', - }, - - '.cm-gutters': { - backgroundColor: ui.background, - color: '#858585', - border: 'none', - }, - - '.cm-activeLine': { - background: 'rgba(43,47,61,0.5)', - }, - - '.cm-activeLineGutter': { - color: '#c6c6c6', - backgroundColor: 'rgba(33, 36, 49, 0.5)', - }, - - '.cm-selectionMatch': { - backgroundColor: '#add6ff26', - }, - - '.cm-button': { - 'font-family': 'Roboto,sans-serif', - 'font-weight': '500', - 'font-size': '.675rem', - 'letter-spacing': '0.0892857143em', - 'vertical-align': 'middle', - padding: '0.3em 1em', - 'border-radius': '4px', - 'border-width': '0', - color: 'var(--color-primary)', - 'background-color': 'var(--v-secondary-darken2)', - 'background-image': 'none!important', - 'text-transform': 'uppercase', - 'text-indent': '0.0892857143em', - 'text-aling': 'left', - }, - - '.cm-textfield:focus': { - 'border-color': 'var(--color-primary)!important', - }, - - '.cm-textfield:focus-visible': { - 'border-color': 'var(--color-primary)!important', - }, - - '.cm-textfield::placeholder': { - 'text-transform': 'uppercase', - }, - '.cm-panel.cm-search label': { - 'font-weight': '500', - 'font-family': 'Roboto,sans-serif', - 'letter-spacing': '0.0892857143em', - 'text-transform': 'uppercase', - 'font-size': '12px', - 'white-space': 'pre', - color: 'var(--v-primary-base)', - }, - - '.cm-panel.cm-search [name=close]': { - 'font-family': 'Roboto,sans-serif', - 'text-transform': 'uppercase', - 'font-size': '200%', - 'white-space': 'pre', - color: 'var(--color-primary)', - 'padding-right': '5px', - 'padding-top': '5px', - }, - - '.cm-button:hover': { - 'background-color': 'var(--v-secondary-lighten1)', - 'background-image': 'none!important', - 'transition-duration': '0.5s', - 'transition-timing-function': 'cubic-bezier(1.2,0,.2,1)', - }, - - '.cm-textfield': { - 'font-family': 'Roboto,sans-serif', - 'vertical-align': 'middle', - 'font-size': '.675rem', - border: '1px solid silver', - backgroundColor: ui.background, - padding: '.3em .1em', - 'padding-left': '0.6em', - 'border-radius': '0.2em', - }, - - '.cm-panels': { - 'background-color': 'var(--v-toolbar-base)', - }, - }, - { dark: true } -) - -const mainsailHighlightStyle = HighlightStyle.define([ - { tag: t.number, color: '#b5cea8' }, - { tag: [t.meta], color: '#d4d4d4' }, - { tag: [t.comment], color: '#6a9955' }, - { tag: t.atom, color: '#9cdcfe' }, - { tag: t.string, color: '#4ec9b0' }, - { tag: t.namespace, color: '#569cd6', fontWeight: 'bold' }, - { tag: t.className, color: '#c586c0' }, - { tag: t.name, color: '#e40', fontWeight: 'bold' }, - { tag: t.propertyName, color: '#e56735' }, - { tag: t.keyword, color: '#fcbe03' }, - { tag: t.updateOperator, color: '#b525d0' }, - { tag: t.operator, color: '#fc03fc' }, -]) - -/// Extension to enable the Mox theme (both the editor theme and -/// the highlight style). -export const mainsailTheme: Extension = [mainsailEditor, syntaxHighlighting(mainsailHighlightStyle)] From 74c4f51a4b19f1630c434e08ce11f898ef6f2e39 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Thu, 18 May 2023 16:22:59 +0200 Subject: [PATCH 22/22] refactor: change function to getter in Codemirror.vue to get the tabSize Signed-off-by: Stefan Dej --- src/components/inputs/Codemirror.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 02287acc5..9c54459ec 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -85,7 +85,7 @@ export default class Codemirror extends Mixins(BaseMixin) { EditorView.theme({}, { dark: true }), basicSetup, vscodeDark, - indentUnit.of(' '.repeat(this.getTabSize())), + indentUnit.of(' '.repeat(this.tabSize)), keymap.of([indentWithTab]), EditorView.updateListener.of((update) => { this.content = update.state?.doc.toString() @@ -107,7 +107,7 @@ export default class Codemirror extends Mixins(BaseMixin) { if (isVisible) this.cminstance?.focus() } - getTabSize() { + get tabSize() { return this.$store.state.gui.editor.tabSize || 2 } }