From ad9c49bb4ff4533ec9b2fc96b8927031e4056927 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sat, 20 May 2023 15:43:35 +0200 Subject: [PATCH 01/16] custom language for printer.cgf with code folding for the configuration blocks and with basic auto completion example --- .gitignore | 3 + package-lock.json | 29 ++ package.json | 1 + src/components/inputs/Codemirror.vue | 22 +- .../KlipperConfigLanguage/complete.ts | 79 ++++ .../languages/KlipperConfigLanguage/index.ts | 80 ++++ .../klipperConfig.grammar | 67 ++++ .../klipperConfigLang.js | 18 + .../klipperConfigLang.terms.js | 31 ++ .../languages/KlipperConfigLanguage/tokens.js | 84 +++++ src/plugins/languages/Python/highlight.js | 34 ++ src/plugins/languages/Python/index.ts | 19 + .../languages/Python/testPython.grammar | 349 ++++++++++++++++++ src/plugins/languages/Python/testPython.js | 28 ++ .../languages/Python/testPython.terms.js | 68 ++++ src/plugins/languages/Python/tokens.js | 149 ++++++++ src/plugins/languages/printLezerTree.ts | 246 ++++++++++++ 17 files changed, 1306 insertions(+), 1 deletion(-) create mode 100644 src/plugins/languages/KlipperConfigLanguage/complete.ts create mode 100644 src/plugins/languages/KlipperConfigLanguage/index.ts create mode 100644 src/plugins/languages/KlipperConfigLanguage/klipperConfig.grammar create mode 100644 src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.js create mode 100644 src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.terms.js create mode 100644 src/plugins/languages/KlipperConfigLanguage/tokens.js create mode 100644 src/plugins/languages/Python/highlight.js create mode 100644 src/plugins/languages/Python/index.ts create mode 100644 src/plugins/languages/Python/testPython.grammar create mode 100644 src/plugins/languages/Python/testPython.js create mode 100644 src/plugins/languages/Python/testPython.terms.js create mode 100644 src/plugins/languages/Python/tokens.js create mode 100644 src/plugins/languages/printLezerTree.ts diff --git a/.gitignore b/.gitignore index acffdf238..b7c9604ca 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ package-lock.json cypress/screenshots/ cypress/videos/ components.d.ts + +src/plugins/languages/dist +src/plugins/languages/KlipperConfigLanguage/*.d.ts diff --git a/package-lock.json b/package-lock.json index 83dc5cb1d..95449227b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "hls.js": "^1.3.3", "jmuxer": "^2.0.5", "js-sha256": "^0.9.0", + "lezer": "^0.13.5", "lodash.kebabcase": "^4.1.1", "lodash.throttle": "^4.1.1", "overlayscrollbars": "^1.13.1", @@ -7374,6 +7375,21 @@ "node": ">= 0.8.0" } }, + "node_modules/lezer": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/lezer/-/lezer-0.13.5.tgz", + "integrity": "sha512-cAiMQZGUo2BD8mpcz7Nv1TlKzWP7YIdIRrX41CiP5bk5t4GHxskOxWUx2iAOuHlz8dO+ivbuXr0J1bfHsWD+lQ==", + "deprecated": "This package has been replaced by @lezer/lr", + "dependencies": { + "lezer-tree": "^0.13.2" + } + }, + "node_modules/lezer-tree": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/lezer-tree/-/lezer-tree-0.13.2.tgz", + "integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ==", + "deprecated": "This package has been replaced by @lezer/common" + }, "node_modules/listr2": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", @@ -15845,6 +15861,19 @@ "type-check": "~0.4.0" } }, + "lezer": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/lezer/-/lezer-0.13.5.tgz", + "integrity": "sha512-cAiMQZGUo2BD8mpcz7Nv1TlKzWP7YIdIRrX41CiP5bk5t4GHxskOxWUx2iAOuHlz8dO+ivbuXr0J1bfHsWD+lQ==", + "requires": { + "lezer-tree": "^0.13.2" + } + }, + "lezer-tree": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/lezer-tree/-/lezer-tree-0.13.2.tgz", + "integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ==" + }, "listr2": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", diff --git a/package.json b/package.json index 181eb4ea7..b4b1688d3 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "hls.js": "^1.3.3", "jmuxer": "^2.0.5", "js-sha256": "^0.9.0", + "lezer": "^0.13.5", "lodash.kebabcase": "^4.1.1", "lodash.throttle": "^4.1.1", "overlayscrollbars": "^1.13.1", diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 9c54459ec..150bc1d1d 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -19,7 +19,12 @@ import { gcode } from '@/plugins/StreamParserGcode' import { indentWithTab } from '@codemirror/commands' import { json } from '@codemirror/lang-json' import { css } from '@codemirror/lang-css' +import { klipperConfig } from '../../plugins/languages/KlipperConfigLanguage/index' import { indentUnit } from '@codemirror/language' +import { python } from '../../plugins/languages/Python/index' +import { logTree } from '../../plugins/languages/printLezerTree' + +import {syntaxTree} from "@codemirror/language" @Component export default class Codemirror extends Mixins(BaseMixin) { @@ -49,6 +54,20 @@ export default class Codemirror extends Mixins(BaseMixin) { if (newVal !== cm_value) { this.setCmValue(newVal) } + const state = this.cminstance.state + logTree( syntaxTree(state), state.doc.toString() ) + /* const state = this.cminstance.state + syntaxTree(state).iterate({ + enter: (node) => { + if (node.from >= 3600 && node.name != "BlockBody" && node.name != "Block") { + if (node.name === "BodyLine") { + console.log("-- " + state.doc.lineAt(node.from).text + " ----------------") + } else { + console.log(node.name + " (" + state.doc.sliceString(node.from, node.to)+ ")") + } + } + }} + ) */ } mounted(): void { @@ -95,9 +114,10 @@ export default class Codemirror extends Mixins(BaseMixin) { }), ] - if (['cfg', 'conf'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(klipper_config)) + if (['cfg', 'conf'].includes(this.fileExtension)) extensions.push(klipperConfig()) else if (['gcode'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(gcode)) else if (['json'].includes(this.fileExtension)) extensions.push(json()) + else if (['py'].includes(this.fileExtension)) extensions.push(python()) else if (['css', 'scss', 'sass'].includes(this.fileExtension)) extensions.push(css()) return extensions diff --git a/src/plugins/languages/KlipperConfigLanguage/complete.ts b/src/plugins/languages/KlipperConfigLanguage/complete.ts new file mode 100644 index 000000000..ef25f1801 --- /dev/null +++ b/src/plugins/languages/KlipperConfigLanguage/complete.ts @@ -0,0 +1,79 @@ +import { CompletionContext } from '@codemirror/autocomplete' +import { syntaxTree } from '@codemirror/language' +import { EditorState } from '@codemirror/state' +import { SyntaxNode } from '@lezer/common' + +const blockTypeOptions = ['mcu', 'printer', 'adxl345', 'resonance_tester', 'stepper_x'].map((tag) => ({ + label: tag, + type: 'namespace', +})) +const mcuParameterOptions = ['serial', 'baud', 'canbus_uuid', 'canbus_interface', 'restart_method'].map((tag) => ({ + label: tag + ': ', + type: 'keyword', +})) +const printerParameterOptions = ['kinematics', 'max_velocity', 'max_accel', 'max_z_velocity', 'max_z_accel'].map( + (tag) => ({ + label: tag + ': ', + type: 'keyword', + }) +) +const adxl345Options = ['cs_pin'].map((tag) => ({ + label: tag + ': ', + type: 'keyword', +})) + +export function klipperConfigCompletionSource(context: CompletionContext) { + const parent = syntaxTree(context.state).resolveInner(context.pos, -1) + if (!parent) return null + const tagBefore = getTagBefore(context.state, parent.from, context.pos) + + if (parent.type.name === 'Parameter') { + const typeNode = findTypeNode(parent) + if (!typeNode) return null + const blocktype = context.state.sliceDoc(typeNode.from, typeNode.to) + const options = getOptionsByBlockType(blocktype) + return { + from: tagBefore ? parent.from + tagBefore.index : context.pos, + options: options, + validFor: /^(\w*)?$/, + } + } + + if (parent.parent?.type.name === 'ConfigBlock') { + return { + from: tagBefore ? parent.from + tagBefore.index : context.pos, + options: blockTypeOptions, + validFor: /^(\w*)?$/, + } + } + + return null +} + +function findTypeNode(node: SyntaxNode | null) { + while (node) { + if (node.type.name === 'ConfigBlock') { + return node.firstChild + } + node = node.parent + } + return null +} + +function getTagBefore(state: EditorState, from: number, pos: number) { + const textBefore = state.sliceDoc(from, pos) + return /\w*$/.exec(textBefore) +} + +function getOptionsByBlockType(blocktype: string) { + switch (blocktype) { + case 'mcu': + return mcuParameterOptions + case 'printer': + return printerParameterOptions + case 'adxl345': + return adxl345Options + default: + return null + } +} diff --git a/src/plugins/languages/KlipperConfigLanguage/index.ts b/src/plugins/languages/KlipperConfigLanguage/index.ts new file mode 100644 index 000000000..31a9c49cc --- /dev/null +++ b/src/plugins/languages/KlipperConfigLanguage/index.ts @@ -0,0 +1,80 @@ +//@ts-ignore +import { parser } from './klipperConfigLang.js' +import { + LRLanguage, + LanguageSupport, + StreamLanguage, + foldNodeProp, + flatIndent, + continuedIndent, + indentNodeProp, +} from '@codemirror/language' +import { styleTags, tags as t } from '@lezer/highlight' +import { parseMixed } from '@lezer/common' +import { klipper_config } from '../../StreamParserKlipperConfig.js' +import {klipperConfigCompletionSource} from "./complete" + +const jinja2Parser = StreamLanguage.define(klipper_config).parser + +export const klipperConfigLang = LRLanguage.define({ + parser: parser.configure({ + props: [ + indentNodeProp.add({ + GcodeKeyword: continuedIndent(), + Jinja2: continuedIndent(), + Parameter: () => null, + }), + foldNodeProp.add({ + ConfigBlock(tree) { + let node = tree.firstChild + if (node == null) return null + while (node.type.name != 'Body') { + node = node.nextSibling + if (node == null) return null + } + return { from: node.from - 1, to: tree.to - 2 } + }, + }), + styleTags({ + ImportKeyword: t.keyword, + Import: t.keyword, + ConfigBlock: t.namespace, + BlockType: t.namespace, + + Parameter: t.keyword, + + Identifier: t.attributeName, + Comment: t.lineComment, + AutoGenerated: t.name, + Boolean: t.bool, + String: t.string, + Number: t.number, + Cords: t.number, + Pin: t.atom, + VirtualPin: t.atom, + FilePath: t.className, + Path: t.className, + File: t.className, + Jinja2: t.typeName, + }), + ], + wrap: parseMixed((node) => { + return node.name == 'Jinja2' ? { parser: jinja2Parser } : null + }), + }), + languageData: { + commentTokens: { line: '#' }, + indentOnInput: /^\s*(gcode:)$/, + }, +}) + +export function klipperConfig() { + return new LanguageSupport(klipperConfigLang, [ + klipperConfigLang.data.of({autocomplete: klipperConfigCompletionSource}), + ]) +} + +/* +to generate the parser run: +npx @lezer/generator klipperConfig.grammar -o klipperConfigLang.js + */ diff --git a/src/plugins/languages/KlipperConfigLanguage/klipperConfig.grammar b/src/plugins/languages/KlipperConfigLanguage/klipperConfig.grammar new file mode 100644 index 000000000..77bb71e50 --- /dev/null +++ b/src/plugins/languages/KlipperConfigLanguage/klipperConfig.grammar @@ -0,0 +1,67 @@ +@top Program { Import* ConfigBlock+ } + +@skip { Comment newline | AutoGenerated newline | space | BlankLine } +@skip {} { + BlankLine { + blankLineStart space? newline + } +} + +Import { "[" ImportKeyword (FilePath | File) "]" newline } +ConfigBlock {"[" BlockType Identifier? "]" newline Body } + +Body { Option+ } +Option { Parameter ":" Value | GcodeKeyword ":" Jinja2 } + +Value { valueBlock } +Jinja2 { valueBlock } + +valueBlock { content (newline | eof) | newline indent (content newline)+ (dedent | eof) } + +value { Pin | VirtualPin | Cords | Number | String | Boolean | FilePath | Path } +Number { number } +String { string } +Cords { number ("," number)+ } +VirtualPin { string ":" string } +Path { "/"? (string "/")+ string } +FilePath { Path "." string} +File {string "." string } + + + + +@tokens { + ImportKeyword{ "include" } + GcodeKeyword{ "gcode" } + Identifier { $[a-zA-Z0-9_.\-]+ } + Parameter { $[a-zA-Z_]+ } + + string { $[ a-zA-Z0-9_\-]+ } + jinja2 { $[ a-zA-Z0-9_.\-"'{}%=]+ } + number { "-"? $[0-9]+ ("." $[0-9]*)? } + Boolean { "True" | "False" } + Pin { ("^" | "~")? "!"? "P" $[A-Z] $[0-9]+ } + + BlockType { + "mcu" | "printer" | "extruder" | "adxl345" | "resonance_tester" | "stepper_x" | "stepper_y" | "stepper_z" | + "stepper_z1" | "z_tilt" | "heater_bed" | "probe" | "bed_mesh" | "screws_tilt_adjust" | "temperature_sensor" | + "fan" | "heater_fan" | "controller_fan" | "static_digital_output" | "tmc2209" | "tmc2208" | "homing_override" + } + + AutoGenerated { "#*#" ![\n\r]* } + Comment { "#" ![\n\r]* } + + space { $[ \t\f]+ } + + @precedence { space, jinja2, string} + @precedence { AutoGenerated, Comment } + @precedence { number, Pin, Boolean, ImportKeyword, string } + @precedence { GcodeKeyword, Parameter} +} + +@context trackIndent from "./tokens.js" +@external tokens indentation from "./tokens.js" { indent, dedent } +@external tokens newlines from "./tokens.js" { newline, blankLineStart, eof } + + +@detectDelim diff --git a/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.js b/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.js new file mode 100644 index 000000000..dc3bc190e --- /dev/null +++ b/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.js @@ -0,0 +1,18 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +import {LRParser} from "@lezer/lr" +import {indentation, newlines, trackIndent} from "./tokens.js" +export const parser = LRParser.deserialize({ + version: 14, + states: "+pO`Q!cOOPeO!cOOOpQ!cO'#CaOOQ!b'#Cu'#CuO`Q!cOOOOQ!b'#Cw'#CwQxQ!cOOP}O!cO'#C_P!VO!bO)C>xPOOO)C>x)C>xO![Q!dO,58{O!dQ!fO,59QOOQ!b-E6s-E6sOsQ!cO'#CfOOQ!b-E6u-E6uPOOO,58y,58yP!lO!bO,58yPOOO/'4d/'4dO!qQ!cO'#CvO!yQ!dO'#CdO#OQ!dO'#CdO#TQ!cO'#CcO#YQ!cO1G.gO#_Q!cO1G.lO#dQ!cO1G.lP#iQ!cO'#CaPOOO1G.e1G.eOOQ!b,59b,59bO#nQ!dO,59PO#sQ!cO,59OOOQ!b-E6t-E6tO$RQ!cO'#CvO$WQ!dO,59OO$]Q!dO,58}O$bQ!cO7+$RO$gQ!jO7+$WO$oQ!cO7+$WOOQ!b1G.k1G.kO$tQ!cO1G.jOOQ!b1G.i1G.iOOQ!b<P#R#S1S#T#U>Y#U#VFh#V#W!!Q#W#X1S#X#Y!1o#Y#Z!/^#Z#[!:X#[#]!@X#]#^#,z#^#a1S#a#b#5`#b#d1S#d#e#7t#e#f1S#f#g#>O#g#h#Lc#h#i%#R#i#n1S#n#o%P~$^Rw~XY$X[]$Xpq$X~$p_w~!T`zQXY$X[]$Xpq$grs%ouv%owx%o}!O&m!O!P%o!Q![&m!_!`%o!c!}&m#R#S&m#T#o&m#o#p%o#q#r%o`%t]!T`pq%ors%ouv%owx%o}!O%o!O!P%o!Q![%o!_!`%o!c!}%o#R#S%o#T#o%o#o#p%o#q#r%ob&t]!T`zQpq&mrs%ouv%owx%o}!O&m!O!P%o!Q![&m!_!`%o!c!}&m#R#S&m#T#o&m#o#p%o#q#r%oQ'pP!r!s'sQ'vP!c!}'yQ'|P!Q![(PQ(UPaQ!Q![(P~(^VP~OY(sZ](s^z(sz{)_{;'S(s;'S;=`)X<%lO(s~(xTP~OY(sZ](s^;'S(s;'S;=`)X<%lO(s~)[P;=`<%l(s~)dVP~OY(sZ](s^s(sst)yt;'S(s;'S;=`)X<%lO(s~*QTQ~P~OY)yZ])y^;'S)y;'S;=`*a<%lO)y~*dP;=`<%l)y~*lO!R~g*u][S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![-p!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%of+w][S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%od,w][S!T`pq%ors%ouv%owx%o}!O,p!O!P,p!Q![,p!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%og-{][S!T`!QRzQpq&mrs%ouv%owx%o}!O+n!O!P.t!Q![-p!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og.}][S!T`!QRpq%ors%ouv%owx%o}!O,p!O!P,p!Q![.t!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%oe0P]{P[S!T`pq%ors%ouv%owx%o}!O,p!O!P,p!Q![,p!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%o~0}Oy~~1SO}~n1_][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%on2c^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U3_#U#o1S#o#p%o#q#r%on3j_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a4i#a#o1S#o#p%o#q#r%on4t_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h5s#h#o1S#o#p%o#q#r%on6O_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y6}#Y#o1S#o#p%o#q#r%on7[][S!T`_WfQzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%on8`][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}9X#R#S1S#T#o1S#o#p%o#q#r%on9d][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![:]!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%of:h][S!T`aQzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![:]!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%on;l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#gPO|~Q>SQqr'm!r!s'so>e_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X?d#X#o1S#o#p%o#q#r%oo?o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#m@n#m#o1S#o#p%o#q#r%oo@y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#aAx#a#o1S#o#p%o#q#r%ooBT_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!T+n!T!UCS!U![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%ogC]_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!U+n!U!VD[!V![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ogDe_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!V+n!V!WEd!W![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ogEo]ZP[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ooFs_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YGr#Y#o1S#o#p%o#q#r%ooG}_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#XH|#X#o1S#o#p%o#q#r%ooIX][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#SJQ#T#o1S#o#p%o#q#r%ooJ]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#bK[#b#o1S#o#p%o#q#r%ooKg_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YLf#Y#o1S#o#p%o#q#r%ooLq_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#hMp#h#o1S#o#p%o#q#r%ooM{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#[1S#[#]Nz#]#o1S#o#p%o#q#r%oo! X]ZP[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo!!]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!#[#d#o1S#o#p%o#q#r%oo!#g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c!$f#c#o1S#o#p%o#q#r%oo!$q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!%p#i#o1S#o#p%o#q#r%oo!%{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!&z#g#o1S#o#p%o#q#r%oo!'V_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!(U#d#o1S#o#p%o#q#r%oo!(a_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a!)`#a#o1S#o#p%o#q#r%oo!)k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a!*j#a#o1S#o#p%o#q#r%oo!*u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!+t#Y#o1S#o#p%o#q#r%oo!,P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!-O#g#o1S#o#p%o#q#r%oo!-Z][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S!.S#T#o1S#o#p%o#q#r%oo!.__[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Y1S#Y#Z!/^#Z#o1S#o#p%o#q#r%oo!/i^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U!0e#U#o1S#o#p%o#q#r%oo!0p_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#cNz#c#o1S#o#p%o#q#r%oo!1z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#m!2y#m#o1S#o#p%o#q#r%oo!3U_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!4T#i#o1S#o#p%o#q#r%oo!4`_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!5_#g#o1S#o#p%o#q#r%oo!5j_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j!6i#j#o1S#o#p%o#q#r%oo!6t_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X!7s#X#o1S#o#p%o#q#r%oo!8O_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!8}#Y#o1S#o#p%o#q#r%oo!9Y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#gNz#g#o1S#o#p%o#q#r%on!:d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W!;c#W#o1S#o#p%o#q#r%on!;n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!S_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!?R#Y#o1S#o#p%o#q#r%on!?`][S!T`gW_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo!@da[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!Ai#Y#c1S#c#d!KY#d#o1S#o#p%o#q#r%oo!At^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U!Bp#U#o1S#o#p%o#q#r%oo!B{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!Cz#i#o1S#o#p%o#q#r%oo!DV_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!EU#Y#o1S#o#p%o#q#r%oo!Ea_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!F`#g#o1S#o#p%o#q#r%oo!Fk][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S!Gd#T#o1S#o#p%o#q#r%oo!Goa[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U1S#U#V!Ht#V#Y1S#Y#Z!/^#Z#o1S#o#p%o#q#r%oo!IP_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!JO#Y#o1S#o#p%o#q#r%oo!JZ_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#XNz#X#o1S#o#p%o#q#r%oo!Ke_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#b!Ld#b#o1S#o#p%o#q#r%oo!Lo_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^!Mn#^#o1S#o#p%o#q#r%oo!My_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c!Nx#c#o1S#o#p%o#q#r%oo# T_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Z1S#Z#[#!S#[#o1S#o#p%o#q#r%oo#!_][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S##W#T#o1S#o#p%o#q#r%oo##c_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d#$b#d#o1S#o#p%o#q#r%oo#$m_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#j1S#j#k#%l#k#o1S#o#p%o#q#r%oo#%w_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#&v#Y#o1S#o#p%o#q#r%oo#'R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#(Q#g#o1S#o#p%o#q#r%oo#(]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#)[#g#o1S#o#p%o#q#r%oo#)g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^#*f#^#o1S#o#p%o#q#r%oo#*q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X#+p#X#o1S#o#p%o#q#r%oo#+{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YNz#Y#o1S#o#p%o#q#r%oo#-V_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#.U#c#o1S#o#p%o#q#r%oo#.a_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#/`#W#o1S#o#p%o#q#r%oo#/k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a#0j#a#o1S#o#p%o#q#r%oo#0u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j#1t#j#o1S#o#p%o#q#r%oo#2P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X#3O#X#o1S#o#p%o#q#r%oo#3Z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#4Y#Y#o1S#o#p%o#q#r%oo#4g][S!T`_WUPzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo#5k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#6j#W#o1S#o#p%o#q#r%oo#6u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#jNz#j#o1S#o#p%o#q#r%oo#8P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#9O#g#o1S#o#p%o#q#r%oo#9Za[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^#:`#^#c1S#c#d#Z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#?Y#Y#o1S#o#p%o#q#r%oo#?e_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h#@d#h#o1S#o#p%o#q#r%oo#@o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d#An#d#o1S#o#p%o#q#r%oo#Ay_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#Bx#c#o1S#o#p%o#q#r%oo#CT^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U#DP#U#o1S#o#p%o#q#r%oo#D[_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#EZ#c#o1S#o#p%o#q#r%oo#Ef_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#Fe#W#o1S#o#p%o#q#r%oo#Fp_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#Go#Y#o1S#o#p%o#q#r%oo#Gz][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S#Hs#T#o1S#o#p%o#q#r%oo#IO_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i#I}#i#o1S#o#p%o#q#r%oo#JY_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#KX#Y#o1S#o#p%o#q#r%oo#Kd_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h#;j#h#o1S#o#p%o#q#r%oo#Lna[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#Ms#W#h1S#h#i$2z#i#o1S#o#p%o#q#r%oo#NO_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#N}#g#o1S#o#p%o#q#r%oo$ Y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y$!X#Y#o1S#o#p%o#q#r%oo$!d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#k1S#k#l$#c#l#o1S#o#p%o#q#r%oo$#n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h$$m#h#o1S#o#p%o#q#r%oo$$x][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$%q#T#o1S#o#p%o#q#r%oo$%|_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$&{#i#o1S#o#p%o#q#r%oo$'W_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$(V#^#o1S#o#p%o#q#r%oo$(b_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$)a#a#o1S#o#p%o#q#r%oo$)l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$*k#i#o1S#o#p%o#q#r%oo$*v][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$+o#T#o1S#o#p%o#q#r%oo$+z^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$,v#U#o1S#o#p%o#q#r%oo$-R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X$.Q#X#o1S#o#p%o#q#r%oo$.]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#^1S#^#_$/[#_#o1S#o#p%o#q#r%oo$/g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$0f#j#o1S#o#p%o#q#r%oo$0q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h$1p#h#o1S#o#p%o#q#r%oo$1{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#iNz#i#o1S#o#p%o#q#r%oo$3V`[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$4X#U#X1S#X#Y$Hj#Y#o1S#o#p%o#q#r%oo$4d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$5c#i#o1S#o#p%o#q#r%oo$5n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$6m#^#o1S#o#p%o#q#r%oo$6x_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W$7w#W#o1S#o#p%o#q#r%oo$8S][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$8{#T#o1S#o#p%o#q#r%oo$9W_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X$:V#X#o1S#o#p%o#q#r%oo$:b_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$;a#^#o1S#o#p%o#q#r%oo$;l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Z1S#Z#[$Q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$?P#i#o1S#o#p%o#q#r%oo$?[^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$@W#U#o1S#o#p%o#q#r%oo$@c_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$Ab#a#o1S#o#p%o#q#r%oo$Am][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$Bf#T#o1S#o#p%o#q#r%oo$Bq_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d$Cp#d#o1S#o#p%o#q#r%oo$C{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$Dz#j#o1S#o#p%o#q#r%oo$EV_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$FU#i#o1S#o#p%o#q#r%oo$Fa_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$G`#e#o1S#o#p%o#q#r%oo$Gk_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$1p#j#o1S#o#p%o#q#r%oo$Hu_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$It#e#o1S#o#p%o#q#r%oo$JP_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$KO#e#o1S#o#p%o#q#r%oo$KZ_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y$LY#Y#o1S#o#p%o#q#r%oo$Le_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g$Md#g#o1S#o#p%o#q#r%oo$Mo][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$Nh#T#o1S#o#p%o#q#r%oo$Ns`[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#mNz#m#nNz#n#o% u#o#p%o#q#r%oo%!S_ZP[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!R+n!R!SEd!S![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo%#^a[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%$c#Y#a1S#a#b%6f#b#o1S#o#p%o#q#r%oo%$n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#b%%m#b#o1S#o#p%o#q#r%oo%%x_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e%&w#e#o1S#o#p%o#q#r%oo%'S_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%(R#Y#o1S#o#p%o#q#r%oo%(^_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g%)]#g#o1S#o#p%o#q#r%oo%)h^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U%*d#U#o1S#o#p%o#q#r%oo%*o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i%+n#i#o1S#o#p%o#q#r%oo%+y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j%,x#j#o1S#o#p%o#q#r%oo%-T_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g%.S#g#o1S#o#p%o#q#r%oo%.__[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%/^#Y#o1S#o#p%o#q#r%oo%/i][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S%0b#T#o1S#o#p%o#q#r%oo%0m_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h%1l#h#o1S#o#p%o#q#r%oo%1w_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%2v#Y#o1S#o#p%o#q#r%oo%3R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c%4Q#c#o1S#o#p%o#q#r%oo%4]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h%5[#h#o1S#o#p%o#q#r%oo%5g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!8}#d#o1S#o#p%o#q#r%oo%6q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W%7p#W#o1S#o#p%o#q#r%oo%7{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!S+n!S!T%8z!T![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%og%9T_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!S+n!S!T%:S!T![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og%:]^[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!R%;X!R![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og%;b_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!Y+n!Y!ZEd!Z![Ed!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%oo%o#i#o1S#o#p%o#q#r%oo%>z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^%?y#^#o1S#o#p%o#q#r%oo%@U_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$1p#a#o1S#o#p%o#q#r%o", + tokenizers: [0, 1, 2, 3, 4, indentation, newlines], + topRules: {"Program":[0,4]}, + tokenPrec: 363 +}) diff --git a/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.terms.js b/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.terms.js new file mode 100644 index 000000000..f5900d068 --- /dev/null +++ b/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.terms.js @@ -0,0 +1,31 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +export const + indent = 33, + dedent = 34, + newline = 35, + blankLineStart = 36, + eof = 37, + Comment = 1, + AutoGenerated = 2, + BlankLine = 3, + Program = 4, + Import = 5, + ImportKeyword = 6, + FilePath = 7, + Path = 8, + File = 9, + ConfigBlock = 10, + BlockType = 11, + Identifier = 12, + Body = 13, + Option = 14, + Parameter = 15, + Value = 16, + Pin = 17, + VirtualPin = 18, + Cords = 19, + Number = 20, + String = 21, + Boolean = 22, + GcodeKeyword = 23, + Jinja2 = 24 diff --git a/src/plugins/languages/KlipperConfigLanguage/tokens.js b/src/plugins/languages/KlipperConfigLanguage/tokens.js new file mode 100644 index 000000000..72fdde9ad --- /dev/null +++ b/src/plugins/languages/KlipperConfigLanguage/tokens.js @@ -0,0 +1,84 @@ +/* ref: https://github.com/lezer-parser/python/blob/main/src/tokens.js */ +import { ExternalTokenizer, ContextTracker } from '@lezer/lr' + +import { newline as newlineToken, eof, blankLineStart, indent, dedent } from './klipperConfigLang.terms.js' + +const newline = 10, + carriageReturn = 13, + space = 32, + tab = 9 + +function isLineBreak(ch) { + return ch == newline || ch == carriageReturn +} + +export const newlines = new ExternalTokenizer( + (input, stack) => { + let prev + if (input.next < 0) { + input.acceptToken(eof) + } else if (((prev = input.peek(-1)) < 0 || isLineBreak(prev)) && stack.canShift(blankLineStart)) { + let spaces = 0 + while (input.next == space || input.next == tab) { + input.advance() + spaces++ + } + if (input.next == newline || input.next == carriageReturn) input.acceptToken(blankLineStart, -spaces) + } else if (isLineBreak(input.next)) { + input.acceptToken(newlineToken, 1) + } + }, + { contextual: true } +) + +export const indentation = new ExternalTokenizer((input, stack) => { + let cDepth = stack.context.depth + if (cDepth < 0) return + let prev = input.peek(-1), + depth + if (prev == newline || prev == carriageReturn) { + let depth = 0, + chars = 0 + for (;;) { + if (input.next == space) depth++ + else if (input.next == tab) depth += 8 - (depth % 8) + else break + input.advance() + chars++ + } + if (depth != cDepth && input.next != newline && input.next != carriageReturn) { + if (depth < cDepth) input.acceptToken(dedent, -chars) + else input.acceptToken(indent) + } + } +}) + +function IndentLevel(parent, depth) { + this.parent = parent + // -1 means this is not an actual indent level but a set of brackets + this.depth = depth + this.hash = (parent ? (parent.hash + parent.hash) << 8 : 0) + depth + (depth << 4) +} + +const topIndent = new IndentLevel(null, 0) + +function countIndent(space) { + let depth = 0 + for (let i = 0; i < space.length; i++) depth += space.charCodeAt(i) == tab ? 8 - (depth % 8) : 1 + return depth +} + +export const trackIndent = new ContextTracker({ + start: topIndent, + reduce(context) { + return context.depth < 0 ? context.parent : context + }, + shift(context, term, stack, input) { + if (term == indent) return new IndentLevel(context, countIndent(input.read(input.pos, stack.pos))) + if (term == dedent) return context.parent + return context + }, + hash(context) { + return context.hash + }, +}) diff --git a/src/plugins/languages/Python/highlight.js b/src/plugins/languages/Python/highlight.js new file mode 100644 index 000000000..65547d9c3 --- /dev/null +++ b/src/plugins/languages/Python/highlight.js @@ -0,0 +1,34 @@ +import {styleTags, tags as t} from "@lezer/highlight" + +export const pythonHighlighting = styleTags({ + "async \"*\" \"**\" FormatConversion FormatSpec": t.modifier, + "for while if elif else try except finally return raise break continue with pass assert await yield match case": t.controlKeyword, + "in not and or is del": t.operatorKeyword, + "from def class global nonlocal lambda": t.definitionKeyword, + import: t.moduleKeyword, + "with as print": t.keyword, + Boolean: t.bool, + None: t.null, + VariableName: t.variableName, + "CallExpression/VariableName": t.function(t.variableName), + "FunctionDefinition/VariableName": t.function(t.definition(t.variableName)), + "ClassDefinition/VariableName": t.definition(t.className), + PropertyName: t.propertyName, + "CallExpression/MemberExpression/PropertyName": t.function(t.propertyName), + Comment: t.lineComment, + Number: t.number, + String: t.string, + FormatString: t.special(t.string), + UpdateOp: t.updateOperator, + "ArithOp!": t.arithmeticOperator, + BitOp: t.bitwiseOperator, + CompareOp: t.compareOperator, + AssignOp: t.definitionOperator, + Ellipsis: t.punctuation, + At: t.meta, + "( )": t.paren, + "[ ]": t.squareBracket, + "{ }": t.brace, + ".": t.derefOperator, + ", ;": t.separator +}) diff --git a/src/plugins/languages/Python/index.ts b/src/plugins/languages/Python/index.ts new file mode 100644 index 000000000..4936d8528 --- /dev/null +++ b/src/plugins/languages/Python/index.ts @@ -0,0 +1,19 @@ +//@ts-ignore +import { parser } from './testPython.js' +import { LRLanguage, LanguageSupport } from '@codemirror/language' + +export const testPython = LRLanguage.define({ + parser: parser, + languageData: { + commentTokens: { line: '#' }, + }, +}) + +export function python() { + return new LanguageSupport(testPython) +} + +/* +to generate the parser run: +npx @lezer/generator testPython.grammar -o testPython.js + */ diff --git a/src/plugins/languages/Python/testPython.grammar b/src/plugins/languages/Python/testPython.grammar new file mode 100644 index 000000000..6b36406b9 --- /dev/null +++ b/src/plugins/languages/Python/testPython.grammar @@ -0,0 +1,349 @@ +@precedence { + cond, + trail, + power @right, + prefix, + times @left, + plus @left, + shift @left, + bitand @left, + xor @left, + bitor @left, + compare @left, + as @left, + and @left, + or @left +} + +@top Script { statement+ } + +@skip { space | newlineBracketed | Comment | blankLine } + +Decorator { At dottedName ArgList? newline } + +FunctionDefinition { + kw<"async">? kw<"def"> VariableName + ParamList + TypeDef { "->" test }? + Body +} + +ParamList { "(" commaSep? ")" } + +MatchStatement { + skw<"match"> "*"? expression MatchBody { ":" newline indent MatchClause+ (dedent | eof) } +} + +MatchClause { + skw<"case"> commaSep Guard { kw<"if"> expression }? Body +} + +pattern[@isGroup=Pattern] { + CapturePattern { VariableName } | + LiteralPattern | + AsPattern { pattern !as kw<"as"> VariableName } | + OrPattern { pattern (!or LogicOp{"|"} pattern)+ } | + AttributePattern | + SequencePattern | + MappingPattern | + StarPattern { "*" !prefix pattern } | + ClassPattern { (VariableName | AttributePattern) PatternArgList } +} + +AttributePattern { VariableName ("." PropertyName)+ } + +LiteralPattern { + ArithOp{"-"}? Number (ArithOp{"+"|"-"} Number)? | + String | + kw<"None"> | + @specialize[@name=Boolean] +} + +PatternArgList { "(" commaSep "]" | "(" commaSep ")" } + +MappingPattern { "{" commaSep<"**" pattern | (VariableName | LiteralPattern) ":" pattern> "}" } + +ClassDefinition { kw<"class"> VariableName ArgList? Body } + +param { VariableName TypeDef? (AssignOp{"="} test)? | "*" VariableName? | "**" VariableName | "/" } + +TypeDef { ":" test } + +statement[@isGroup=Statement] { simpleStatement | compoundStatement } + +simpleStatement { + smallStatement (newline | eof) | + StatementGroup { smallStatement (";" smallStatement?)+ (newline | eof) } +} + +smallStatement { + AssignStatement { expressions (TypeDef? (AssignOp{"="} (YieldExpression | expressions))+ | TypeDef) } | + UpdateStatement { expressions UpdateOp (YieldExpression | commaSep) } | + ExpressionStatement { expressions } | + DeleteStatement { kw<"del"> commaSep } | + PassStatement { kw<"pass"> } | + BreakStatement { kw<"break"> } | + ContinueStatement { kw<"continue"> } | + ReturnStatement { kw<"return"> commaSep? } | + YieldStatement { yield } | + PrintStatement { printKeyword test } | + RaiseStatement { kw<"raise"> (test (kw<"from"> test | ("," test ("," test)?))?)? } | + ImportStatement | + ScopeStatement { (kw<"global"> | kw<"nonlocal">) commaSep } | + AssertStatement { kw<"assert"> commaSep } +} + +expressions { commaSep<"*" expression | test> } + +ImportStatement { + kw<"import"> dottedName (kw<"as"> VariableName)? | + kw<"from"> (("." | "...")+ dottedName? | dottedName) kw<"import"> ("*" | importList | importedNames) +} +importedNames { commaSep VariableName> } +importList[@export] { "(" importedNames ")" } + +commaSep { expr ("," expr)* ","? } + +compoundStatement { + IfStatement | + WhileStatement { kw<"while"> testNamed Body elseClause? } | + ForStatement { kw<"async">? kw<"for"> commaSep<"*"? expression> kw<"in"> commaSep Body elseClause? } | + TryStatement | + WithStatement { kw<"async">? kw<"with"> commaSep VariableName)?> Body } | + FunctionDefinition | + ClassDefinition | + DecoratedStatement { Decorator+ (ClassDefinition | FunctionDefinition) } | + MatchStatement +} + +elseClause { kw<"else"> Body } + +IfStatement { + kw<"if"> testNamed Body + (kw<"elif"> testNamed? Body)* + elseClause? +} + +TryStatement { + kw<"try"> Body + (kw<"except"> (test ((kw<"as"> | ",") VariableName)?)? Body)* + elseClause? + (kw<"finally"> Body)? +} + +Body { ":" (simpleStatement | newline indent statement+ (dedent | eof)) } + +lambdaParam { VariableName (AssignOp{"="} test)? | "*" VariableName? | "**" VariableName } + +lambdaParams[@name="ParamList"] { (lambdaParam ("," lambdaParam)*)? } + +test { + testInner | + ConditionalExpression { testInner !cond kw<"if"> testInner kw<"else"> test } | + LambdaExpression { kw<"lambda"> lambdaParams ":" test } +} + +testNoCond { + testInner | + LambdaExpression { kw<"lambda"> lambdaParams ":" testNoCond } +} + +testNamed { + test | NamedExpression { test AssignOp{":="} test } +} + +testInner { binaryTest | unaryTest | expression } + +binaryTest[@name="BinaryExpression"] { + testInner !or kw<"or"> testInner | + testInner !and kw<"and"> testInner | + testInner !compare (CompareOp | kw<"in"> | kw<"not"> kw<"in"> | kw<"is"> kw<"not">?) testInner +} + +unaryTest[@name="UnaryExpression"] { kw<"not"> testInner } + +expression[@isGroup=Expression] { + BinaryExpression | + UnaryExpression { !prefix (ArithOp{"+" | "-"} | BitOp{"~"}) expression } | + AwaitExpression { kw<"await"> expression } | + ParenthesizedExpression | + TupleExpression | + ComprehensionExpression | + ArrayExpression | + ArrayComprehensionExpression | + DictionaryExpression | + DictionaryComprehensionExpression | + SetExpression | + SetComprehensionExpression | + CallExpression { expression !trail ArgList } | + MemberExpression { expression !trail (subscript | "." PropertyName) } | + VariableName | + Number | + String | FormatString | + ContinuedString { (String | FormatString) (String | FormatString)+ } | + "..." | + kw<"None"> | + @specialize[@name=Boolean] +} + +subscript[@export] { + "[" commaSep "]" +} + +ParenthesizedExpression { "(" (testNamed | "*" expression | YieldExpression) ")" } + +TupleExpression { "(" ((testNamed | "*" expression) (("," (testNamed | "*" expression))+ ","? | ","))? ")" } +ComprehensionExpression { "(" (testNamed | "*" expression) compFor ")" } + +ArrayExpression { "[" commaSep? "]" } +ArrayComprehensionExpression { "[" (testNamed | "*" expression) compFor "]" } + +DictionaryExpression { "{" commaSep? "}" } +DictionaryComprehensionExpression { "{" (test ":" test | "**" expression) compFor "}" } + +SetExpression { "{" commaSep "}" } +SetComprehensionExpression { "{" (test | "*" expression) compFor "}" } + +yield { kw<"yield"> (kw<"from"> test | commaSep) } + +YieldExpression { yield } + +BinaryExpression { + expression !bitor BitOp{"|"} expression | + expression !xor BitOp{"^"} expression | + expression !bitand BitOp{"&"} expression | + expression !shift BitOp{"<<" | ">>"} expression | + expression !plus ArithOp{"+" | "-"} expression | + expression !times ArithOp{"*" | "@" | "/" | "%" | "//"} expression | + expression !power ArithOp{"**"} expression +} + +ArgList { "(" commaSep? ")" } + +argument { test compFor? | VariableName AssignOp{"=" | ":="} test | "**" test | "*" test } + +compFor { + kw<"async">? kw<"for"> commaSep kw<"in"> testInner (compFor | compIf)? +} + +compIf { + kw<"if"> testNoCond (compFor | compIf)? +} + +// FIXME Is it possible to distinguish between VariableName and VariableDefinition? + +VariableName { identifier } + +PropertyName { word } + +dottedName { VariableName ("." VariableName)* } + +kw { @specialize[@name={term}] } + +skw { @extend[@name={term}] } + +@skip {} { + String { + shortString | + longStringStart<"'"> longString1Content* "'''" | + longStringStart<'"'> longString2Content* '"""' + } + + FormatString { + formatStringStart<"'"> (formatString1Content | FormatReplacement)* formatString1End | + formatStringStart<'"'> (formatString2Content | FormatReplacement)* formatString2End | + longFormatStringStart<"'"> (formatString1lContent | FormatReplacement)* formatString1lEnd | + longFormatStringStart<'"'> (formatString2lContent | FormatReplacement)* formatString2lEnd + } + + formatStringSpec { FormatSpec { ":" (formatStringSpecChars | FormatReplacement<"{">)* } "}" } + + blankLine { + blankLineStart space? Comment? newline + } +} + +FormatReplacement { start (YieldExpression | commaSep<"*"? test>) FormatConversion? (formatStringSpec | "}") } + +@context trackIndent from "./tokens.js" + +@external tokens legacyPrint from "./tokens.js" { printKeyword[@name="print"] } + +@external tokens indentation from "./tokens" { indent, dedent } + +@external tokens newlines from "./tokens" { newline, blankLineStart, newlineBracketed, eof } + +@external tokens formatString1 from "./tokens" { formatString1Content, formatString1Brace[@name="{"], formatString1End } +@external tokens formatString2 from "./tokens" { formatString2Content, formatString2Brace[@name="{"], formatString2End } +@external tokens formatString1l from "./tokens" { formatString1lContent, formatString1lBrace[@name="{"], formatString1lEnd } +@external tokens formatString2l from "./tokens" { formatString2lContent, formatString2lBrace[@name="{"], formatString2lEnd } + +@tokens { + CompareOp { "<" | ">" | $[<>=!] "=" | "<>" } + + UpdateOp { ($[+\-@%&|^] | "<<" | ">>" | "*" "*"? | "/" "/"?) "=" } + + @precedence { + longStringStart<"'">, longStringStart<'"'>, longFormatStringStart<"'">, longFormatStringStart<'"'>, + shortString, formatStringStart<"'">, formatStringStart<'"'>, + identifier + } + + identifierChar { @asciiLetter | $[_\u{a1}-\u{10ffff}] } + + word { identifierChar (@digit | identifierChar)* } + + identifier { word } + + stringPrefix { $[rRuUbB] | $[bB] $[rR] | $[rR] $[bR] } + + formatPrefix { $[fF] | $[fF] $[rR] | $[rR] $[fF] } + + shortString { stringPrefix? ("'" (!['\\\n\r] | "\\" _)* "'"? | '"' (!["\\\n\r] | "\\" _)* '"'?) } + + formatStringStart { formatPrefix quote } + + FormatConversion { "!" $[sra] } + + formatStringSpecChars { ![{}]+ } + + longStringStart { stringPrefix? quote quote quote } + + longString1Content { (!['\\] | "\\" _ | "'" longString1_2)+ } + longString1_2 { !['\\] | "\\" _ | "'" longString1_3 } + longString1_3 { !['\\] | "\\" _ } + + longString2Content { (!["\\] | "\\" _ | '"' longString2_2)+ } + longString2_2 { !["\\] | "\\" _ | '"' longString2_3 } + longString2_3 { !["\\] | "\\" _ } + + longFormatStringStart { formatPrefix quote quote quote } + + Number { + (@digit ("_" | @digit)* ("." @digit ("_" | @digit)*)? | "." @digit ("_" | @digit)*) + ($[eE] $[+\-]? @digit ("_" | @digit)*)? $[jJ]? | + "0" $[bB] $[_01]+ | + "0" $[oO] $[_0-7]+ | + "0" $[xX] $[_0-9a-fA-F]+ + } + + Comment { "#" ![\n\r]* } + + space { ($[ \t\f] | "\\" $[\n\r])+ } + + At { "@" } + + "..."[@name=Ellipsis] + + "("[@export=ParenL] ")" + "["[@export=BracketL] "]" + "{"[@export=BraceL] "}" + + "." "," ";" ":" "@" "*" "**" +} + +@external propSource pythonHighlighting from "./highlight" + +@detectDelim diff --git a/src/plugins/languages/Python/testPython.js b/src/plugins/languages/Python/testPython.js new file mode 100644 index 000000000..111099004 --- /dev/null +++ b/src/plugins/languages/Python/testPython.js @@ -0,0 +1,28 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +import {LRParser} from "@lezer/lr" +import {legacyPrint, trackIndent} from "./tokens.js" +import {indentation, newlines, formatString1, formatString2, formatString1l, formatString2l} from "./tokens" +import {pythonHighlighting} from "./highlight" +const spec_identifier = {__proto__:null,await:48, or:58, and:60, in:64, not:66, is:68, if:74, else:76, lambda:80, yield:98, from:100, async:106, for:108, None:168, True:170, False:170, del:184, pass:188, break:192, continue:196, return:200, raise:208, import:212, as:214, global:218, nonlocal:220, assert:224, elif:234, while:238, try:244, except:246, finally:248, with:252, def:256, class:266, match:277, case:283} +export const parser = LRParser.deserialize({ + version: 14, + states: "#!OO`Q#yOOP$_OSOOO%hQ&nO'#H^OOQS'#Cq'#CqOOQS'#Cr'#CrO'WQ#xO'#CpO(yQ&nO'#H]OOQS'#H^'#H^OOQS'#DW'#DWOOQS'#H]'#H]O)gQ#xO'#DaO)zQ#xO'#DhO*[Q#xO'#DlOOQS'#Dw'#DwO*oO,UO'#DwO*wO7[O'#DwO+POWO'#DxO+[O`O'#DxO+gOpO'#DxO+rO!bO'#DxO-tQ&nO'#G}OOQS'#G}'#G}O'WQ#xO'#G|O/WQ&nO'#G|OOQS'#Ee'#EeO/oQ#xO'#EfOOQS'#G{'#G{O/yQ#xO'#GzOOQV'#Gz'#GzO0UQ#xO'#FXOOQS'#G`'#G`O0ZQ#xO'#FWOOQV'#IS'#ISOOQV'#Gy'#GyOOQV'#Fp'#FpQ`Q#yOOO'WQ#xO'#CsO0iQ#xO'#DPO0pQ#xO'#DTO1OQ#xO'#HbO1`Q&nO'#EYO'WQ#xO'#EZOOQS'#E]'#E]OOQS'#E_'#E_OOQS'#Ea'#EaO1tQ#xO'#EcO2[Q#xO'#EgO0UQ#xO'#EiO2oQ&nO'#EiO0UQ#xO'#ElO/oQ#xO'#EoO/oQ#xO'#EsO/oQ#xO'#EvO2zQ#xO'#ExO3RQ#xO'#E}O3^Q#xO'#EyO/oQ#xO'#E}O0UQ#xO'#FPO0UQ#xO'#FUO3cQ#xO'#FZP3jO#xO'#GxPOOO)CBl)CBlOOQS'#Cg'#CgOOQS'#Ch'#ChOOQS'#Ci'#CiOOQS'#Cj'#CjOOQS'#Ck'#CkOOQS'#Cl'#ClOOQS'#Cn'#CnO'WQ#xO,59QO'WQ#xO,59QO'WQ#xO,59QO'WQ#xO,59QO'WQ#xO,59QO'WQ#xO,59QO3uQ#xO'#DqOOQS,5:[,5:[O4YQ#xO'#HlOOQS,5:_,5:_O4gQMlO,5:_O4lQ&nO,59[O0iQ#xO,59dO0iQ#xO,59dO0iQ#xO,59dO7[Q#xO,59dO7aQ#xO,59dO7hQ#xO,59lO7oQ#xO'#H]O8uQ#xO'#H[OOQS'#H['#H[OOQS'#D^'#D^O9^Q#xO,59cO'WQ#xO,59cO9lQ#xO,59cOOQS,59{,59{O9qQ#xO,5:TO'WQ#xO,5:TOOQS,5:S,5:SO:PQ#xO,5:SO:UQ#xO,5:ZO'WQ#xO,5:ZO'WQ#xO,5:XOOQS,5:W,5:WO:gQ#xO,5:WO:lQ#xO,5:YOOOO'#Fx'#FxO:qO,UO,5:cOOQS,5:c,5:cOOOO'#Fy'#FyO:yO7[O,5:cO;RQ#xO'#DyOOOW'#Fz'#FzO;cOWO,5:dOOQS,5:d,5:dO;RQ#xO'#D}OOO`'#F}'#F}O;nO`O,5:dO;RQ#xO'#EOOOOp'#GO'#GOO;yOpO,5:dO;RQ#xO'#EPOOO!b'#GP'#GPOWOOQS'#Du'#DuOOQS1G/y1G/yOOQS1G/O1G/OO!-ZQ&nO1G/OO!-bQ&nO1G/OO0iQ#xO1G/OO!-}Q#xO1G/WOOQS'#D]'#D]O/oQ#xO,59vOOQS1G.}1G.}O!.UQ#xO1G/gO!.fQ#xO1G/gO!.nQ#xO1G/hO'WQ#xO'#HdO!.sQ#xO'#HdO!.xQ&nO1G.}O!/YQ#xO,59kO!0`Q#xO,5>SO!0pQ#xO,5>SO!0xQ#xO1G/oO!0}Q&nO1G/oOOQS1G/n1G/nO!1_Q#xO,5=}O!2UQ#xO,5=}O/oQ#xO1G/sO!2sQ#xO1G/uO!2xQ&nO1G/uO!3YQ&nO1G/sOOQS1G/r1G/rOOQS1G/t1G/tOOOO-E9v-E9vOOQS1G/}1G/}OOOO-E9w-E9wO!3jQ#xO'#HwO/oQ#xO'#HwO!3xQ#xO,5:eOOOW-E9x-E9xOOQS1G0O1G0OO!4TQ#xO,5:iOOO`-E9{-E9{O!4`Q#xO,5:jOOOp-E9|-E9|O!4kQ#xO,5:kOOO!b-E9}-E9}OOQS-E:O-E:OO!4vQ!LUO1G3SO!5gQ&nO1G3SO'WQ#xO,5jOOQS1G1_1G1_O!6gQ#xO1G1_OOQS'#DX'#DXO/oQ#xO,5=yOOQS,5=y,5=yO!6lQ#xO'#FqO!6wQ#xO,59qO!7PQ#xO1G/ZO!7ZQ&nO,5=}OOQS1G3h1G3hOOQS,5:p,5:pO!7zQ#xO'#G|OOQS,5PO!8{Q#xO,5>PO/oQ#xO1G0mO/oQ#xO1G0mO0UQ#xO1G0oOOQS-E:T-E:TO!9^Q#xO1G0oO!9iQ#xO1G0oO!9nQ#xO,5>mO!9|Q#xO,5>mO!:[Q#xO,5>iO!:rQ#xO,5>iO!;TQ#{O1G0yO!>cQ#{O1G0|O!AnQ#xO,5>oO!AxQ#xO,5>oO!BQQ&nO,5>oO/oQ#xO1G1OO!B[Q#xO1G1OO3^Q#xO1G1TO! RQ#xO1G1VOOQV,5;`,5;`O!BaQ#zO,5;`O!BfQ#{O1G1PO!EwQ#xO'#G]O3^Q#xO1G1PO3^Q#xO1G1PO!FUQ#xO,5>pO!FcQ#xO,5>pO0UQ#xO,5>pOOQV1G1T1G1TO!FkQ#xO'#FRO!F|QMlO1G1VOOQV1G1[1G1[O3^Q#xO1G1[O!GUQ#xO'#F]OOQV1G1a1G1aO! `Q&nO1G1aPOOO1G3O1G3OP!GZOSO1G3OOOQS,5>V,5>VOOQS'#Dr'#DrO/oQ#xO,5>VO!G`Q#xO,5>UO!GsQ#xO,5>UOOQS1G/w1G/wO!G{Q#xO,5>XO!H]Q#xO,5>XO!HeQ#xO,5>XO!HxQ#xO,5>XO!IYQ#xO,5>XOOQS1G3r1G3rOOQS7+$j7+$jO!7PQ#xO7+$rO!J{Q#xO1G/OO!KSQ#xO1G/OOOQS1G/b1G/bOOQS,5<_,5<_O'WQ#xO,5<_OOQS7+%R7+%RO!KZQ#xO7+%ROOQS-E9q-E9qOOQS7+%S7+%SO!KkQ#xO,5>OO'WQ#xO,5>OOOQS7+$i7+$iO!KpQ#xO7+%RO!KxQ#xO7+%SO!K}Q#xO1G3nOOQS7+%Z7+%ZO!L_Q#xO1G3nO!LgQ#xO7+%ZOOQS,5<^,5<^O'WQ#xO,5<^O!LlQ#xO1G3iOOQS-E9p-E9pO!McQ#xO7+%_OOQS7+%a7+%aO!MqQ#xO1G3iO!N`Q#xO7+%aO!NeQ#xO1G3oO!NuQ#xO1G3oO!N}Q#xO7+%_O# SQ#xO,5>cO# jQ#xO,5>cO# jQ#xO,5>cO# xO$ISO'#D{O#!TO#tO'#HxOOOW1G0P1G0PO#!YQ#xO1G0POOO`1G0T1G0TO#!bQ#xO1G0TOOOp1G0U1G0UO#!jQ#xO1G0UOOO!b1G0V1G0VO#!rQ#xO1G0VO#!zQ!LUO7+(nO##kQ&nO1G2XP#$UQ#xO'#GROOQS,5d,5>dOOOW7+%k7+%kOOO`7+%o7+%oOOOp7+%p7+%pOOO!b7+%q7+%qO#7{Q#xO1G3SO#8fQ#xO1G3SP'WQ#xO'#FtO/oQ#xO<lO#9YQ#xO,5>lO0UQ#xO,5>lO#9kQ#xO,5>kOOQS<rO#AdQ#xO,5>rOOQS,5>r,5>rO#AoQ#xO,5>qO#BQQ#xO,5>qOOQS1G1X1G1XOOQS,5;o,5;oO#BYQ#xO1G1cP#B_Q#xO'#FvO#BoQ#xO1G1}O#CSQ#xO1G1}O#CdQ#xO1G1}P#CoQ#xO'#FwO#C|Q#xO7+)_O#D^Q#xO7+)_O#D^Q#xO7+)_O#DfQ#xO7+)_O#DvQ#xO7+)UO7hQ#xO7+)UOOQSAN>XAN>XO#EaQ#xO<eAN>eO/oQ#xO1G1{O#EqQ&nO1G1{P#E{Q#xO'#FuOOQS1G2R1G2RP#FYQ#xO'#F{O#FgQ#xO7+)iO#F}Q#xO,5:hOOOO-E9z-E9zO#GYQ#xO7+(nOOQSAN?_AN?_O#GsQ#xO,5QOOQSANB[ANB[OOOO7+%n7+%nOOQS7+'x7+'xO$'{Q#xO<tO$*qQ#xO,5>tO0UQ#xO,5vO#MRQ#xO,5>vOOQS1G1o1G1oO$.iQ&nO,5wO$.wQ#xO,5>wOOQS1G1r1G1rOOQS7+'R7+'RP#MRQ#xO'#GfO$/PQ#xO1G4bO$/ZQ#xO1G4bO$/cQ#xO1G4bOOQS7+%V7+%VO$/qQ#xO1G1sO$0PQ&nO'#F`O$0WQ#xO,5=POOQS,5=P,5=PO$0fQ#xO1G4cOOQS-E:c-E:cO#MRQ#xO,5=OO$0mQ#xO,5=OO$0rQ#xO7+)|OOQS-E:b-E:bO$0|Q#xO7+)|O#MRQ#xO,5e>hPP'Z'ZPP?QPP'Z'ZPP'Z'Z'Z'Z'Z?U?{'ZP@OP@UD]GyPG}HZH_HcHg'ZPPPHkHq'RP'R'RP'RP'RP'RP'RP'R'R'RP'RPP'RPP'RPHwPIOIUPIOPIOIOPPPIOPKTPK^KdKjKTPIOKpPIOPKwK}PLRLgMUMoLRLRMuNSLRLRLRLRNhNnNqNvNy! T! Z! g! y!!P!!Z!!a!!}!#T!#Z!#a!#k!#q!#w!#}!$T!$Z!$m!$w!$}!%T!%Z!%e!%k!%q!%w!&R!&X!&c!&i!&r!&x!'X!'a!'k!'rPPPPPPPPPPPPPPPPP!'x!'{!(R!([!(f!(qPPPPPPPPPPPP!-e!.y!2s!6TPP!6]!6o!6x!7n!7e!7w!7}!8Q!8T!8W!8`!9PPPPPPPPPP!9S!9cPPPP!:R!:_!:k!:q!:z!:}!;T!;Z!;a!;dP!;l!;u!x|}#@S}!O#AW!O!P#Ci!P!Q#N_!Q!R$!y!R![$&w![!]$1e!]!^$3s!^!_$4w!_!`$7c!`!a$8m!a!b%T!b!c$;U!c!d$W!e!h$W#V#Y$Q<%lO$Xc&m!b&eS&hW%k!TOX%TXY=|Y[%T[]=|]p%Tpq=|qr%Trs&Vsw%Twx/Xx#O%T#O#P?d#P#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T#s?i[&m!bOY%TYZ=|Z]%T]^=|^#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=P;=`<%l8^<%lO%T!q@hd&m!b&eS&hWOr%Trs&Vsw%Twx/Xx!_%T!_!`Av!`#O%T#O#P7o#P#T%T#T#UBz#U#f%T#f#gBz#g#hBz#h#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T!qBR]oR&m!b&eS&hWOr%Trs&Vsw%Twx/Xx#O%T#O#P7o#P#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T!qCV]!nR&m!b&eS&hWOr%Trs&Vsw%Twx/Xx#O%T#O#P7o#P#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T#cDXa&m!b&eS&csOYE^YZ%TZ]E^]^%T^rE^rs!)|swE^wxGpx#OE^#O#P!!u#P#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!)v<%lOE^#cEia&m!b&eS&hW&csOYE^YZ%TZ]E^]^%T^rE^rsFnswE^wxGpx#OE^#O#P!!u#P#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!)v<%lOE^#cFw]&m!b&eS&csOr%Trs'Vsw%Twx/Xx#O%T#O#P7o#P#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T#cGya&m!b&hW&csOYE^YZ%TZ]E^]^%T^rE^rsFnswE^wxIOx#OE^#O#P!!u#P#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!)v<%lOE^#cIXa&m!b&hW&csOYE^YZ%TZ]E^]^%T^rE^rsFnswE^wxJ^x#OE^#O#P!!u#P#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!)v<%lOE^#_Jg_&m!b&hW&csOYJ^YZ1XZ]J^]^1X^rJ^rsKfs#OJ^#O#PL`#P#oJ^#o#pL}#p#qJ^#q#rL}#r;'SJ^;'S;=`!!o<%lOJ^#_KmZ&m!b&csOr1Xrs2ys#O1X#O#P3q#P#o1X#o#p4`#p#q1X#q#r4`#r;'S1X;'S;=`7i<%lO1X#_LeW&m!bO#oJ^#o#pL}#p#qJ^#q#rL}#r;'SJ^;'S;=`! r;=`<%lL}<%lOJ^{MUZ&hW&csOYL}YZ4`Z]L}]^4`^rL}rsMws#OL}#O#PNc#P;'SL};'S;=`! l<%lOL}{M|V&csOr4`rs5ds#O4`#O#P5y#P;'S4`;'S;=`6t<%lO4`{NfRO;'SL};'S;=`No;=`OL}{Nv[&hW&csOYL}YZ4`Z]L}]^4`^rL}rsMws#OL}#O#PNc#P;'SL};'S;=`! l;=`<%lL}<%lOL}{! oP;=`<%lL}#_! y[&hW&csOYL}YZ4`Z]L}]^4`^rL}rsMws#OL}#O#PNc#P;'SL};'S;=`! l;=`<%lJ^<%lOL}#_!!rP;=`<%lJ^#c!!zW&m!bO#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!(q;=`<%l!#d<%lOE^!P!#m]&eS&hW&csOY!#dYZ8^Z]!#d]^8^^r!#drs!$fsw!#dwx!%Yx#O!#d#O#P!'Y#P;'S!#d;'S;=`!(k<%lO!#d!P!$mX&eS&csOr8^rs9rsw8^wx:dx#O8^#O#P;v#P;'S8^;'S;=`^s#O!=U#O#P!@j#P#o!=U#o#p!Ag#p#q!=U#q#r!Ag#r;'S!=U;'S;=`!FQ<%lO!=U#o!>e_U!T&m!bOY!=UYZ1XZ]!=U]^1X^r!=Urs!?ds#O!=U#O#P!@j#P#o!=U#o#p!Ag#p#q!=U#q#r!Ag#r;'S!=U;'S;=`!FQ<%lO!=U#o!?k_U!T&m!bOY!=UYZ1XZ]!=U]^1X^r!=Urs!3`s#O!=U#O#P!@j#P#o!=U#o#p!Ag#p#q!=U#q#r!Ag#r;'S!=U;'S;=`!FQ<%lO!=U#o!@q[U!T&m!bOY!=UYZ1XZ]!=U]^1X^#o!=U#o#p!Ag#p#q!=U#q#r!Ag#r;'S!=U;'S;=`!Ec;=`<%l4`<%lO!=U!]!AnZU!T&hWOY!AgYZ4`Z]!Ag]^4`^r!Agrs!Bas#O!Ag#O#P!DP#P;'S!Ag;'S;=`!E]<%lO!Ag!]!BfZU!TOY!AgYZ4`Z]!Ag]^4`^r!Agrs!CXs#O!Ag#O#P!DP#P;'S!Ag;'S;=`!E]<%lO!Ag!]!C^ZU!TOY!AgYZ4`Z]!Ag]^4`^r!Agrs!4Ys#O!Ag#O#P!DP#P;'S!Ag;'S;=`!E]<%lO!Ag!]!DUWU!TOY!AgYZ4`Z]!Ag]^4`^;'S!Ag;'S;=`!Dn;=`<%l4`<%lO!Ag!]!DsW&hWOr4`rs4zs#O4`#O#P5y#P;'S4`;'S;=`6t;=`<%l!Ag<%lO4`!]!E`P;=`<%l!Ag#o!EhW&hWOr4`rs4zs#O4`#O#P5y#P;'S4`;'S;=`6t;=`<%l!=U<%lO4`#o!FTP;=`<%l!=U#s!F_[U!T&m!bOY!+|YZ%TZ]!+|]^%T^#o!+|#o#p!GT#p#q!+|#q#r!GT#r;'S!+|;'S;=`!Mq;=`<%l8^<%lO!+|!a!G^]U!T&eS&hWOY!GTYZ8^Z]!GT]^8^^r!GTrs!HVsw!GTwx!JVx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!H^]U!T&eSOY!GTYZ8^Z]!GT]^8^^r!GTrs!IVsw!GTwx!JVx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!I^]U!T&eSOY!GTYZ8^Z]!GT]^8^^r!GTrs!5wsw!GTwx!JVx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!J^]U!T&hWOY!GTYZ8^Z]!GT]^8^^r!GTrs!HVsw!GTwx!KVx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!K^]U!T&hWOY!GTYZ8^Z]!GT]^8^^r!GTrs!HVsw!GTwx!Agx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!L[WU!TOY!GTYZ8^Z]!GT]^8^^;'S!GT;'S;=`!Lt;=`<%l8^<%lO!GT!a!L{Y&eS&hWOr8^rs9Qsw8^wx:dx#O8^#O#P;v#P;'S8^;'S;=`Q<%lO$TP;=`<%l$ei&m!b&eS&hW&b`%}sOr%Trs$@Ssw%Twx$C`x!Q%T!Q![$Q<%lO$Q<%lO$Q<%lO$Q<%lO$Q<%lO$ spec_identifier[value] || -1}], + tokenPrec: 7205 +}) diff --git a/src/plugins/languages/Python/testPython.terms.js b/src/plugins/languages/Python/testPython.terms.js new file mode 100644 index 000000000..9157cab1c --- /dev/null +++ b/src/plugins/languages/Python/testPython.terms.js @@ -0,0 +1,68 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +export const + printKeyword = 1, + indent = 196, + dedent = 197, + newline = 198, + blankLineStart = 199, + newlineBracketed = 200, + eof = 201, + formatString1Content = 202, + formatString1Brace = 2, + formatString1End = 203, + formatString2Content = 204, + formatString2Brace = 3, + formatString2End = 205, + formatString1lContent = 206, + formatString1lBrace = 4, + formatString1lEnd = 207, + formatString2lContent = 208, + formatString2lBrace = 5, + formatString2lEnd = 209, + Comment = 6, + Script = 7, + BinaryExpression = 10, + ParenL = 26, + ParenthesizedExpression = 27, + binaryTest = 28, + CompareOp = 31, + unaryTest = 35, + lambdaParams = 41, + VariableName = 42, + YieldExpression = 48, + TupleExpression = 51, + ComprehensionExpression = 52, + BracketL = 57, + ArrayExpression = 58, + ArrayComprehensionExpression = 59, + BraceL = 61, + DictionaryExpression = 62, + DictionaryComprehensionExpression = 63, + SetExpression = 64, + SetComprehensionExpression = 65, + ArgList = 67, + subscript = 246, + PropertyName = 71, + Number = 72, + String = 73, + FormatString = 74, + FormatConversion = 76, + TypeDef = 86, + UpdateOp = 89, + ImportStatement = 105, + importList = 265, + IfStatement = 115, + Body = 116, + TryStatement = 121, + FunctionDefinition = 127, + ParamList = 129, + ClassDefinition = 132, + Decorator = 135, + At = 136, + MatchStatement = 137, + MatchClause = 140, + LiteralPattern = 143, + AttributePattern = 149, + SequencePattern = 150, + MappingPattern = 151, + PatternArgList = 154 diff --git a/src/plugins/languages/Python/tokens.js b/src/plugins/languages/Python/tokens.js new file mode 100644 index 000000000..72b8aee6e --- /dev/null +++ b/src/plugins/languages/Python/tokens.js @@ -0,0 +1,149 @@ +import {ExternalTokenizer, ContextTracker} from "@lezer/lr" +import { + newline as newlineToken, eof, newlineBracketed, blankLineStart, indent, dedent, printKeyword, + ParenthesizedExpression, TupleExpression, ComprehensionExpression, + PatternArgList, SequencePattern, MappingPattern, FormatString, + ArrayExpression, ArrayComprehensionExpression, ArgList, ParamList, importList, subscript, + DictionaryExpression, DictionaryComprehensionExpression, SetExpression, SetComprehensionExpression, + formatString1Content, formatString1Brace, formatString1End, + formatString2Content, formatString2Brace, formatString2End, + formatString1lContent, formatString1lBrace, formatString1lEnd, + formatString2lContent, formatString2lBrace, formatString2lEnd, + ParenL, BraceL, BracketL +} from "./testPython.terms" + +const newline = 10, carriageReturn = 13, space = 32, tab = 9, hash = 35, parenOpen = 40, dot = 46, + braceOpen = 123, singleQuote = 39, doubleQuote = 34 + +const bracketed = new Set([ + ParenthesizedExpression, TupleExpression, ComprehensionExpression, importList, ArgList, ParamList, + ArrayExpression, ArrayComprehensionExpression, subscript, + SetExpression, SetComprehensionExpression, FormatString, + DictionaryExpression, DictionaryComprehensionExpression, + SequencePattern, MappingPattern, PatternArgList +]) + +function isLineBreak(ch) { + return ch == newline || ch == carriageReturn +} + +export const newlines = new ExternalTokenizer((input, stack) => { + let prev + if (input.next < 0) { + input.acceptToken(eof) + } else if (stack.context.depth < 0) { + if (isLineBreak(input.next)) input.acceptToken(newlineBracketed, 1) + } else if (((prev = input.peek(-1)) < 0 || isLineBreak(prev)) && + stack.canShift(blankLineStart)) { + let spaces = 0 + while (input.next == space || input.next == tab) { input.advance(); spaces++ } + if (input.next == newline || input.next == carriageReturn || input.next == hash) + input.acceptToken(blankLineStart, -spaces) + } else if (isLineBreak(input.next)) { + input.acceptToken(newlineToken, 1) + } +}, {contextual: true}) + +export const indentation = new ExternalTokenizer((input, stack) => { + let cDepth = stack.context.depth + if (cDepth < 0) return + let prev = input.peek(-1), depth + if (prev == newline || prev == carriageReturn) { + let depth = 0, chars = 0 + for (;;) { + if (input.next == space) depth++ + else if (input.next == tab) depth += 8 - (depth % 8) + else break + input.advance() + chars++ + } + if (depth != cDepth && + input.next != newline && input.next != carriageReturn && input.next != hash) { + if (depth < cDepth) input.acceptToken(dedent, -chars) + else input.acceptToken(indent) + } + } +}) + +function IndentLevel(parent, depth) { + this.parent = parent + // -1 means this is not an actual indent level but a set of brackets + this.depth = depth + this.hash = (parent ? parent.hash + parent.hash << 8 : 0) + depth + (depth << 4) +} + +const topIndent = new IndentLevel(null, 0) + +function countIndent(space) { + let depth = 0 + for (let i = 0; i < space.length; i++) + depth += space.charCodeAt(i) == tab ? 8 - (depth % 8) : 1 + return depth +} + +export const trackIndent = new ContextTracker({ + start: topIndent, + reduce(context, term) { + return context.depth < 0 && bracketed.has(term) ? context.parent : context + }, + shift(context, term, stack, input) { + if (term == indent) return new IndentLevel(context, countIndent(input.read(input.pos, stack.pos))) + if (term == dedent) return context.parent + if (term == ParenL || term == BracketL || term == BraceL) return new IndentLevel(context, -1) + return context + }, + hash(context) { return context.hash } +}) + +export const legacyPrint = new ExternalTokenizer(input => { + for (let i = 0; i < 5; i++) { + if (input.next != "print".charCodeAt(i)) return + input.advance() + } + if (/\w/.test(String.fromCharCode(input.next))) return + for (let off = 0;; off++) { + let next = input.peek(off) + if (next == space || next == tab) continue + if (next != parenOpen && next != dot && next != newline && next != carriageReturn && next != hash) + input.acceptToken(printKeyword) + return + } +}) + +function formatString(quote, len, content, brace, end) { + return new ExternalTokenizer(input => { + let start = input.pos + for (;;) { + if (input.next < 0) { + break + } else if (input.next == braceOpen) { + if (input.peek(1) == braceOpen) { + input.advance(2) + } else { + if (input.pos == start) { + input.acceptToken(brace, 1) + return + } + break + } + } else if (input.next == "\\") { + input.advance() + if (input.next >= 0) input.advance() + } else if (input.next == quote && (len == 1 || input.peek(1) == quote && input.peek(2) == quote)) { + if (input.pos == start) { + input.acceptToken(end, len) + return + } + break + } else { + input.advance() + } + } + if (input.pos > start) input.acceptToken(content) + }) +} + +export const formatString1 = formatString(singleQuote, 1, formatString1Content, formatString1Brace, formatString1End) +export const formatString2 = formatString(doubleQuote, 1, formatString2Content, formatString2Brace, formatString2End) +export const formatString1l = formatString(singleQuote, 3, formatString1lContent, formatString1lBrace, formatString1lEnd) +export const formatString2l = formatString(doubleQuote, 3, formatString2lContent, formatString2lBrace, formatString2lEnd) diff --git a/src/plugins/languages/printLezerTree.ts b/src/plugins/languages/printLezerTree.ts new file mode 100644 index 000000000..ce1e60910 --- /dev/null +++ b/src/plugins/languages/printLezerTree.ts @@ -0,0 +1,246 @@ +// MIT License +// +// Copyright (c) 2021 Matthijs Steen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import { Text } from "@codemirror/state" +import { Input, NodeType, SyntaxNode, Tree, TreeCursor } from "@lezer/common" + +class StringInput implements Input { + constructor(private readonly input: string) {} + + get length() { + return this.input.length + } + + chunk(from: number): string { + return this.input.slice(from) + } + + lineChunks = false + + read(from: number, to: number): string { + return this.input.slice(from, to) + } +} + +export function sliceType(cursor: TreeCursor, input: Input, type: number): string | null { + if (cursor.type.id === type) { + const s = input.read(cursor.from, cursor.to) + cursor.nextSibling() + return s + } + return null +} + +export function isType(cursor: TreeCursor, type: number): boolean { + const cond = cursor.type.id === type + if (cond) cursor.nextSibling() + return cond +} + +export type CursorNode = { type: NodeType; from: number; to: number; isLeaf: boolean } + +function cursorNode({ type, from, to }: TreeCursor, isLeaf = false): CursorNode { + return { type, from, to, isLeaf } +} + +export type TreeTraversal = { + beforeEnter?: (cursor: TreeCursor) => void + onEnter: (node: CursorNode) => false | void + onLeave?: (node: CursorNode) => false | void +} + +type TreeTraversalOptions = { + from?: number + to?: number + includeParents?: boolean +} & TreeTraversal + +export function traverseTree( + cursor: TreeCursor | Tree | SyntaxNode, + { + from = -Infinity, + to = Infinity, + includeParents = false, + beforeEnter, + onEnter, + onLeave, + }: TreeTraversalOptions, +): void { + if (!(cursor instanceof TreeCursor)) cursor = cursor instanceof Tree ? cursor.cursor() : cursor.cursor + for (;;) { + let node = cursorNode(cursor) + let leave = false + if (node.from <= to && node.to >= from) { + const enter = !node.type.isAnonymous && (includeParents || (node.from >= from && node.to <= to)) + if (enter && beforeEnter) beforeEnter(cursor) + node.isLeaf = !cursor.firstChild() + if (enter) { + leave = true + if (onEnter(node) === false) return + } + if (!node.isLeaf) continue + } + for (;;) { + node = cursorNode(cursor, node.isLeaf) + if (leave && onLeave) if (onLeave(node) === false) return + leave = cursor.type.isAnonymous + node.isLeaf = false + if (cursor.nextSibling()) break + if (!cursor.parent()) return + leave = true + } + } +} + +function isChildOf(child: CursorNode, parent: CursorNode): boolean { + return ( + child.from >= parent.from && child.from <= parent.to && child.to <= parent.to && child.to >= parent.from + ) +} + +export function validatorTraversal( + input: Input | string, + { fullMatch = true }: { fullMatch?: boolean } = {}, +) { + if (typeof input === "string") input = new StringInput(input) + const state = { + valid: true, + parentNodes: [] as CursorNode[], + lastLeafTo: 0, + } + return { + state, + traversal: { + onEnter(node) { + state.valid = true + if (!node.isLeaf) state.parentNodes.unshift(node) + if (node.from > node.to || node.from < state.lastLeafTo) { + state.valid = false + } else if (node.isLeaf) { + if (state.parentNodes.length && !isChildOf(node, state.parentNodes[0])) state.valid = false + state.lastLeafTo = node.to + } else { + if (state.parentNodes.length) { + if (!isChildOf(node, state.parentNodes[0])) state.valid = false + } else if (fullMatch && (node.from !== 0 || node.to !== input.length)) { + state.valid = false + } + } + }, + onLeave(node) { + if (!node.isLeaf) state.parentNodes.shift() + }, + } as TreeTraversal, + } +} + +export function validateTree( + tree: TreeCursor | Tree | SyntaxNode, + input: Input | string, + options?: { fullMatch?: boolean }, +): boolean { + const { state, traversal } = validatorTraversal(input, options) + traverseTree(tree, traversal) + return state.valid +} + +enum Color { + Red = 31, + Green = 32, + Yellow = 33, +} + +function colorize(value: any, color: number): string { + return /* "\u001b[" + color + "m" + */String(value)/* + "\u001b[39m" */ +} + +type PrintTreeOptions = { from?: number; to?: number; start?: number; includeParents?: boolean } + +export function printTree( + cursor: TreeCursor | Tree | SyntaxNode, + input: Input | string, + { from, to, start = 0, includeParents }: PrintTreeOptions = {}, +): string { + const inp = typeof input === "string" ? new StringInput(input) : input + const text = Text.of(inp.read(0, inp.length).split("\n")) + const state = { + output: "", + prefixes: [] as string[], + hasNextSibling: false, + } + const validator = validatorTraversal(inp) + traverseTree(cursor, { + from, + to, + includeParents, + beforeEnter(cursor) { + state.hasNextSibling = cursor.nextSibling() && cursor.prevSibling() + }, + onEnter(node) { + validator.traversal.onEnter(node) + const isTop = state.output === "" + const hasPrefix = !isTop || node.from > 0 + if (hasPrefix) { + state.output += (!isTop ? "\n" : "") + state.prefixes.join("") + if (state.hasNextSibling) { + state.output += " ├─ " + state.prefixes.push(" │ ") + } else { + state.output += " └─ " + state.prefixes.push(" ") + } + } + const hasRange = node.from !== node.to + state.output += + (node.type.isError || !validator.state.valid ? colorize(node.type.name, Color.Red) : node.type.name) + + " " + + (hasRange + ? "[" + + colorize(locAt(text, start + node.from), Color.Yellow) + + ".." + + colorize(locAt(text, start + node.to), Color.Yellow) + + "]" + : colorize(locAt(text, start + node.from), Color.Yellow)) + if (hasRange && node.isLeaf) { + state.output += ": " + colorize(JSON.stringify(inp.read(node.from, node.to)), Color.Green) + } + }, + onLeave(node) { + validator.traversal.onLeave!(node) + state.prefixes.pop() + }, + }) + return state.output +} + +function locAt(text: Text, pos: number): string { + const line = text.lineAt(pos) + return line.number + ":" + (pos - line.from) +} + +export function logTree( + tree: TreeCursor | Tree | SyntaxNode, + input: string, + options?: PrintTreeOptions, +): void { + console.log(printTree(tree, input, options)) +} From 64701a210a0bfc4c1d2eb32ccacfbf07d59f663f Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sun, 21 May 2023 14:40:11 +0200 Subject: [PATCH 02/16] basic linting example --- src/components/inputs/Codemirror.vue | 2 ++ .../languages/KlipperConfigLanguage/lint.ts | 36 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/plugins/languages/KlipperConfigLanguage/lint.ts diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 150bc1d1d..3820228b5 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -20,6 +20,7 @@ import { indentWithTab } from '@codemirror/commands' import { json } from '@codemirror/lang-json' import { css } from '@codemirror/lang-css' import { klipperConfig } from '../../plugins/languages/KlipperConfigLanguage/index' +import { klipperConfigLint } from '../../plugins/languages/KlipperConfigLanguage/lint' import { indentUnit } from '@codemirror/language' import { python } from '../../plugins/languages/Python/index' import { logTree } from '../../plugins/languages/printLezerTree' @@ -105,6 +106,7 @@ export default class Codemirror extends Mixins(BaseMixin) { basicSetup, vscodeDark, indentUnit.of(' '.repeat(this.tabSize)), + klipperConfigLint, keymap.of([indentWithTab]), EditorView.updateListener.of((update) => { this.content = update.state?.doc.toString() diff --git a/src/plugins/languages/KlipperConfigLanguage/lint.ts b/src/plugins/languages/KlipperConfigLanguage/lint.ts new file mode 100644 index 000000000..9ccb6bcf2 --- /dev/null +++ b/src/plugins/languages/KlipperConfigLanguage/lint.ts @@ -0,0 +1,36 @@ +import { syntaxTree } from '@codemirror/language' +import { linter, Diagnostic } from '@codemirror/lint' + +export const klipperConfigLint = linter((view) => { + let diagnostics: Diagnostic[] = [] + syntaxTree(view.state) + .cursor() + .iterate((node) => { + if (node.name == 'Number') { + diagnostics.push({ + from: node.from, + to: node.to, + severity: 'warning', + message: 'Numbers are bad', + actions: [ + { + name: 'Remove', + apply(view, from, to) { + view.dispatch({ changes: { from, to } }) + }, + }, + ], + }) + } else { + if (node.type.isError) { + diagnostics.push({ + from: node.from, + to: node.to, + severity: 'error', + message: 'Syntax error', + }) + } + } + }) + return diagnostics +}) From 120717dfd8f4f4518e311e8a17b865e3026b2f08 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sun, 21 May 2023 21:43:14 +0200 Subject: [PATCH 03/16] new file structure --- package.json | 1 + src/components/inputs/Codemirror.vue | 8 ++--- .../KlipperConfigLanguage/lang}/complete.ts | 0 .../lang/klipperConfig.ts} | 33 +++---------------- .../KlipperConfigLanguage/lang}/lint.ts | 0 .../KlipperConfigLanguage/parser/highlight.js | 24 ++++++++++++++ .../parser}/klipperConfig.grammar | 1 + .../parser/klipperConfigParser.js} | 2 ++ .../parser/klipperConfigParser.terms.js} | 0 .../KlipperConfigLanguage/parser}/tokens.js | 2 +- .../Python/highlight.js | 0 .../Python/index.ts | 0 .../Python/testPython.grammar | 0 .../Python/testPython.js | 4 +-- .../Python/testPython.terms.js | 0 .../Python/tokens.js | 0 .../printLezerTree.ts | 0 17 files changed, 39 insertions(+), 36 deletions(-) rename src/plugins/{languages/KlipperConfigLanguage => CodemirrorLanguages/KlipperConfigLanguage/lang}/complete.ts (100%) rename src/plugins/{languages/KlipperConfigLanguage/index.ts => CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts} (57%) rename src/plugins/{languages/KlipperConfigLanguage => CodemirrorLanguages/KlipperConfigLanguage/lang}/lint.ts (100%) create mode 100644 src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js rename src/plugins/{languages/KlipperConfigLanguage => CodemirrorLanguages/KlipperConfigLanguage/parser}/klipperConfig.grammar (96%) rename src/plugins/{languages/KlipperConfigLanguage/klipperConfigLang.js => CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js} (99%) rename src/plugins/{languages/KlipperConfigLanguage/klipperConfigLang.terms.js => CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js} (100%) rename src/plugins/{languages/KlipperConfigLanguage => CodemirrorLanguages/KlipperConfigLanguage/parser}/tokens.js (97%) rename src/plugins/{languages => CodemirrorLanguages}/Python/highlight.js (100%) rename src/plugins/{languages => CodemirrorLanguages}/Python/index.ts (100%) rename src/plugins/{languages => CodemirrorLanguages}/Python/testPython.grammar (100%) rename src/plugins/{languages => CodemirrorLanguages}/Python/testPython.js (99%) rename src/plugins/{languages => CodemirrorLanguages}/Python/testPython.terms.js (100%) rename src/plugins/{languages => CodemirrorLanguages}/Python/tokens.js (100%) rename src/plugins/{languages => CodemirrorLanguages}/printLezerTree.ts (100%) diff --git a/package.json b/package.json index b4b1688d3..7de1c59f2 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "format": "npm run format:base -- --write", "format:base": "prettier .", "format:check": "npm run format:base -- --check", + "build-parser": "npx @lezer/generator src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar -o src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js", "lint": "eslint --ignore-path .gitignore src", "lint:fix": "npm run lint -- --fix", "build.zip": "cd ./dist && zip -r mainsail.zip ./ -x '**.DS_Store' ./ && cd ..", diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 3820228b5..e9c966f37 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -19,11 +19,11 @@ import { gcode } from '@/plugins/StreamParserGcode' import { indentWithTab } from '@codemirror/commands' import { json } from '@codemirror/lang-json' import { css } from '@codemirror/lang-css' -import { klipperConfig } from '../../plugins/languages/KlipperConfigLanguage/index' -import { klipperConfigLint } from '../../plugins/languages/KlipperConfigLanguage/lint' +import { klipperConfig } from '../../plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig' +import { klipperConfigLint } from '../../plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint' +import { python } from '../../plugins/CodemirrorLanguages/Python/index' +import { logTree } from '../../plugins/CodemirrorLanguages/printLezerTree' import { indentUnit } from '@codemirror/language' -import { python } from '../../plugins/languages/Python/index' -import { logTree } from '../../plugins/languages/printLezerTree' import {syntaxTree} from "@codemirror/language" diff --git a/src/plugins/languages/KlipperConfigLanguage/complete.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/complete.ts similarity index 100% rename from src/plugins/languages/KlipperConfigLanguage/complete.ts rename to src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/complete.ts diff --git a/src/plugins/languages/KlipperConfigLanguage/index.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts similarity index 57% rename from src/plugins/languages/KlipperConfigLanguage/index.ts rename to src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts index 31a9c49cc..82530a76d 100644 --- a/src/plugins/languages/KlipperConfigLanguage/index.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts @@ -1,18 +1,15 @@ -//@ts-ignore -import { parser } from './klipperConfigLang.js' +import { parser } from '../parser/klipperConfigParser.js' import { LRLanguage, LanguageSupport, StreamLanguage, foldNodeProp, - flatIndent, continuedIndent, indentNodeProp, } from '@codemirror/language' -import { styleTags, tags as t } from '@lezer/highlight' import { parseMixed } from '@lezer/common' -import { klipper_config } from '../../StreamParserKlipperConfig.js' -import {klipperConfigCompletionSource} from "./complete" +import { klipper_config } from '../../../StreamParserKlipperConfig' +import { klipperConfigCompletionSource } from './complete.js' const jinja2Parser = StreamLanguage.define(klipper_config).parser @@ -35,28 +32,6 @@ export const klipperConfigLang = LRLanguage.define({ return { from: node.from - 1, to: tree.to - 2 } }, }), - styleTags({ - ImportKeyword: t.keyword, - Import: t.keyword, - ConfigBlock: t.namespace, - BlockType: t.namespace, - - Parameter: t.keyword, - - Identifier: t.attributeName, - Comment: t.lineComment, - AutoGenerated: t.name, - Boolean: t.bool, - String: t.string, - Number: t.number, - Cords: t.number, - Pin: t.atom, - VirtualPin: t.atom, - FilePath: t.className, - Path: t.className, - File: t.className, - Jinja2: t.typeName, - }), ], wrap: parseMixed((node) => { return node.name == 'Jinja2' ? { parser: jinja2Parser } : null @@ -70,7 +45,7 @@ export const klipperConfigLang = LRLanguage.define({ export function klipperConfig() { return new LanguageSupport(klipperConfigLang, [ - klipperConfigLang.data.of({autocomplete: klipperConfigCompletionSource}), + klipperConfigLang.data.of({ autocomplete: klipperConfigCompletionSource }), ]) } diff --git a/src/plugins/languages/KlipperConfigLanguage/lint.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts similarity index 100% rename from src/plugins/languages/KlipperConfigLanguage/lint.ts rename to src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js new file mode 100644 index 000000000..56ad58062 --- /dev/null +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js @@ -0,0 +1,24 @@ +import { styleTags, tags as t } from '@lezer/highlight' + +export const klipperConfigHighlighting = styleTags({ + ImportKeyword: t.keyword, + Import: t.keyword, + ConfigBlock: t.namespace, + BlockType: t.namespace, + + Parameter: t.keyword, + + Identifier: t.attributeName, + Comment: t.lineComment, + AutoGenerated: t.name, + Boolean: t.bool, + String: t.string, + Number: t.number, + Cords: t.number, + Pin: t.atom, + VirtualPin: t.atom, + FilePath: t.className, + Path: t.className, + File: t.className, + Jinja2: t.typeName, +}) diff --git a/src/plugins/languages/KlipperConfigLanguage/klipperConfig.grammar b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar similarity index 96% rename from src/plugins/languages/KlipperConfigLanguage/klipperConfig.grammar rename to src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar index 77bb71e50..553eaca1b 100644 --- a/src/plugins/languages/KlipperConfigLanguage/klipperConfig.grammar +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar @@ -63,5 +63,6 @@ File {string "." string } @external tokens indentation from "./tokens.js" { indent, dedent } @external tokens newlines from "./tokens.js" { newline, blankLineStart, eof } +@external propSource klipperConfigHighlighting from "./highlight" @detectDelim diff --git a/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js similarity index 99% rename from src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.js rename to src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js index dc3bc190e..df9ed845b 100644 --- a/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js @@ -1,6 +1,7 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. import {LRParser} from "@lezer/lr" import {indentation, newlines, trackIndent} from "./tokens.js" +import {klipperConfigHighlighting} from "./highlight" export const parser = LRParser.deserialize({ version: 14, states: "+pO`Q!cOOPeO!cOOOpQ!cO'#CaOOQ!b'#Cu'#CuO`Q!cOOOOQ!b'#Cw'#CwQxQ!cOOP}O!cO'#C_P!VO!bO)C>xPOOO)C>x)C>xO![Q!dO,58{O!dQ!fO,59QOOQ!b-E6s-E6sOsQ!cO'#CfOOQ!b-E6u-E6uPOOO,58y,58yP!lO!bO,58yPOOO/'4d/'4dO!qQ!cO'#CvO!yQ!dO'#CdO#OQ!dO'#CdO#TQ!cO'#CcO#YQ!cO1G.gO#_Q!cO1G.lO#dQ!cO1G.lP#iQ!cO'#CaPOOO1G.e1G.eOOQ!b,59b,59bO#nQ!dO,59PO#sQ!cO,59OOOQ!b-E6t-E6tO$RQ!cO'#CvO$WQ!dO,59OO$]Q!dO,58}O$bQ!cO7+$RO$gQ!jO7+$WO$oQ!cO7+$WOOQ!b1G.k1G.kO$tQ!cO1G.jOOQ!b1G.i1G.iOOQ!b<P#R#S1S#T#U>Y#U#VFh#V#W!!Q#W#X1S#X#Y!1o#Y#Z!/^#Z#[!:X#[#]!@X#]#^#,z#^#a1S#a#b#5`#b#d1S#d#e#7t#e#f1S#f#g#>O#g#h#Lc#h#i%#R#i#n1S#n#o%P~$^Rw~XY$X[]$Xpq$X~$p_w~!T`zQXY$X[]$Xpq$grs%ouv%owx%o}!O&m!O!P%o!Q![&m!_!`%o!c!}&m#R#S&m#T#o&m#o#p%o#q#r%o`%t]!T`pq%ors%ouv%owx%o}!O%o!O!P%o!Q![%o!_!`%o!c!}%o#R#S%o#T#o%o#o#p%o#q#r%ob&t]!T`zQpq&mrs%ouv%owx%o}!O&m!O!P%o!Q![&m!_!`%o!c!}&m#R#S&m#T#o&m#o#p%o#q#r%oQ'pP!r!s'sQ'vP!c!}'yQ'|P!Q![(PQ(UPaQ!Q![(P~(^VP~OY(sZ](s^z(sz{)_{;'S(s;'S;=`)X<%lO(s~(xTP~OY(sZ](s^;'S(s;'S;=`)X<%lO(s~)[P;=`<%l(s~)dVP~OY(sZ](s^s(sst)yt;'S(s;'S;=`)X<%lO(s~*QTQ~P~OY)yZ])y^;'S)y;'S;=`*a<%lO)y~*dP;=`<%l)y~*lO!R~g*u][S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![-p!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%of+w][S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%od,w][S!T`pq%ors%ouv%owx%o}!O,p!O!P,p!Q![,p!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%og-{][S!T`!QRzQpq&mrs%ouv%owx%o}!O+n!O!P.t!Q![-p!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og.}][S!T`!QRpq%ors%ouv%owx%o}!O,p!O!P,p!Q![.t!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%oe0P]{P[S!T`pq%ors%ouv%owx%o}!O,p!O!P,p!Q![,p!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%o~0}Oy~~1SO}~n1_][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%on2c^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U3_#U#o1S#o#p%o#q#r%on3j_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a4i#a#o1S#o#p%o#q#r%on4t_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h5s#h#o1S#o#p%o#q#r%on6O_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y6}#Y#o1S#o#p%o#q#r%on7[][S!T`_WfQzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%on8`][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}9X#R#S1S#T#o1S#o#p%o#q#r%on9d][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![:]!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%of:h][S!T`aQzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![:]!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%on;l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#gPO|~Q>SQqr'm!r!s'so>e_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X?d#X#o1S#o#p%o#q#r%oo?o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#m@n#m#o1S#o#p%o#q#r%oo@y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#aAx#a#o1S#o#p%o#q#r%ooBT_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!T+n!T!UCS!U![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%ogC]_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!U+n!U!VD[!V![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ogDe_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!V+n!V!WEd!W![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ogEo]ZP[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ooFs_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YGr#Y#o1S#o#p%o#q#r%ooG}_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#XH|#X#o1S#o#p%o#q#r%ooIX][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#SJQ#T#o1S#o#p%o#q#r%ooJ]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#bK[#b#o1S#o#p%o#q#r%ooKg_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YLf#Y#o1S#o#p%o#q#r%ooLq_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#hMp#h#o1S#o#p%o#q#r%ooM{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#[1S#[#]Nz#]#o1S#o#p%o#q#r%oo! X]ZP[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo!!]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!#[#d#o1S#o#p%o#q#r%oo!#g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c!$f#c#o1S#o#p%o#q#r%oo!$q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!%p#i#o1S#o#p%o#q#r%oo!%{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!&z#g#o1S#o#p%o#q#r%oo!'V_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!(U#d#o1S#o#p%o#q#r%oo!(a_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a!)`#a#o1S#o#p%o#q#r%oo!)k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a!*j#a#o1S#o#p%o#q#r%oo!*u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!+t#Y#o1S#o#p%o#q#r%oo!,P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!-O#g#o1S#o#p%o#q#r%oo!-Z][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S!.S#T#o1S#o#p%o#q#r%oo!.__[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Y1S#Y#Z!/^#Z#o1S#o#p%o#q#r%oo!/i^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U!0e#U#o1S#o#p%o#q#r%oo!0p_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#cNz#c#o1S#o#p%o#q#r%oo!1z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#m!2y#m#o1S#o#p%o#q#r%oo!3U_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!4T#i#o1S#o#p%o#q#r%oo!4`_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!5_#g#o1S#o#p%o#q#r%oo!5j_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j!6i#j#o1S#o#p%o#q#r%oo!6t_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X!7s#X#o1S#o#p%o#q#r%oo!8O_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!8}#Y#o1S#o#p%o#q#r%oo!9Y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#gNz#g#o1S#o#p%o#q#r%on!:d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W!;c#W#o1S#o#p%o#q#r%on!;n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!S_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!?R#Y#o1S#o#p%o#q#r%on!?`][S!T`gW_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo!@da[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!Ai#Y#c1S#c#d!KY#d#o1S#o#p%o#q#r%oo!At^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U!Bp#U#o1S#o#p%o#q#r%oo!B{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!Cz#i#o1S#o#p%o#q#r%oo!DV_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!EU#Y#o1S#o#p%o#q#r%oo!Ea_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!F`#g#o1S#o#p%o#q#r%oo!Fk][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S!Gd#T#o1S#o#p%o#q#r%oo!Goa[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U1S#U#V!Ht#V#Y1S#Y#Z!/^#Z#o1S#o#p%o#q#r%oo!IP_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!JO#Y#o1S#o#p%o#q#r%oo!JZ_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#XNz#X#o1S#o#p%o#q#r%oo!Ke_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#b!Ld#b#o1S#o#p%o#q#r%oo!Lo_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^!Mn#^#o1S#o#p%o#q#r%oo!My_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c!Nx#c#o1S#o#p%o#q#r%oo# T_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Z1S#Z#[#!S#[#o1S#o#p%o#q#r%oo#!_][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S##W#T#o1S#o#p%o#q#r%oo##c_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d#$b#d#o1S#o#p%o#q#r%oo#$m_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#j1S#j#k#%l#k#o1S#o#p%o#q#r%oo#%w_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#&v#Y#o1S#o#p%o#q#r%oo#'R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#(Q#g#o1S#o#p%o#q#r%oo#(]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#)[#g#o1S#o#p%o#q#r%oo#)g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^#*f#^#o1S#o#p%o#q#r%oo#*q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X#+p#X#o1S#o#p%o#q#r%oo#+{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YNz#Y#o1S#o#p%o#q#r%oo#-V_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#.U#c#o1S#o#p%o#q#r%oo#.a_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#/`#W#o1S#o#p%o#q#r%oo#/k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a#0j#a#o1S#o#p%o#q#r%oo#0u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j#1t#j#o1S#o#p%o#q#r%oo#2P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X#3O#X#o1S#o#p%o#q#r%oo#3Z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#4Y#Y#o1S#o#p%o#q#r%oo#4g][S!T`_WUPzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo#5k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#6j#W#o1S#o#p%o#q#r%oo#6u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#jNz#j#o1S#o#p%o#q#r%oo#8P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#9O#g#o1S#o#p%o#q#r%oo#9Za[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^#:`#^#c1S#c#d#Z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#?Y#Y#o1S#o#p%o#q#r%oo#?e_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h#@d#h#o1S#o#p%o#q#r%oo#@o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d#An#d#o1S#o#p%o#q#r%oo#Ay_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#Bx#c#o1S#o#p%o#q#r%oo#CT^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U#DP#U#o1S#o#p%o#q#r%oo#D[_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#EZ#c#o1S#o#p%o#q#r%oo#Ef_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#Fe#W#o1S#o#p%o#q#r%oo#Fp_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#Go#Y#o1S#o#p%o#q#r%oo#Gz][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S#Hs#T#o1S#o#p%o#q#r%oo#IO_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i#I}#i#o1S#o#p%o#q#r%oo#JY_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#KX#Y#o1S#o#p%o#q#r%oo#Kd_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h#;j#h#o1S#o#p%o#q#r%oo#Lna[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#Ms#W#h1S#h#i$2z#i#o1S#o#p%o#q#r%oo#NO_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#N}#g#o1S#o#p%o#q#r%oo$ Y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y$!X#Y#o1S#o#p%o#q#r%oo$!d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#k1S#k#l$#c#l#o1S#o#p%o#q#r%oo$#n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h$$m#h#o1S#o#p%o#q#r%oo$$x][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$%q#T#o1S#o#p%o#q#r%oo$%|_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$&{#i#o1S#o#p%o#q#r%oo$'W_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$(V#^#o1S#o#p%o#q#r%oo$(b_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$)a#a#o1S#o#p%o#q#r%oo$)l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$*k#i#o1S#o#p%o#q#r%oo$*v][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$+o#T#o1S#o#p%o#q#r%oo$+z^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$,v#U#o1S#o#p%o#q#r%oo$-R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X$.Q#X#o1S#o#p%o#q#r%oo$.]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#^1S#^#_$/[#_#o1S#o#p%o#q#r%oo$/g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$0f#j#o1S#o#p%o#q#r%oo$0q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h$1p#h#o1S#o#p%o#q#r%oo$1{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#iNz#i#o1S#o#p%o#q#r%oo$3V`[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$4X#U#X1S#X#Y$Hj#Y#o1S#o#p%o#q#r%oo$4d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$5c#i#o1S#o#p%o#q#r%oo$5n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$6m#^#o1S#o#p%o#q#r%oo$6x_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W$7w#W#o1S#o#p%o#q#r%oo$8S][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$8{#T#o1S#o#p%o#q#r%oo$9W_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X$:V#X#o1S#o#p%o#q#r%oo$:b_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$;a#^#o1S#o#p%o#q#r%oo$;l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Z1S#Z#[$Q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$?P#i#o1S#o#p%o#q#r%oo$?[^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$@W#U#o1S#o#p%o#q#r%oo$@c_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$Ab#a#o1S#o#p%o#q#r%oo$Am][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$Bf#T#o1S#o#p%o#q#r%oo$Bq_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d$Cp#d#o1S#o#p%o#q#r%oo$C{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$Dz#j#o1S#o#p%o#q#r%oo$EV_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$FU#i#o1S#o#p%o#q#r%oo$Fa_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$G`#e#o1S#o#p%o#q#r%oo$Gk_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$1p#j#o1S#o#p%o#q#r%oo$Hu_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$It#e#o1S#o#p%o#q#r%oo$JP_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$KO#e#o1S#o#p%o#q#r%oo$KZ_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y$LY#Y#o1S#o#p%o#q#r%oo$Le_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g$Md#g#o1S#o#p%o#q#r%oo$Mo][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$Nh#T#o1S#o#p%o#q#r%oo$Ns`[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#mNz#m#nNz#n#o% u#o#p%o#q#r%oo%!S_ZP[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!R+n!R!SEd!S![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo%#^a[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%$c#Y#a1S#a#b%6f#b#o1S#o#p%o#q#r%oo%$n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#b%%m#b#o1S#o#p%o#q#r%oo%%x_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e%&w#e#o1S#o#p%o#q#r%oo%'S_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%(R#Y#o1S#o#p%o#q#r%oo%(^_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g%)]#g#o1S#o#p%o#q#r%oo%)h^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U%*d#U#o1S#o#p%o#q#r%oo%*o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i%+n#i#o1S#o#p%o#q#r%oo%+y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j%,x#j#o1S#o#p%o#q#r%oo%-T_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g%.S#g#o1S#o#p%o#q#r%oo%.__[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%/^#Y#o1S#o#p%o#q#r%oo%/i][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S%0b#T#o1S#o#p%o#q#r%oo%0m_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h%1l#h#o1S#o#p%o#q#r%oo%1w_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%2v#Y#o1S#o#p%o#q#r%oo%3R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c%4Q#c#o1S#o#p%o#q#r%oo%4]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h%5[#h#o1S#o#p%o#q#r%oo%5g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!8}#d#o1S#o#p%o#q#r%oo%6q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W%7p#W#o1S#o#p%o#q#r%oo%7{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!S+n!S!T%8z!T![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%og%9T_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!S+n!S!T%:S!T![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og%:]^[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!R%;X!R![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og%;b_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!Y+n!Y!ZEd!Z![Ed!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%oo%o#i#o1S#o#p%o#q#r%oo%>z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^%?y#^#o1S#o#p%o#q#r%oo%@U_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$1p#a#o1S#o#p%o#q#r%o", diff --git a/src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.terms.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js similarity index 100% rename from src/plugins/languages/KlipperConfigLanguage/klipperConfigLang.terms.js rename to src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js diff --git a/src/plugins/languages/KlipperConfigLanguage/tokens.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js similarity index 97% rename from src/plugins/languages/KlipperConfigLanguage/tokens.js rename to src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js index 72fdde9ad..51da00e8c 100644 --- a/src/plugins/languages/KlipperConfigLanguage/tokens.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js @@ -1,7 +1,7 @@ /* ref: https://github.com/lezer-parser/python/blob/main/src/tokens.js */ import { ExternalTokenizer, ContextTracker } from '@lezer/lr' -import { newline as newlineToken, eof, blankLineStart, indent, dedent } from './klipperConfigLang.terms.js' +import { newline as newlineToken, eof, blankLineStart, indent, dedent } from '../parser/klipperConfigParser.terms.js' const newline = 10, carriageReturn = 13, diff --git a/src/plugins/languages/Python/highlight.js b/src/plugins/CodemirrorLanguages/Python/highlight.js similarity index 100% rename from src/plugins/languages/Python/highlight.js rename to src/plugins/CodemirrorLanguages/Python/highlight.js diff --git a/src/plugins/languages/Python/index.ts b/src/plugins/CodemirrorLanguages/Python/index.ts similarity index 100% rename from src/plugins/languages/Python/index.ts rename to src/plugins/CodemirrorLanguages/Python/index.ts diff --git a/src/plugins/languages/Python/testPython.grammar b/src/plugins/CodemirrorLanguages/Python/testPython.grammar similarity index 100% rename from src/plugins/languages/Python/testPython.grammar rename to src/plugins/CodemirrorLanguages/Python/testPython.grammar diff --git a/src/plugins/languages/Python/testPython.js b/src/plugins/CodemirrorLanguages/Python/testPython.js similarity index 99% rename from src/plugins/languages/Python/testPython.js rename to src/plugins/CodemirrorLanguages/Python/testPython.js index 111099004..342984cb7 100644 --- a/src/plugins/languages/Python/testPython.js +++ b/src/plugins/CodemirrorLanguages/Python/testPython.js @@ -1,8 +1,8 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. import {LRParser} from "@lezer/lr" import {legacyPrint, trackIndent} from "./tokens.js" -import {indentation, newlines, formatString1, formatString2, formatString1l, formatString2l} from "./tokens" -import {pythonHighlighting} from "./highlight" +import {indentation, newlines, formatString1, formatString2, formatString1l, formatString2l} from "./tokens.js" +import {pythonHighlighting} from "./highlight.js" const spec_identifier = {__proto__:null,await:48, or:58, and:60, in:64, not:66, is:68, if:74, else:76, lambda:80, yield:98, from:100, async:106, for:108, None:168, True:170, False:170, del:184, pass:188, break:192, continue:196, return:200, raise:208, import:212, as:214, global:218, nonlocal:220, assert:224, elif:234, while:238, try:244, except:246, finally:248, with:252, def:256, class:266, match:277, case:283} export const parser = LRParser.deserialize({ version: 14, diff --git a/src/plugins/languages/Python/testPython.terms.js b/src/plugins/CodemirrorLanguages/Python/testPython.terms.js similarity index 100% rename from src/plugins/languages/Python/testPython.terms.js rename to src/plugins/CodemirrorLanguages/Python/testPython.terms.js diff --git a/src/plugins/languages/Python/tokens.js b/src/plugins/CodemirrorLanguages/Python/tokens.js similarity index 100% rename from src/plugins/languages/Python/tokens.js rename to src/plugins/CodemirrorLanguages/Python/tokens.js diff --git a/src/plugins/languages/printLezerTree.ts b/src/plugins/CodemirrorLanguages/printLezerTree.ts similarity index 100% rename from src/plugins/languages/printLezerTree.ts rename to src/plugins/CodemirrorLanguages/printLezerTree.ts From e2b333f06be07a6c24eec28d2738341dfdc14a9a Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sun, 21 May 2023 21:54:38 +0200 Subject: [PATCH 04/16] final block-folding --- .../KlipperConfigLanguage/lang/klipperConfig.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts index 82530a76d..2b77461be 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts @@ -23,13 +23,17 @@ export const klipperConfigLang = LRLanguage.define({ }), foldNodeProp.add({ ConfigBlock(tree) { - let node = tree.firstChild - if (node == null) return null - while (node.type.name != 'Body') { - node = node.nextSibling - if (node == null) return null + let body = tree.lastChild + if (body == null) return null + + let lastOption = body.lastChild + if (lastOption == null) return null + while (lastOption.name == 'Comment' || lastOption.name == 'BlankLine') { + lastOption = lastOption.prevSibling + if (lastOption == null) return null } - return { from: node.from - 1, to: tree.to - 2 } + + return { from: body.from - 1, to: lastOption.to - 1 } }, }), ], From 3ce9b196d4f5da5405ef477d9a777aa63a544f61 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Thu, 25 May 2023 15:09:54 +0200 Subject: [PATCH 05/16] fixed indentation tracking and blankline error, better linting --- .../lang/klipperConfig.ts | 2 +- .../KlipperConfigLanguage/lang/lint.ts | 4 +- .../KlipperConfigLanguage/parser/highlight.js | 4 +- .../parser/klipperConfig.grammar | 32 ++- .../parser/klipperConfigParser.js | 22 +- .../parser/klipperConfigParser.terms.js | 40 ++-- .../KlipperConfigLanguage/parser/tokens.js | 8 +- .../CodemirrorLanguages/Python/index.ts | 1 - .../Python/testPython.grammar | 41 +--- .../CodemirrorLanguages/Python/testPython.js | 38 ++-- .../Python/testPython.terms.js | 116 +++++------ .../CodemirrorLanguages/Python/tokens.js | 191 ++++++------------ 12 files changed, 191 insertions(+), 308 deletions(-) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts index 2b77461be..fe877a493 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts @@ -55,5 +55,5 @@ export function klipperConfig() { /* to generate the parser run: -npx @lezer/generator klipperConfig.grammar -o klipperConfigLang.js +npx @lezer/generator klipperConfig.grammar -o klipperConfigParser.js */ diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts index 9ccb6bcf2..5424e8cb4 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts @@ -6,7 +6,7 @@ export const klipperConfigLint = linter((view) => { syntaxTree(view.state) .cursor() .iterate((node) => { - if (node.name == 'Number') { + if (node.name == '') { diagnostics.push({ from: node.from, to: node.to, @@ -27,7 +27,7 @@ export const klipperConfigLint = linter((view) => { from: node.from, to: node.to, severity: 'error', - message: 'Syntax error', + message: 'Parse error: ' + JSON.stringify(view.state.sliceDoc(node.from, node.to)), }) } } diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js index 56ad58062..975f419b4 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js @@ -11,14 +11,14 @@ export const klipperConfigHighlighting = styleTags({ Identifier: t.attributeName, Comment: t.lineComment, AutoGenerated: t.name, - Boolean: t.bool, + Boolean: t.string, String: t.string, Number: t.number, Cords: t.number, Pin: t.atom, + Pins: t.atom, VirtualPin: t.atom, FilePath: t.className, Path: t.className, File: t.className, - Jinja2: t.typeName, }) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar index 553eaca1b..e4660e99e 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar @@ -1,11 +1,6 @@ @top Program { Import* ConfigBlock+ } -@skip { Comment newline | AutoGenerated newline | space | BlankLine } -@skip {} { - BlankLine { - blankLineStart space? newline - } -} +@skip { Comment newline? | AutoGenerated newline | space | blankLine } Import { "[" ImportKeyword (FilePath | File) "]" newline } ConfigBlock {"[" BlockType Identifier? "]" newline Body } @@ -13,12 +8,14 @@ ConfigBlock {"[" BlockType Identifier? "]" newline Body } Body { Option+ } Option { Parameter ":" Value | GcodeKeyword ":" Jinja2 } -Value { valueBlock } -Jinja2 { valueBlock } +Value { value (newline | eof) | newline valueBlock } +Jinja2 { jinja2 (newline | eof) | newline valueBlock } -valueBlock { content (newline | eof) | newline indent (content newline)+ (dedent | eof) } +valueBlock { indent (content newline | valueBlock)+ (dedent | eof) } -value { Pin | VirtualPin | Cords | Number | String | Boolean | FilePath | Path } +value { Pin | Pins | VirtualPin | Cords | Number | String | Boolean | FilePath | Path } +Pin { pin } +Pins { pin ("," pin)+ } Number { number } String { string } Cords { number ("," number)+ } @@ -29,18 +26,21 @@ File {string "." string } +@context trackIndent from "./tokens.js" +@external tokens indentation from "./tokens.js" { indent, dedent } +@external tokens newlines from "./tokens.js" { newline, blankLine, eof } @tokens { ImportKeyword{ "include" } GcodeKeyword{ "gcode" } Identifier { $[a-zA-Z0-9_.\-]+ } - Parameter { $[a-zA-Z_]+ } + Parameter { $[a-zA-Z0-9_]+ } string { $[ a-zA-Z0-9_\-]+ } - jinja2 { $[ a-zA-Z0-9_.\-"'{}%=]+ } + jinja2 { $[ \ta-zA-Z0-9_.\-"'{}%=]+ } number { "-"? $[0-9]+ ("." $[0-9]*)? } Boolean { "True" | "False" } - Pin { ("^" | "~")? "!"? "P" $[A-Z] $[0-9]+ } + pin { ("^" | "~")? "!"? "P" $[A-Z] $[0-9]+ } BlockType { "mcu" | "printer" | "extruder" | "adxl345" | "resonance_tester" | "stepper_x" | "stepper_y" | "stepper_z" | @@ -55,14 +55,10 @@ File {string "." string } @precedence { space, jinja2, string} @precedence { AutoGenerated, Comment } - @precedence { number, Pin, Boolean, ImportKeyword, string } + @precedence { number, pin, Boolean, ImportKeyword, string } @precedence { GcodeKeyword, Parameter} } -@context trackIndent from "./tokens.js" -@external tokens indentation from "./tokens.js" { indent, dedent } -@external tokens newlines from "./tokens.js" { newline, blankLineStart, eof } - @external propSource klipperConfigHighlighting from "./highlight" @detectDelim diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js index df9ed845b..676f64b12 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js @@ -4,17 +4,17 @@ import {indentation, newlines, trackIndent} from "./tokens.js" import {klipperConfigHighlighting} from "./highlight" export const parser = LRParser.deserialize({ version: 14, - states: "+pO`Q!cOOPeO!cOOOpQ!cO'#CaOOQ!b'#Cu'#CuO`Q!cOOOOQ!b'#Cw'#CwQxQ!cOOP}O!cO'#C_P!VO!bO)C>xPOOO)C>x)C>xO![Q!dO,58{O!dQ!fO,59QOOQ!b-E6s-E6sOsQ!cO'#CfOOQ!b-E6u-E6uPOOO,58y,58yP!lO!bO,58yPOOO/'4d/'4dO!qQ!cO'#CvO!yQ!dO'#CdO#OQ!dO'#CdO#TQ!cO'#CcO#YQ!cO1G.gO#_Q!cO1G.lO#dQ!cO1G.lP#iQ!cO'#CaPOOO1G.e1G.eOOQ!b,59b,59bO#nQ!dO,59PO#sQ!cO,59OOOQ!b-E6t-E6tO$RQ!cO'#CvO$WQ!dO,59OO$]Q!dO,58}O$bQ!cO7+$RO$gQ!jO7+$WO$oQ!cO7+$WOOQ!b1G.k1G.kO$tQ!cO1G.jOOQ!b1G.i1G.iOOQ!b<yO!SQYO,58zO![QbO,59POOQQ-E6s-E6sOsQUO'#CeOOQQ-E6u-E6uPOOO/'4e/'4eO!dQUO'#CvO!lQYO'#CcO!qQYO'#CcO!vQUO'#CbO!{QUO1G.fO#QQUO1G.kO#VQUO1G.kP#[QUO'#C`OOQQ,59b,59bO#aQYO,59OO#fQUO,58}OOQQ-E6t-E6tO#tQUO'#CvO#yQYO,58}O$OQYO,58|O$TQUO7+$QO$YQrO7+$VO$bQUO7+$VOOQQ1G.j1G.jO$gQUO1G.iOOQQ1G.h1G.hOOQQ<P#R#S1S#T#U>Y#U#VFh#V#W!!Q#W#X1S#X#Y!1o#Y#Z!/^#Z#[!:X#[#]!@X#]#^#,z#^#a1S#a#b#5`#b#d1S#d#e#7t#e#f1S#f#g#>O#g#h#Lc#h#i%#R#i#n1S#n#o%P~$^Rw~XY$X[]$Xpq$X~$p_w~!T`zQXY$X[]$Xpq$grs%ouv%owx%o}!O&m!O!P%o!Q![&m!_!`%o!c!}&m#R#S&m#T#o&m#o#p%o#q#r%o`%t]!T`pq%ors%ouv%owx%o}!O%o!O!P%o!Q![%o!_!`%o!c!}%o#R#S%o#T#o%o#o#p%o#q#r%ob&t]!T`zQpq&mrs%ouv%owx%o}!O&m!O!P%o!Q![&m!_!`%o!c!}&m#R#S&m#T#o&m#o#p%o#q#r%oQ'pP!r!s'sQ'vP!c!}'yQ'|P!Q![(PQ(UPaQ!Q![(P~(^VP~OY(sZ](s^z(sz{)_{;'S(s;'S;=`)X<%lO(s~(xTP~OY(sZ](s^;'S(s;'S;=`)X<%lO(s~)[P;=`<%l(s~)dVP~OY(sZ](s^s(sst)yt;'S(s;'S;=`)X<%lO(s~*QTQ~P~OY)yZ])y^;'S)y;'S;=`*a<%lO)y~*dP;=`<%l)y~*lO!R~g*u][S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![-p!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%of+w][S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%od,w][S!T`pq%ors%ouv%owx%o}!O,p!O!P,p!Q![,p!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%og-{][S!T`!QRzQpq&mrs%ouv%owx%o}!O+n!O!P.t!Q![-p!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og.}][S!T`!QRpq%ors%ouv%owx%o}!O,p!O!P,p!Q![.t!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%oe0P]{P[S!T`pq%ors%ouv%owx%o}!O,p!O!P,p!Q![,p!_!`%o!c!},p#R#S,p#T#o,p#o#p%o#q#r%o~0}Oy~~1SO}~n1_][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%on2c^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U3_#U#o1S#o#p%o#q#r%on3j_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a4i#a#o1S#o#p%o#q#r%on4t_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h5s#h#o1S#o#p%o#q#r%on6O_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y6}#Y#o1S#o#p%o#q#r%on7[][S!T`_WfQzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%on8`][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}9X#R#S1S#T#o1S#o#p%o#q#r%on9d][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![:]!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%of:h][S!T`aQzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![:]!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%on;l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#gPO|~Q>SQqr'm!r!s'so>e_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X?d#X#o1S#o#p%o#q#r%oo?o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#m@n#m#o1S#o#p%o#q#r%oo@y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#aAx#a#o1S#o#p%o#q#r%ooBT_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!T+n!T!UCS!U![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%ogC]_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!U+n!U!VD[!V![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ogDe_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!V+n!V!WEd!W![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ogEo]ZP[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%ooFs_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YGr#Y#o1S#o#p%o#q#r%ooG}_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#XH|#X#o1S#o#p%o#q#r%ooIX][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#SJQ#T#o1S#o#p%o#q#r%ooJ]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#bK[#b#o1S#o#p%o#q#r%ooKg_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YLf#Y#o1S#o#p%o#q#r%ooLq_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#hMp#h#o1S#o#p%o#q#r%ooM{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#[1S#[#]Nz#]#o1S#o#p%o#q#r%oo! X]ZP[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo!!]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!#[#d#o1S#o#p%o#q#r%oo!#g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c!$f#c#o1S#o#p%o#q#r%oo!$q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!%p#i#o1S#o#p%o#q#r%oo!%{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!&z#g#o1S#o#p%o#q#r%oo!'V_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!(U#d#o1S#o#p%o#q#r%oo!(a_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a!)`#a#o1S#o#p%o#q#r%oo!)k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a!*j#a#o1S#o#p%o#q#r%oo!*u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!+t#Y#o1S#o#p%o#q#r%oo!,P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!-O#g#o1S#o#p%o#q#r%oo!-Z][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S!.S#T#o1S#o#p%o#q#r%oo!.__[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Y1S#Y#Z!/^#Z#o1S#o#p%o#q#r%oo!/i^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U!0e#U#o1S#o#p%o#q#r%oo!0p_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#cNz#c#o1S#o#p%o#q#r%oo!1z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#m!2y#m#o1S#o#p%o#q#r%oo!3U_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!4T#i#o1S#o#p%o#q#r%oo!4`_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!5_#g#o1S#o#p%o#q#r%oo!5j_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j!6i#j#o1S#o#p%o#q#r%oo!6t_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X!7s#X#o1S#o#p%o#q#r%oo!8O_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!8}#Y#o1S#o#p%o#q#r%oo!9Y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#gNz#g#o1S#o#p%o#q#r%on!:d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W!;c#W#o1S#o#p%o#q#r%on!;n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!S_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!?R#Y#o1S#o#p%o#q#r%on!?`][S!T`gW_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo!@da[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!Ai#Y#c1S#c#d!KY#d#o1S#o#p%o#q#r%oo!At^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U!Bp#U#o1S#o#p%o#q#r%oo!B{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i!Cz#i#o1S#o#p%o#q#r%oo!DV_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!EU#Y#o1S#o#p%o#q#r%oo!Ea_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g!F`#g#o1S#o#p%o#q#r%oo!Fk][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S!Gd#T#o1S#o#p%o#q#r%oo!Goa[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U1S#U#V!Ht#V#Y1S#Y#Z!/^#Z#o1S#o#p%o#q#r%oo!IP_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y!JO#Y#o1S#o#p%o#q#r%oo!JZ_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#XNz#X#o1S#o#p%o#q#r%oo!Ke_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#b!Ld#b#o1S#o#p%o#q#r%oo!Lo_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^!Mn#^#o1S#o#p%o#q#r%oo!My_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c!Nx#c#o1S#o#p%o#q#r%oo# T_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Z1S#Z#[#!S#[#o1S#o#p%o#q#r%oo#!_][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S##W#T#o1S#o#p%o#q#r%oo##c_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d#$b#d#o1S#o#p%o#q#r%oo#$m_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#j1S#j#k#%l#k#o1S#o#p%o#q#r%oo#%w_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#&v#Y#o1S#o#p%o#q#r%oo#'R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#(Q#g#o1S#o#p%o#q#r%oo#(]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#)[#g#o1S#o#p%o#q#r%oo#)g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^#*f#^#o1S#o#p%o#q#r%oo#*q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X#+p#X#o1S#o#p%o#q#r%oo#+{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#YNz#Y#o1S#o#p%o#q#r%oo#-V_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#.U#c#o1S#o#p%o#q#r%oo#.a_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#/`#W#o1S#o#p%o#q#r%oo#/k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a#0j#a#o1S#o#p%o#q#r%oo#0u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j#1t#j#o1S#o#p%o#q#r%oo#2P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X#3O#X#o1S#o#p%o#q#r%oo#3Z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#4Y#Y#o1S#o#p%o#q#r%oo#4g][S!T`_WUPzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo#5k_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#6j#W#o1S#o#p%o#q#r%oo#6u_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#jNz#j#o1S#o#p%o#q#r%oo#8P_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#9O#g#o1S#o#p%o#q#r%oo#9Za[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^#:`#^#c1S#c#d#Z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#?Y#Y#o1S#o#p%o#q#r%oo#?e_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h#@d#h#o1S#o#p%o#q#r%oo#@o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d#An#d#o1S#o#p%o#q#r%oo#Ay_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#Bx#c#o1S#o#p%o#q#r%oo#CT^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U#DP#U#o1S#o#p%o#q#r%oo#D[_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c#EZ#c#o1S#o#p%o#q#r%oo#Ef_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#Fe#W#o1S#o#p%o#q#r%oo#Fp_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#Go#Y#o1S#o#p%o#q#r%oo#Gz][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S#Hs#T#o1S#o#p%o#q#r%oo#IO_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i#I}#i#o1S#o#p%o#q#r%oo#JY_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y#KX#Y#o1S#o#p%o#q#r%oo#Kd_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h#;j#h#o1S#o#p%o#q#r%oo#Lna[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W#Ms#W#h1S#h#i$2z#i#o1S#o#p%o#q#r%oo#NO_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g#N}#g#o1S#o#p%o#q#r%oo$ Y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y$!X#Y#o1S#o#p%o#q#r%oo$!d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#k1S#k#l$#c#l#o1S#o#p%o#q#r%oo$#n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h$$m#h#o1S#o#p%o#q#r%oo$$x][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$%q#T#o1S#o#p%o#q#r%oo$%|_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$&{#i#o1S#o#p%o#q#r%oo$'W_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$(V#^#o1S#o#p%o#q#r%oo$(b_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$)a#a#o1S#o#p%o#q#r%oo$)l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$*k#i#o1S#o#p%o#q#r%oo$*v][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$+o#T#o1S#o#p%o#q#r%oo$+z^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$,v#U#o1S#o#p%o#q#r%oo$-R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X$.Q#X#o1S#o#p%o#q#r%oo$.]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#^1S#^#_$/[#_#o1S#o#p%o#q#r%oo$/g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$0f#j#o1S#o#p%o#q#r%oo$0q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h$1p#h#o1S#o#p%o#q#r%oo$1{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#iNz#i#o1S#o#p%o#q#r%oo$3V`[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$4X#U#X1S#X#Y$Hj#Y#o1S#o#p%o#q#r%oo$4d_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$5c#i#o1S#o#p%o#q#r%oo$5n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$6m#^#o1S#o#p%o#q#r%oo$6x_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W$7w#W#o1S#o#p%o#q#r%oo$8S][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$8{#T#o1S#o#p%o#q#r%oo$9W_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#W1S#W#X$:V#X#o1S#o#p%o#q#r%oo$:b_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^$;a#^#o1S#o#p%o#q#r%oo$;l_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#Z1S#Z#[$Q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$?P#i#o1S#o#p%o#q#r%oo$?[^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U$@W#U#o1S#o#p%o#q#r%oo$@c_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$Ab#a#o1S#o#p%o#q#r%oo$Am][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$Bf#T#o1S#o#p%o#q#r%oo$Bq_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d$Cp#d#o1S#o#p%o#q#r%oo$C{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$Dz#j#o1S#o#p%o#q#r%oo$EV_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i$FU#i#o1S#o#p%o#q#r%oo$Fa_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$G`#e#o1S#o#p%o#q#r%oo$Gk_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j$1p#j#o1S#o#p%o#q#r%oo$Hu_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$It#e#o1S#o#p%o#q#r%oo$JP_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e$KO#e#o1S#o#p%o#q#r%oo$KZ_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y$LY#Y#o1S#o#p%o#q#r%oo$Le_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g$Md#g#o1S#o#p%o#q#r%oo$Mo][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S$Nh#T#o1S#o#p%o#q#r%oo$Ns`[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#l1S#l#mNz#m#nNz#n#o% u#o#p%o#q#r%oo%!S_ZP[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!R+n!R!SEd!S![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%oo%#^a[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%$c#Y#a1S#a#b%6f#b#o1S#o#p%o#q#r%oo%$n_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#a1S#a#b%%m#b#o1S#o#p%o#q#r%oo%%x_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#d1S#d#e%&w#e#o1S#o#p%o#q#r%oo%'S_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%(R#Y#o1S#o#p%o#q#r%oo%(^_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g%)]#g#o1S#o#p%o#q#r%oo%)h^[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#U%*d#U#o1S#o#p%o#q#r%oo%*o_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#h1S#h#i%+n#i#o1S#o#p%o#q#r%oo%+y_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#i1S#i#j%,x#j#o1S#o#p%o#q#r%oo%-T_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#f1S#f#g%.S#g#o1S#o#p%o#q#r%oo%.__[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%/^#Y#o1S#o#p%o#q#r%oo%/i][S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S%0b#T#o1S#o#p%o#q#r%oo%0m_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h%1l#h#o1S#o#p%o#q#r%oo%1w_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#X1S#X#Y%2v#Y#o1S#o#p%o#q#r%oo%3R_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#b1S#b#c%4Q#c#o1S#o#p%o#q#r%oo%4]_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#g1S#g#h%5[#h#o1S#o#p%o#q#r%oo%5g_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#c1S#c#d!8}#d#o1S#o#p%o#q#r%oo%6q_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#V1S#V#W%7p#W#o1S#o#p%o#q#r%oo%7{_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!S+n!S!T%8z!T![+n!_!`%o!c!}1S#R#S1S#T#o1S#o#p%o#q#r%og%9T_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!S+n!S!T%:S!T![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og%:]^[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!R%;X!R![+n!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%og%;b_[S!T`zQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q!Y+n!Y!ZEd!Z![Ed!_!`%o!c!}+n#R#S+n#T#o+n#o#p%o#q#r%oo%o#i#o1S#o#p%o#q#r%oo%>z_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#]1S#]#^%?y#^#o1S#o#p%o#q#r%oo%@U_[S!T`_WzQpq&mrs%ouv%owx%o}!O+n!O!P,p!Q![+n!_!`%o!c!}1S#R#S1S#T#`1S#`#a$1p#a#o1S#o#p%o#q#r%o", - tokenizers: [0, 1, 2, 3, 4, indentation, newlines], - topRules: {"Program":[0,4]}, - tokenPrec: 363 + skippedNodes: [0,1,2], + repeatNodeCount: 8, + tokenData: "%My~R!QXY$X[]%_pq&nqr(yrs%mst)euv%mwx%m|}+s}!O+x!O!P1c!P!Q2h!Q![2m![!]4}!_!`%m!c!h3v!h!i5S!i!r3v!r!s;`!s!v3v!v!w>w!w!}3v!}#OAc#P#QAh#Q#RAm#R#S3v#T#UAv#U#VJq#V#W!%j#W#X3v#X#Y!6Q#Y#Z!3i#Z#[!?P#[#]!E`#]#^#3g#^#a3v#a#b#|#e#f3v#f#g#Eg#g#h$&p#h#i%.S#i#n3v#n#o%Hy#o#p%m#q#r%m#r#sAm~$`_x~!U`XY$X[]%_pq$Xrs%muv%mwx%m}!O%m!O!P%m!Q![%m!_!`%m!c!}%m#R#S%m#T#o%m#o#p%m#q#r%m~%dRx~XY%_[]%_pq%_`%r^!U`XY%mpq%mrs%muv%mwx%m}!O%m!O!P%m!Q![%m!_!`%m!c!}%m#R#S%m#T#o%m#o#p%m#q#r%m~&w_x~!U`{QXY$X[]%_pq&nrs%muv%mwx%m}!O'v!O!P%m!Q!['v!_!`%m!c!}'v#R#S'v#T#o'v#o#p%m#q#r%mb'}^!U`{QXY%mpq'vrs%muv%mwx%m}!O'v!O!P%m!Q!['v!_!`%m!c!}'v#R#S'v#T#o'v#o#p%m#q#r%mR(|P!r!s)PR)SP!c!})VR)YP!Q![)]R)bP!QR!Q![)]~)jVP~OY*PZ]*P^z*Pz{*k{;'S*P;'S;=`*e<%lO*P~*UTP~OY*PZ]*P^;'S*P;'S;=`*e<%lO*P~*hP;=`<%l*P~*pVP~OY*PZ]*P^s*Pst+Vt;'S*P;'S;=`*e<%lO*P~+^TQ~P~OY+VZ]+V^;'S+V;'S;=`+m<%lO+V~+pP;=`<%l+V~+xO!R~g,R^ZS!U`{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![/V!_!`%m!c!},}#R#S,}#T#o,}#o#p%m#q#r%mf-W^ZS!U`{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![,}!_!`%m!c!},}#R#S,}#T#o,}#o#p%m#q#r%md.Z^ZS!U`XY%mpq%mrs%muv%mwx%m}!O.S!O!P.S!Q![.S!_!`%m!c!}.S#R#S.S#T#o.S#o#p%m#q#r%mg/b^ZS!U`!SR{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P0^!Q![/V!_!`%m!c!},}#R#S,}#T#o,}#o#p%m#q#r%mg0g^ZS!U`!SRXY%mpq%mrs%muv%mwx%m}!O.S!O!P.S!Q![0^!_!`%m!c!}.S#R#S.S#T#o.S#o#p%m#q#r%me1l^|PZS!U`XY%mpq%mrs%muv%mwx%m}!O.S!O!P.S!Q![.S!_!`%m!c!}.S#R#S.S#T#o.S#o#p%m#q#r%m~2mOz~o2z^ZS!U`^W!SR{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P0^!Q![2m!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mn4R^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%m~5SO!O~n5__ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#U6^#U#o3v#o#p%m#q#r%mn6i`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#`3v#`#a7k#a#o3v#o#p%m#q#r%mn7v`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#g3v#g#h8x#h#o3v#o#p%m#q#r%mn9T`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y:V#Y#o3v#o#p%m#q#r%mn:d^ZS!U`^WfQ{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo;k^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}{#i#o3v#o#p%m#q#r%mo$?W`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#]3v#]#^$@Y#^#o3v#o#p%m#q#r%mo$@e`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#V3v#V#W$Ag#W#o3v#o#p%m#q#r%mo$Ar^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S$Bn#T#o3v#o#p%m#q#r%mo$By`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#W3v#W#X$C{#X#o3v#o#p%m#q#r%mo$DW`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#]3v#]#^$EY#^#o3v#o#p%m#q#r%mo$Ee`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#Z3v#Z#[$Fg#[#o3v#o#p%m#q#r%mo$Fr`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#]3v#]#^$Gt#^#o3v#o#p%m#q#r%mo$HP`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#h3v#h#i$IR#i#o3v#o#p%m#q#r%mo$I^_ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#U$J]#U#o3v#o#p%m#q#r%mo$Jh`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#`3v#`#a$Kj#a#o3v#o#p%m#q#r%mo$Ku^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S$Lq#T#o3v#o#p%m#q#r%mo$L|`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#c3v#c#d$NO#d#o3v#o#p%m#q#r%mo$NZ`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#i3v#i#j% ]#j#o3v#o#p%m#q#r%mo% h`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#h3v#h#i%!j#i#o3v#o#p%m#q#r%mo%!u`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#d3v#d#e%#w#e#o3v#o#p%m#q#r%mo%$S`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#i3v#i#j$;P#j#o3v#o#p%m#q#r%mo%%a`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#d3v#d#e%&c#e#o3v#o#p%m#q#r%mo%&n`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#d3v#d#e%'p#e#o3v#o#p%m#q#r%mo%'{`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y%(}#Y#o3v#o#p%m#q#r%mo%)Y`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#f3v#f#g%*[#g#o3v#o#p%m#q#r%mo%*g^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S%+c#T#o3v#o#p%m#q#r%mo%+naZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#l3v#l#mIh#m#nIh#n#o%,s#o#p%m#q#r%mo%-Q`YPZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!R3v!R!SIh!S![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%._bZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y%/g#Y#a3v#a#b%Bi#b#o3v#o#p%m#q#r%mo%/r`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#a3v#a#b%0t#b#o3v#o#p%m#q#r%mo%1P`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#d3v#d#e%2R#e#o3v#o#p%m#q#r%mo%2^`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y%3`#Y#o3v#o#p%m#q#r%mo%3k`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#f3v#f#g%4m#g#o3v#o#p%m#q#r%mo%4x_ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#U%5w#U#o3v#o#p%m#q#r%mo%6S`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#h3v#h#i%7U#i#o3v#o#p%m#q#r%mo%7a`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#i3v#i#j%8c#j#o3v#o#p%m#q#r%mo%8n`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#f3v#f#g%9p#g#o3v#o#p%m#q#r%mo%9{`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y%:}#Y#o3v#o#p%m#q#r%mo%;Y^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S%p#Y#o3v#o#p%m#q#r%mo%>{`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#b3v#b#c%?}#c#o3v#o#p%m#q#r%mo%@Y`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#g3v#g#h%A[#h#o3v#o#p%m#q#r%mo%Ag`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#c3v#c#d!=r#d#o3v#o#p%m#q#r%mo%Bt`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#V3v#V#W%Cv#W#o3v#o#p%m#q#r%mo%DR`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!S3v!S!T%ET!T![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%E``ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!S3v!S!T%Fb!T![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%Fm_ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!R%Gl!R![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%Gw`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!Y3v!Y!ZIh!Z![Ih!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%IU^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S%JQ#T#o3v#o#p%m#q#r%mo%J]`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#h3v#h#i%K_#i#o3v#o#p%m#q#r%mo%Kj`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#]3v#]#^%Ll#^#o3v#o#p%m#q#r%mo%Lw`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#`3v#`#a$;P#a#o3v#o#p%m#q#r%m", + tokenizers: [indentation, newlines, 0, 1, 2, 3, 4], + topRules: {"Program":[0,3]}, + tokenPrec: 393 }) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js index f5900d068..4b50d17a6 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js @@ -1,27 +1,27 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. export const - indent = 33, - dedent = 34, - newline = 35, - blankLineStart = 36, - eof = 37, + indent = 34, + dedent = 35, + newline = 36, + blankLine = 37, + eof = 38, Comment = 1, AutoGenerated = 2, - BlankLine = 3, - Program = 4, - Import = 5, - ImportKeyword = 6, - FilePath = 7, - Path = 8, - File = 9, - ConfigBlock = 10, - BlockType = 11, - Identifier = 12, - Body = 13, - Option = 14, - Parameter = 15, - Value = 16, - Pin = 17, + Program = 3, + Import = 4, + ImportKeyword = 5, + FilePath = 6, + Path = 7, + File = 8, + ConfigBlock = 9, + BlockType = 10, + Identifier = 11, + Body = 12, + Option = 13, + Parameter = 14, + Value = 15, + Pin = 16, + Pins = 17, VirtualPin = 18, Cords = 19, Number = 20, diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js index 51da00e8c..ef023b7e8 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js @@ -1,7 +1,7 @@ /* ref: https://github.com/lezer-parser/python/blob/main/src/tokens.js */ import { ExternalTokenizer, ContextTracker } from '@lezer/lr' -import { newline as newlineToken, eof, blankLineStart, indent, dedent } from '../parser/klipperConfigParser.terms.js' +import { newline as newlineToken, eof, blankLine, indent, dedent } from '../parser/klipperConfigParser.terms.js' const newline = 10, carriageReturn = 13, @@ -17,13 +17,11 @@ export const newlines = new ExternalTokenizer( let prev if (input.next < 0) { input.acceptToken(eof) - } else if (((prev = input.peek(-1)) < 0 || isLineBreak(prev)) && stack.canShift(blankLineStart)) { - let spaces = 0 + } else if ((prev = input.peek(-1)) < 0 || isLineBreak(prev)) { while (input.next == space || input.next == tab) { input.advance() - spaces++ } - if (input.next == newline || input.next == carriageReturn) input.acceptToken(blankLineStart, -spaces) + if (input.next == newline || input.next == carriageReturn) input.acceptToken(blankLine, 1) } else if (isLineBreak(input.next)) { input.acceptToken(newlineToken, 1) } diff --git a/src/plugins/CodemirrorLanguages/Python/index.ts b/src/plugins/CodemirrorLanguages/Python/index.ts index 4936d8528..fbd219d4a 100644 --- a/src/plugins/CodemirrorLanguages/Python/index.ts +++ b/src/plugins/CodemirrorLanguages/Python/index.ts @@ -1,4 +1,3 @@ -//@ts-ignore import { parser } from './testPython.js' import { LRLanguage, LanguageSupport } from '@codemirror/language' diff --git a/src/plugins/CodemirrorLanguages/Python/testPython.grammar b/src/plugins/CodemirrorLanguages/Python/testPython.grammar index 6b36406b9..4f30091da 100644 --- a/src/plugins/CodemirrorLanguages/Python/testPython.grammar +++ b/src/plugins/CodemirrorLanguages/Python/testPython.grammar @@ -17,7 +17,7 @@ @top Script { statement+ } -@skip { space | newlineBracketed | Comment | blankLine } +@skip { space | Comment | blankLine } Decorator { At dottedName ArgList? newline } @@ -88,7 +88,6 @@ smallStatement { ContinueStatement { kw<"continue"> } | ReturnStatement { kw<"return"> commaSep? } | YieldStatement { yield } | - PrintStatement { printKeyword test } | RaiseStatement { kw<"raise"> (test (kw<"from"> test | ("," test ("," test)?))?)? } | ImportStatement | ScopeStatement { (kw<"global"> | kw<"nonlocal">) commaSep } | @@ -181,8 +180,8 @@ expression[@isGroup=Expression] { MemberExpression { expression !trail (subscript | "." PropertyName) } | VariableName | Number | - String | FormatString | - ContinuedString { (String | FormatString) (String | FormatString)+ } | + String | + ContinuedString { (String) (String)+ } | "..." | kw<"None"> | @specialize[@name=Boolean] @@ -251,34 +250,16 @@ skw { @extend[@name={term}] } longStringStart<'"'> longString2Content* '"""' } - FormatString { - formatStringStart<"'"> (formatString1Content | FormatReplacement)* formatString1End | - formatStringStart<'"'> (formatString2Content | FormatReplacement)* formatString2End | - longFormatStringStart<"'"> (formatString1lContent | FormatReplacement)* formatString1lEnd | - longFormatStringStart<'"'> (formatString2lContent | FormatReplacement)* formatString2lEnd - } - - formatStringSpec { FormatSpec { ":" (formatStringSpecChars | FormatReplacement<"{">)* } "}" } - blankLine { blankLineStart space? Comment? newline } } -FormatReplacement { start (YieldExpression | commaSep<"*"? test>) FormatConversion? (formatStringSpec | "}") } - @context trackIndent from "./tokens.js" -@external tokens legacyPrint from "./tokens.js" { printKeyword[@name="print"] } - @external tokens indentation from "./tokens" { indent, dedent } -@external tokens newlines from "./tokens" { newline, blankLineStart, newlineBracketed, eof } - -@external tokens formatString1 from "./tokens" { formatString1Content, formatString1Brace[@name="{"], formatString1End } -@external tokens formatString2 from "./tokens" { formatString2Content, formatString2Brace[@name="{"], formatString2End } -@external tokens formatString1l from "./tokens" { formatString1lContent, formatString1lBrace[@name="{"], formatString1lEnd } -@external tokens formatString2l from "./tokens" { formatString2lContent, formatString2lBrace[@name="{"], formatString2lEnd } +@external tokens newlines from "./tokens" { newline, blankLineStart, eof } @tokens { CompareOp { "<" | ">" | $[<>=!] "=" | "<>" } @@ -286,8 +267,8 @@ FormatReplacement { start (YieldExpression | commaSep<"*"? test>) FormatC UpdateOp { ($[+\-@%&|^] | "<<" | ">>" | "*" "*"? | "/" "/"?) "=" } @precedence { - longStringStart<"'">, longStringStart<'"'>, longFormatStringStart<"'">, longFormatStringStart<'"'>, - shortString, formatStringStart<"'">, formatStringStart<'"'>, + longStringStart<"'">, longStringStart<'"'>, + shortString, identifier } @@ -299,16 +280,8 @@ FormatReplacement { start (YieldExpression | commaSep<"*"? test>) FormatC stringPrefix { $[rRuUbB] | $[bB] $[rR] | $[rR] $[bR] } - formatPrefix { $[fF] | $[fF] $[rR] | $[rR] $[fF] } - shortString { stringPrefix? ("'" (!['\\\n\r] | "\\" _)* "'"? | '"' (!["\\\n\r] | "\\" _)* '"'?) } - formatStringStart { formatPrefix quote } - - FormatConversion { "!" $[sra] } - - formatStringSpecChars { ![{}]+ } - longStringStart { stringPrefix? quote quote quote } longString1Content { (!['\\] | "\\" _ | "'" longString1_2)+ } @@ -319,8 +292,6 @@ FormatReplacement { start (YieldExpression | commaSep<"*"? test>) FormatC longString2_2 { !["\\] | "\\" _ | '"' longString2_3 } longString2_3 { !["\\] | "\\" _ } - longFormatStringStart { formatPrefix quote quote quote } - Number { (@digit ("_" | @digit)* ("." @digit ("_" | @digit)*)? | "." @digit ("_" | @digit)*) ($[eE] $[+\-]? @digit ("_" | @digit)*)? $[jJ]? | diff --git a/src/plugins/CodemirrorLanguages/Python/testPython.js b/src/plugins/CodemirrorLanguages/Python/testPython.js index 342984cb7..e843af7cf 100644 --- a/src/plugins/CodemirrorLanguages/Python/testPython.js +++ b/src/plugins/CodemirrorLanguages/Python/testPython.js @@ -1,28 +1,28 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. import {LRParser} from "@lezer/lr" -import {legacyPrint, trackIndent} from "./tokens.js" -import {indentation, newlines, formatString1, formatString2, formatString1l, formatString2l} from "./tokens.js" -import {pythonHighlighting} from "./highlight.js" -const spec_identifier = {__proto__:null,await:48, or:58, and:60, in:64, not:66, is:68, if:74, else:76, lambda:80, yield:98, from:100, async:106, for:108, None:168, True:170, False:170, del:184, pass:188, break:192, continue:196, return:200, raise:208, import:212, as:214, global:218, nonlocal:220, assert:224, elif:234, while:238, try:244, except:246, finally:248, with:252, def:256, class:266, match:277, case:283} +import {indentation, newlines} from "./tokens" +import {trackIndent} from "./tokens.js" +import {pythonHighlighting} from "./highlight" +const spec_identifier = {__proto__:null,await:38, or:48, and:50, in:54, not:56, is:58, if:64, else:66, lambda:70, yield:88, from:90, async:96, for:98, None:142, True:144, False:144, del:158, pass:162, break:166, continue:170, return:174, raise:180, import:184, as:186, global:190, nonlocal:192, assert:196, elif:206, while:210, try:216, except:218, finally:220, with:224, def:228, class:238, match:249, case:255} export const parser = LRParser.deserialize({ version: 14, - states: "#!OO`Q#yOOP$_OSOOO%hQ&nO'#H^OOQS'#Cq'#CqOOQS'#Cr'#CrO'WQ#xO'#CpO(yQ&nO'#H]OOQS'#H^'#H^OOQS'#DW'#DWOOQS'#H]'#H]O)gQ#xO'#DaO)zQ#xO'#DhO*[Q#xO'#DlOOQS'#Dw'#DwO*oO,UO'#DwO*wO7[O'#DwO+POWO'#DxO+[O`O'#DxO+gOpO'#DxO+rO!bO'#DxO-tQ&nO'#G}OOQS'#G}'#G}O'WQ#xO'#G|O/WQ&nO'#G|OOQS'#Ee'#EeO/oQ#xO'#EfOOQS'#G{'#G{O/yQ#xO'#GzOOQV'#Gz'#GzO0UQ#xO'#FXOOQS'#G`'#G`O0ZQ#xO'#FWOOQV'#IS'#ISOOQV'#Gy'#GyOOQV'#Fp'#FpQ`Q#yOOO'WQ#xO'#CsO0iQ#xO'#DPO0pQ#xO'#DTO1OQ#xO'#HbO1`Q&nO'#EYO'WQ#xO'#EZOOQS'#E]'#E]OOQS'#E_'#E_OOQS'#Ea'#EaO1tQ#xO'#EcO2[Q#xO'#EgO0UQ#xO'#EiO2oQ&nO'#EiO0UQ#xO'#ElO/oQ#xO'#EoO/oQ#xO'#EsO/oQ#xO'#EvO2zQ#xO'#ExO3RQ#xO'#E}O3^Q#xO'#EyO/oQ#xO'#E}O0UQ#xO'#FPO0UQ#xO'#FUO3cQ#xO'#FZP3jO#xO'#GxPOOO)CBl)CBlOOQS'#Cg'#CgOOQS'#Ch'#ChOOQS'#Ci'#CiOOQS'#Cj'#CjOOQS'#Ck'#CkOOQS'#Cl'#ClOOQS'#Cn'#CnO'WQ#xO,59QO'WQ#xO,59QO'WQ#xO,59QO'WQ#xO,59QO'WQ#xO,59QO'WQ#xO,59QO3uQ#xO'#DqOOQS,5:[,5:[O4YQ#xO'#HlOOQS,5:_,5:_O4gQMlO,5:_O4lQ&nO,59[O0iQ#xO,59dO0iQ#xO,59dO0iQ#xO,59dO7[Q#xO,59dO7aQ#xO,59dO7hQ#xO,59lO7oQ#xO'#H]O8uQ#xO'#H[OOQS'#H['#H[OOQS'#D^'#D^O9^Q#xO,59cO'WQ#xO,59cO9lQ#xO,59cOOQS,59{,59{O9qQ#xO,5:TO'WQ#xO,5:TOOQS,5:S,5:SO:PQ#xO,5:SO:UQ#xO,5:ZO'WQ#xO,5:ZO'WQ#xO,5:XOOQS,5:W,5:WO:gQ#xO,5:WO:lQ#xO,5:YOOOO'#Fx'#FxO:qO,UO,5:cOOQS,5:c,5:cOOOO'#Fy'#FyO:yO7[O,5:cO;RQ#xO'#DyOOOW'#Fz'#FzO;cOWO,5:dOOQS,5:d,5:dO;RQ#xO'#D}OOO`'#F}'#F}O;nO`O,5:dO;RQ#xO'#EOOOOp'#GO'#GOO;yOpO,5:dO;RQ#xO'#EPOOO!b'#GP'#GPOWOOQS'#Du'#DuOOQS1G/y1G/yOOQS1G/O1G/OO!-ZQ&nO1G/OO!-bQ&nO1G/OO0iQ#xO1G/OO!-}Q#xO1G/WOOQS'#D]'#D]O/oQ#xO,59vOOQS1G.}1G.}O!.UQ#xO1G/gO!.fQ#xO1G/gO!.nQ#xO1G/hO'WQ#xO'#HdO!.sQ#xO'#HdO!.xQ&nO1G.}O!/YQ#xO,59kO!0`Q#xO,5>SO!0pQ#xO,5>SO!0xQ#xO1G/oO!0}Q&nO1G/oOOQS1G/n1G/nO!1_Q#xO,5=}O!2UQ#xO,5=}O/oQ#xO1G/sO!2sQ#xO1G/uO!2xQ&nO1G/uO!3YQ&nO1G/sOOQS1G/r1G/rOOQS1G/t1G/tOOOO-E9v-E9vOOQS1G/}1G/}OOOO-E9w-E9wO!3jQ#xO'#HwO/oQ#xO'#HwO!3xQ#xO,5:eOOOW-E9x-E9xOOQS1G0O1G0OO!4TQ#xO,5:iOOO`-E9{-E9{O!4`Q#xO,5:jOOOp-E9|-E9|O!4kQ#xO,5:kOOO!b-E9}-E9}OOQS-E:O-E:OO!4vQ!LUO1G3SO!5gQ&nO1G3SO'WQ#xO,5jOOQS1G1_1G1_O!6gQ#xO1G1_OOQS'#DX'#DXO/oQ#xO,5=yOOQS,5=y,5=yO!6lQ#xO'#FqO!6wQ#xO,59qO!7PQ#xO1G/ZO!7ZQ&nO,5=}OOQS1G3h1G3hOOQS,5:p,5:pO!7zQ#xO'#G|OOQS,5PO!8{Q#xO,5>PO/oQ#xO1G0mO/oQ#xO1G0mO0UQ#xO1G0oOOQS-E:T-E:TO!9^Q#xO1G0oO!9iQ#xO1G0oO!9nQ#xO,5>mO!9|Q#xO,5>mO!:[Q#xO,5>iO!:rQ#xO,5>iO!;TQ#{O1G0yO!>cQ#{O1G0|O!AnQ#xO,5>oO!AxQ#xO,5>oO!BQQ&nO,5>oO/oQ#xO1G1OO!B[Q#xO1G1OO3^Q#xO1G1TO! RQ#xO1G1VOOQV,5;`,5;`O!BaQ#zO,5;`O!BfQ#{O1G1PO!EwQ#xO'#G]O3^Q#xO1G1PO3^Q#xO1G1PO!FUQ#xO,5>pO!FcQ#xO,5>pO0UQ#xO,5>pOOQV1G1T1G1TO!FkQ#xO'#FRO!F|QMlO1G1VOOQV1G1[1G1[O3^Q#xO1G1[O!GUQ#xO'#F]OOQV1G1a1G1aO! `Q&nO1G1aPOOO1G3O1G3OP!GZOSO1G3OOOQS,5>V,5>VOOQS'#Dr'#DrO/oQ#xO,5>VO!G`Q#xO,5>UO!GsQ#xO,5>UOOQS1G/w1G/wO!G{Q#xO,5>XO!H]Q#xO,5>XO!HeQ#xO,5>XO!HxQ#xO,5>XO!IYQ#xO,5>XOOQS1G3r1G3rOOQS7+$j7+$jO!7PQ#xO7+$rO!J{Q#xO1G/OO!KSQ#xO1G/OOOQS1G/b1G/bOOQS,5<_,5<_O'WQ#xO,5<_OOQS7+%R7+%RO!KZQ#xO7+%ROOQS-E9q-E9qOOQS7+%S7+%SO!KkQ#xO,5>OO'WQ#xO,5>OOOQS7+$i7+$iO!KpQ#xO7+%RO!KxQ#xO7+%SO!K}Q#xO1G3nOOQS7+%Z7+%ZO!L_Q#xO1G3nO!LgQ#xO7+%ZOOQS,5<^,5<^O'WQ#xO,5<^O!LlQ#xO1G3iOOQS-E9p-E9pO!McQ#xO7+%_OOQS7+%a7+%aO!MqQ#xO1G3iO!N`Q#xO7+%aO!NeQ#xO1G3oO!NuQ#xO1G3oO!N}Q#xO7+%_O# SQ#xO,5>cO# jQ#xO,5>cO# jQ#xO,5>cO# xO$ISO'#D{O#!TO#tO'#HxOOOW1G0P1G0PO#!YQ#xO1G0POOO`1G0T1G0TO#!bQ#xO1G0TOOOp1G0U1G0UO#!jQ#xO1G0UOOO!b1G0V1G0VO#!rQ#xO1G0VO#!zQ!LUO7+(nO##kQ&nO1G2XP#$UQ#xO'#GROOQS,5d,5>dOOOW7+%k7+%kOOO`7+%o7+%oOOOp7+%p7+%pOOO!b7+%q7+%qO#7{Q#xO1G3SO#8fQ#xO1G3SP'WQ#xO'#FtO/oQ#xO<lO#9YQ#xO,5>lO0UQ#xO,5>lO#9kQ#xO,5>kOOQS<rO#AdQ#xO,5>rOOQS,5>r,5>rO#AoQ#xO,5>qO#BQQ#xO,5>qOOQS1G1X1G1XOOQS,5;o,5;oO#BYQ#xO1G1cP#B_Q#xO'#FvO#BoQ#xO1G1}O#CSQ#xO1G1}O#CdQ#xO1G1}P#CoQ#xO'#FwO#C|Q#xO7+)_O#D^Q#xO7+)_O#D^Q#xO7+)_O#DfQ#xO7+)_O#DvQ#xO7+)UO7hQ#xO7+)UOOQSAN>XAN>XO#EaQ#xO<eAN>eO/oQ#xO1G1{O#EqQ&nO1G1{P#E{Q#xO'#FuOOQS1G2R1G2RP#FYQ#xO'#F{O#FgQ#xO7+)iO#F}Q#xO,5:hOOOO-E9z-E9zO#GYQ#xO7+(nOOQSAN?_AN?_O#GsQ#xO,5QOOQSANB[ANB[OOOO7+%n7+%nOOQS7+'x7+'xO$'{Q#xO<tO$*qQ#xO,5>tO0UQ#xO,5vO#MRQ#xO,5>vOOQS1G1o1G1oO$.iQ&nO,5wO$.wQ#xO,5>wOOQS1G1r1G1rOOQS7+'R7+'RP#MRQ#xO'#GfO$/PQ#xO1G4bO$/ZQ#xO1G4bO$/cQ#xO1G4bOOQS7+%V7+%VO$/qQ#xO1G1sO$0PQ&nO'#F`O$0WQ#xO,5=POOQS,5=P,5=PO$0fQ#xO1G4cOOQS-E:c-E:cO#MRQ#xO,5=OO$0mQ#xO,5=OO$0rQ#xO7+)|OOQS-E:b-E:bO$0|Q#xO7+)|O#MRQ#xO,5e>hPP'Z'ZPP?QPP'Z'ZPP'Z'Z'Z'Z'Z?U?{'ZP@OP@UD]GyPG}HZH_HcHg'ZPPPHkHq'RP'R'RP'RP'RP'RP'RP'R'R'RP'RPP'RPP'RPHwPIOIUPIOPIOIOPPPIOPKTPK^KdKjKTPIOKpPIOPKwK}PLRLgMUMoLRLRMuNSLRLRLRLRNhNnNqNvNy! T! Z! g! y!!P!!Z!!a!!}!#T!#Z!#a!#k!#q!#w!#}!$T!$Z!$m!$w!$}!%T!%Z!%e!%k!%q!%w!&R!&X!&c!&i!&r!&x!'X!'a!'k!'rPPPPPPPPPPPPPPPPP!'x!'{!(R!([!(f!(qPPPPPPPPPPPP!-e!.y!2s!6TPP!6]!6o!6x!7n!7e!7w!7}!8Q!8T!8W!8`!9PPPPPPPPPP!9S!9cPPPP!:R!:_!:k!:q!:z!:}!;T!;Z!;a!;dP!;l!;u!pQUO,5:}OOQR,5{QYO'#HYO?dQUO,5;eOOQQ-E9x-E9xOOQR,5;d,5;dO1XQUO'#EqOOQR-E9`-E9`O?lQYO,59YOApQYO,59fOBZQUO'#GpOBfQUO'#GpO-zQUO'#GpOBqQUO'#DQOByQUO,59jOCOQUO'#GtO&qQUO'#GtO0pQUO,5=_OOQQ,5=_,5=_O0pQUO'#DwOOQQ'#Dx'#DxOCdQUO'#FnOCtQUO,58yOCtQUO,58yO(zQUO,5:eODSQYO'#GvOOQQ,5:h,5:hOOQQ,5:p,5:pODgQUO,5:sODxQUO,5:uOOQQ'#Fq'#FqOEWQYO,5:uOEfQUO,5:uOEkQUO'#H]OOQQ,5:x,5:xOEyQUO'#HXOOQQ,5:{,5:{O1^QUO,5;PO1^QUO,5;SOF[QYO'#H_O&qQUO'#H_OFfQUO,5;UO0zQUO,5;UO0pQUO,5;ZO-zQUO,5;]OFkQUO'#EfOGqQVO,5;VOJsQUO'#H`O1^QUO,5;ZOKOQUO,5;]OKTQUO,5;bOK]QYO,5;gO&qQUO,5;gPOOO,5zQUO'#FwO1^QUO1G0qO1^QUO1G0qO!?XQUO,5=zO!?fQUO,5=zO-zQUO,5=zOOQR1G0u1G0uO!?nQUO'#EsO!@PQ!dO1G0wOOQR1G0|1G0|O1^QUO1G0|O!@XQUO'#E}OOQR1G1R1G1ROK]QYO1G1RPOOO1G2a1G2aP!@^OQO1G2aOOQQ,5=h,5=hOOQQ'#Dm'#DmO0pQUO,5=hO!@cQUO,5=gO!@vQUO,5=gOOQQ1G/r1G/rO!AOQUO,5=jO!A`QUO,5=jO!AhQUO,5=jO!A{QUO,5=jO!B]QUO,5=jOOQQ1G3T1G3TOOQQ7+$e7+$eO!1[QUO7+$mO!C{QUO1G.yO!DSQUO1G.yOOQQ1G/]1G/]OOQQ,5zQUO'#FuO1^QUO7+&VO1^QUO7+&YO# rQYO,5SAN>SO#9pQUO<`AN>`O0pQUO1G1mO#:QQYO1G1mP#:[QUO'#FgO#:iQUO7+(POOQQAN?PAN?PO#;SQUO,5<^O#;hQUO1G3bOOQQ-E9p-E9pO#;yQUO1G3bOOQQ1G3a1G3aOOQRAN?]AN?]OOQR1G1{1G1{O1^QUOAN?bO#<[QVOAN?bOOQRAN?iAN?iOOQR<OO#KiQUO,5>OO-zQUO,5;pO#KzQUO,5;tO#LPQUO,5;tO#@RQUO'#HfO#LUQUO'#HfO#LZQUO,5;uOOQQ,5;v,5;vO&qQUO'#FaOOQR1G1U1G1UO1^QUO1G1UOOQQAN@aAN@aO#L`QUOG27bO#LpQUO,59zOOQQ1G2}1G2}OOQQ,5QO#@RQUO,5>QOOQQ1G1a1G1aO$ aQYO,5;{OOQR7+&p7+&pO#BOQUO1G/fO#@RQUO,5;yO$ hQUO,5>RO$ oQUO,5>ROOQQ1G1d1G1dOOQQ7+&s7+&sP#@RQUO'#GQO$ wQUO1G3lO$!RQUO1G3lO$!ZQUO1G3lOOQQ7+%Q7+%QO$!iQUO1G1eO$!wQYO'#FQO$#OQUO,5x|}#@S}!O#AW!O!P#Ci!P!Q#N_!Q!R$!y!R![$&w![!]$1e!]!^$3s!^!_$4w!_!`$7c!`!a$8m!a!b%T!b!c$;U!c!d$W!e!h$W#V#Y$Q<%lO$Xc&m!b&eS&hW%k!TOX%TXY=|Y[%T[]=|]p%Tpq=|qr%Trs&Vsw%Twx/Xx#O%T#O#P?d#P#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T#s?i[&m!bOY%TYZ=|Z]%T]^=|^#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=P;=`<%l8^<%lO%T!q@hd&m!b&eS&hWOr%Trs&Vsw%Twx/Xx!_%T!_!`Av!`#O%T#O#P7o#P#T%T#T#UBz#U#f%T#f#gBz#g#hBz#h#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T!qBR]oR&m!b&eS&hWOr%Trs&Vsw%Twx/Xx#O%T#O#P7o#P#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T!qCV]!nR&m!b&eS&hWOr%Trs&Vsw%Twx/Xx#O%T#O#P7o#P#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T#cDXa&m!b&eS&csOYE^YZ%TZ]E^]^%T^rE^rs!)|swE^wxGpx#OE^#O#P!!u#P#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!)v<%lOE^#cEia&m!b&eS&hW&csOYE^YZ%TZ]E^]^%T^rE^rsFnswE^wxGpx#OE^#O#P!!u#P#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!)v<%lOE^#cFw]&m!b&eS&csOr%Trs'Vsw%Twx/Xx#O%T#O#P7o#P#o%T#o#p8^#p#q%T#q#r8^#r;'S%T;'S;=`=v<%lO%T#cGya&m!b&hW&csOYE^YZ%TZ]E^]^%T^rE^rsFnswE^wxIOx#OE^#O#P!!u#P#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!)v<%lOE^#cIXa&m!b&hW&csOYE^YZ%TZ]E^]^%T^rE^rsFnswE^wxJ^x#OE^#O#P!!u#P#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!)v<%lOE^#_Jg_&m!b&hW&csOYJ^YZ1XZ]J^]^1X^rJ^rsKfs#OJ^#O#PL`#P#oJ^#o#pL}#p#qJ^#q#rL}#r;'SJ^;'S;=`!!o<%lOJ^#_KmZ&m!b&csOr1Xrs2ys#O1X#O#P3q#P#o1X#o#p4`#p#q1X#q#r4`#r;'S1X;'S;=`7i<%lO1X#_LeW&m!bO#oJ^#o#pL}#p#qJ^#q#rL}#r;'SJ^;'S;=`! r;=`<%lL}<%lOJ^{MUZ&hW&csOYL}YZ4`Z]L}]^4`^rL}rsMws#OL}#O#PNc#P;'SL};'S;=`! l<%lOL}{M|V&csOr4`rs5ds#O4`#O#P5y#P;'S4`;'S;=`6t<%lO4`{NfRO;'SL};'S;=`No;=`OL}{Nv[&hW&csOYL}YZ4`Z]L}]^4`^rL}rsMws#OL}#O#PNc#P;'SL};'S;=`! l;=`<%lL}<%lOL}{! oP;=`<%lL}#_! y[&hW&csOYL}YZ4`Z]L}]^4`^rL}rsMws#OL}#O#PNc#P;'SL};'S;=`! l;=`<%lJ^<%lOL}#_!!rP;=`<%lJ^#c!!zW&m!bO#oE^#o#p!#d#p#qE^#q#r!#d#r;'SE^;'S;=`!(q;=`<%l!#d<%lOE^!P!#m]&eS&hW&csOY!#dYZ8^Z]!#d]^8^^r!#drs!$fsw!#dwx!%Yx#O!#d#O#P!'Y#P;'S!#d;'S;=`!(k<%lO!#d!P!$mX&eS&csOr8^rs9rsw8^wx:dx#O8^#O#P;v#P;'S8^;'S;=`^s#O!=U#O#P!@j#P#o!=U#o#p!Ag#p#q!=U#q#r!Ag#r;'S!=U;'S;=`!FQ<%lO!=U#o!>e_U!T&m!bOY!=UYZ1XZ]!=U]^1X^r!=Urs!?ds#O!=U#O#P!@j#P#o!=U#o#p!Ag#p#q!=U#q#r!Ag#r;'S!=U;'S;=`!FQ<%lO!=U#o!?k_U!T&m!bOY!=UYZ1XZ]!=U]^1X^r!=Urs!3`s#O!=U#O#P!@j#P#o!=U#o#p!Ag#p#q!=U#q#r!Ag#r;'S!=U;'S;=`!FQ<%lO!=U#o!@q[U!T&m!bOY!=UYZ1XZ]!=U]^1X^#o!=U#o#p!Ag#p#q!=U#q#r!Ag#r;'S!=U;'S;=`!Ec;=`<%l4`<%lO!=U!]!AnZU!T&hWOY!AgYZ4`Z]!Ag]^4`^r!Agrs!Bas#O!Ag#O#P!DP#P;'S!Ag;'S;=`!E]<%lO!Ag!]!BfZU!TOY!AgYZ4`Z]!Ag]^4`^r!Agrs!CXs#O!Ag#O#P!DP#P;'S!Ag;'S;=`!E]<%lO!Ag!]!C^ZU!TOY!AgYZ4`Z]!Ag]^4`^r!Agrs!4Ys#O!Ag#O#P!DP#P;'S!Ag;'S;=`!E]<%lO!Ag!]!DUWU!TOY!AgYZ4`Z]!Ag]^4`^;'S!Ag;'S;=`!Dn;=`<%l4`<%lO!Ag!]!DsW&hWOr4`rs4zs#O4`#O#P5y#P;'S4`;'S;=`6t;=`<%l!Ag<%lO4`!]!E`P;=`<%l!Ag#o!EhW&hWOr4`rs4zs#O4`#O#P5y#P;'S4`;'S;=`6t;=`<%l!=U<%lO4`#o!FTP;=`<%l!=U#s!F_[U!T&m!bOY!+|YZ%TZ]!+|]^%T^#o!+|#o#p!GT#p#q!+|#q#r!GT#r;'S!+|;'S;=`!Mq;=`<%l8^<%lO!+|!a!G^]U!T&eS&hWOY!GTYZ8^Z]!GT]^8^^r!GTrs!HVsw!GTwx!JVx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!H^]U!T&eSOY!GTYZ8^Z]!GT]^8^^r!GTrs!IVsw!GTwx!JVx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!I^]U!T&eSOY!GTYZ8^Z]!GT]^8^^r!GTrs!5wsw!GTwx!JVx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!J^]U!T&hWOY!GTYZ8^Z]!GT]^8^^r!GTrs!HVsw!GTwx!KVx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!K^]U!T&hWOY!GTYZ8^Z]!GT]^8^^r!GTrs!HVsw!GTwx!Agx#O!GT#O#P!LV#P;'S!GT;'S;=`!Mk<%lO!GT!a!L[WU!TOY!GTYZ8^Z]!GT]^8^^;'S!GT;'S;=`!Lt;=`<%l8^<%lO!GT!a!L{Y&eS&hWOr8^rs9Qsw8^wx:dx#O8^#O#P;v#P;'S8^;'S;=`Q<%lO$TP;=`<%l$ei&m!b&eS&hW&b`%}sOr%Trs$@Ssw%Twx$C`x!Q%T!Q![$Q<%lO$Q<%lO$Q<%lO$Q<%lO$Q<%lO$ spec_identifier[value] || -1}], - tokenPrec: 7205 + skippedNodes: [0,1], + repeatNodeCount: 31, + tokenData: "#2j!aR![OX$wXY.pY[$w[].p]p$wpq.pqr0brs2Qsthswo]P!T%vSOY]!P!Q$w!Q![!?V![!d$w!d!e!@w!e!g$w!g!h!5s!h!l$w!l!m!9R!m!q$w!q!r!CP!r!z$w!z!{!ER!{#O$w#O#P-g#P#R$w#R#S!?V#S#U$w#U#V!@w#V#X$w#X#Y!5s#Y#^$w#^#_!9R#_#c$w#c#d!CP#d#l$w#l#m!ER#m;'S$w;'S;=`.j<%lO$w}!>dZ%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q![!4X![#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w}!?`g!eq%vS%yWOr$wrs%ksw$wwx)ix!O$w!O!P!>]!P!Q$w!Q![!?V![!g$w!g!h!5s!h!l$w!l!m!9R!m#O$w#O#P-g#P#R$w#R#S!?V#S#X$w#X#Y!5s#Y#^$w#^#_!9R#_;'S$w;'S;=`.j<%lO$w}!AO^%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q!R!Az!R!S!Az!S#O$w#O#P-g#P#R$w#R#S!Az#S;'S$w;'S;=`.j<%lO$w}!BT^!eq%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q!R!Az!R!S!Az!S#O$w#O#P-g#P#R$w#R#S!Az#S;'S$w;'S;=`.j<%lO$w}!CW]%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q!Y!DP!Y#O$w#O#P-g#P#R$w#R#S!DP#S;'S$w;'S;=`.j<%lO$w}!DY]!eq%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q!Y!DP!Y#O$w#O#P-g#P#R$w#R#S!DP#S;'S$w;'S;=`.j<%lO$w}!EYa%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q![!F_![!c$w!c!i!F_!i#O$w#O#P-g#P#R$w#R#S!F_#S#T$w#T#Z!F_#Z;'S$w;'S;=`.j<%lO$w}!Fha!eq%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q![!F_![!c$w!c!i!F_!i#O$w#O#P-g#P#R$w#R#S!F_#S#T$w#T#Z!F_#Z;'S$w;'S;=`.j<%lO$w!a!GvZx!T%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`!Hi!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w_!HrX%fR%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P!IhX#Ws%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P!J^]jR%vS%yWOr$wrs%ksw$wwx)ix!^$w!^!_!KV!_!`1[!`!a1[!a#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!O!K`Z%WQ%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P!L[Z%es%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`1[!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P!MW[jR%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`1[!`!a!M|!a#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!O!NVZ%XQ%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P# TZ[Q#nP%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!a#!Rb%vS%yW%s`%`sOr$wrs%ksw$wwx)ix!Q$w!Q![# v![!c$w!c!}# v!}#O$w#O#P-g#P#R$w#R#S# v#S#T$w#T#o# v#o$g$w$g;'S# v;'S;=`##Z<%lO# v!a##^P;=`<%l# v!a##lf%vS%yW%s`%`sOr$wrs#%Qsw$wwx#'bx!Q$w!Q![# v![!c$w!c!t# v!t!u#)r!u!}# v!}#O$w#O#P-g#P#R$w#R#S# v#S#T$w#T#f# v#f#g#)r#g#o# v#o$g$w$g;'S# v;'S;=`##Z<%lO# v!P#%X]%vS%tsOY3QYZ$wZ]3Q]^$w^r3Qrs#&Qsw3Qwx4vx#O3Q#O#P9k#P;'S3Q;'S;=`:|<%lO3Q!P#&XX%vS%tsOr$wrs#&tsw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$ww#&{V%vS%xsOw&}wx'ix#O&}#O#P(h#P;'S&};'S;=`)c<%lO&}!P#'i]%yW%tsOY! SYZ$wZ]! S]^$w^r! Srs!!Usw! Swx#(bx#O! S#O#P!'m#P;'S! S;'S;=`!)O<%lO! S!P#(iX%yW%tsOr$wrs%ksw$wwx#)Ux#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w{#)]V%yW%usOr*{rs+gs#O*{#O#P,f#P;'S*{;'S;=`-a<%lO*{!a#)}b%vS%yW%s`%`sOr$wrs#%Qsw$wwx#'bx!Q$w!Q![# v![!c$w!c!}# v!}#O$w#O#P-g#P#R$w#R#S# v#S#T$w#T#o# v#o$g$w$g;'S# v;'S;=`##Z<%lO# v!a#+bf%vS%yW%s`%`sOr$wrs#%Qsw$wwx#'bx!Q$w!Q![# v![!c$w!c!t# v!t!u#)r!u!}# v!}#O$w#O#P-g#P#R$w#R#S# v#S#T$w#T#U# v#U#V#)r#V#o# v#o$g$w$g;'S# v;'S;=`##Z<%lO# v!P#-PX!Us%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w_#-uX!TR%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!O#.kZ%UQ%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w}#/gX!Yq%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P#0]Z%TR%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w_#1XX!XR%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w}#1}X%_q%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w", + tokenizers: [indentation, newlines, 0, 1, 2, 3, 4, 5], + topRules: {"Script":[0,2]}, + specialized: [{term: 200, get: value => spec_identifier[value] || -1}], + tokenPrec: 6599 }) diff --git a/src/plugins/CodemirrorLanguages/Python/testPython.terms.js b/src/plugins/CodemirrorLanguages/Python/testPython.terms.js index 9157cab1c..51ac2a4da 100644 --- a/src/plugins/CodemirrorLanguages/Python/testPython.terms.js +++ b/src/plugins/CodemirrorLanguages/Python/testPython.terms.js @@ -1,68 +1,52 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. export const - printKeyword = 1, - indent = 196, - dedent = 197, - newline = 198, - blankLineStart = 199, - newlineBracketed = 200, - eof = 201, - formatString1Content = 202, - formatString1Brace = 2, - formatString1End = 203, - formatString2Content = 204, - formatString2Brace = 3, - formatString2End = 205, - formatString1lContent = 206, - formatString1lBrace = 4, - formatString1lEnd = 207, - formatString2lContent = 208, - formatString2lBrace = 5, - formatString2lEnd = 209, - Comment = 6, - Script = 7, - BinaryExpression = 10, - ParenL = 26, - ParenthesizedExpression = 27, - binaryTest = 28, - CompareOp = 31, - unaryTest = 35, - lambdaParams = 41, - VariableName = 42, - YieldExpression = 48, - TupleExpression = 51, - ComprehensionExpression = 52, - BracketL = 57, - ArrayExpression = 58, - ArrayComprehensionExpression = 59, - BraceL = 61, - DictionaryExpression = 62, - DictionaryComprehensionExpression = 63, - SetExpression = 64, - SetComprehensionExpression = 65, - ArgList = 67, - subscript = 246, - PropertyName = 71, - Number = 72, - String = 73, - FormatString = 74, - FormatConversion = 76, - TypeDef = 86, - UpdateOp = 89, - ImportStatement = 105, - importList = 265, - IfStatement = 115, - Body = 116, - TryStatement = 121, - FunctionDefinition = 127, - ParamList = 129, - ClassDefinition = 132, - Decorator = 135, - At = 136, - MatchStatement = 137, - MatchClause = 140, - LiteralPattern = 143, - AttributePattern = 149, - SequencePattern = 150, - MappingPattern = 151, - PatternArgList = 154 + indent = 176, + dedent = 177, + newline = 178, + blankLineStart = 179, + eof = 180, + Comment = 1, + Script = 2, + BinaryExpression = 5, + ParenL = 21, + ParenthesizedExpression = 22, + binaryTest = 23, + CompareOp = 26, + unaryTest = 30, + lambdaParams = 36, + VariableName = 37, + YieldExpression = 43, + TupleExpression = 46, + ComprehensionExpression = 47, + BracketL = 52, + ArrayExpression = 53, + ArrayComprehensionExpression = 54, + BraceL = 56, + DictionaryExpression = 57, + DictionaryComprehensionExpression = 58, + SetExpression = 59, + SetComprehensionExpression = 60, + ArgList = 62, + subscript = 217, + PropertyName = 66, + Number = 67, + String = 68, + TypeDef = 73, + UpdateOp = 76, + ImportStatement = 91, + importList = 229, + IfStatement = 101, + Body = 102, + TryStatement = 107, + FunctionDefinition = 113, + ParamList = 115, + ClassDefinition = 118, + Decorator = 121, + At = 122, + MatchStatement = 123, + MatchClause = 126, + LiteralPattern = 129, + AttributePattern = 135, + SequencePattern = 136, + MappingPattern = 137, + PatternArgList = 140 diff --git a/src/plugins/CodemirrorLanguages/Python/tokens.js b/src/plugins/CodemirrorLanguages/Python/tokens.js index 72b8aee6e..e7eebded8 100644 --- a/src/plugins/CodemirrorLanguages/Python/tokens.js +++ b/src/plugins/CodemirrorLanguages/Python/tokens.js @@ -1,149 +1,84 @@ -import {ExternalTokenizer, ContextTracker} from "@lezer/lr" -import { - newline as newlineToken, eof, newlineBracketed, blankLineStart, indent, dedent, printKeyword, - ParenthesizedExpression, TupleExpression, ComprehensionExpression, - PatternArgList, SequencePattern, MappingPattern, FormatString, - ArrayExpression, ArrayComprehensionExpression, ArgList, ParamList, importList, subscript, - DictionaryExpression, DictionaryComprehensionExpression, SetExpression, SetComprehensionExpression, - formatString1Content, formatString1Brace, formatString1End, - formatString2Content, formatString2Brace, formatString2End, - formatString1lContent, formatString1lBrace, formatString1lEnd, - formatString2lContent, formatString2lBrace, formatString2lEnd, - ParenL, BraceL, BracketL -} from "./testPython.terms" +/* ref: https://github.com/lezer-parser/python/blob/main/src/tokens.js */ +import { ExternalTokenizer, ContextTracker } from '@lezer/lr' -const newline = 10, carriageReturn = 13, space = 32, tab = 9, hash = 35, parenOpen = 40, dot = 46, - braceOpen = 123, singleQuote = 39, doubleQuote = 34 +import { newline as newlineToken, eof, blankLineStart, indent, dedent } from './testPython.terms' -const bracketed = new Set([ - ParenthesizedExpression, TupleExpression, ComprehensionExpression, importList, ArgList, ParamList, - ArrayExpression, ArrayComprehensionExpression, subscript, - SetExpression, SetComprehensionExpression, FormatString, - DictionaryExpression, DictionaryComprehensionExpression, - SequencePattern, MappingPattern, PatternArgList -]) +const newline = 10, + carriageReturn = 13, + space = 32, + tab = 9 function isLineBreak(ch) { - return ch == newline || ch == carriageReturn + return ch == newline || ch == carriageReturn } -export const newlines = new ExternalTokenizer((input, stack) => { - let prev - if (input.next < 0) { - input.acceptToken(eof) - } else if (stack.context.depth < 0) { - if (isLineBreak(input.next)) input.acceptToken(newlineBracketed, 1) - } else if (((prev = input.peek(-1)) < 0 || isLineBreak(prev)) && - stack.canShift(blankLineStart)) { - let spaces = 0 - while (input.next == space || input.next == tab) { input.advance(); spaces++ } - if (input.next == newline || input.next == carriageReturn || input.next == hash) - input.acceptToken(blankLineStart, -spaces) - } else if (isLineBreak(input.next)) { - input.acceptToken(newlineToken, 1) - } -}, {contextual: true}) +export const newlines = new ExternalTokenizer( + (input, stack) => { + let prev + if (input.next < 0) { + input.acceptToken(eof) + } else if (((prev = input.peek(-1)) < 0 || isLineBreak(prev)) && stack.canShift(blankLineStart)) { + let spaces = 0 + while (input.next == space || input.next == tab) { + input.advance() + spaces++ + } + if (input.next == newline || input.next == carriageReturn) input.acceptToken(blankLineStart, -spaces) + } else if (isLineBreak(input.next)) { + input.acceptToken(newlineToken, 1) + } + }, + { contextual: true } +) export const indentation = new ExternalTokenizer((input, stack) => { - let cDepth = stack.context.depth - if (cDepth < 0) return - let prev = input.peek(-1), depth - if (prev == newline || prev == carriageReturn) { - let depth = 0, chars = 0 - for (;;) { - if (input.next == space) depth++ - else if (input.next == tab) depth += 8 - (depth % 8) - else break - input.advance() - chars++ - } - if (depth != cDepth && - input.next != newline && input.next != carriageReturn && input.next != hash) { - if (depth < cDepth) input.acceptToken(dedent, -chars) - else input.acceptToken(indent) + let cDepth = stack.context.depth + if (cDepth < 0) return + let prev = input.peek(-1), + depth + if (prev == newline || prev == carriageReturn) { + let depth = 0, + chars = 0 + for (;;) { + if (input.next == space) depth++ + else if (input.next == tab) depth += 8 - (depth % 8) + else break + input.advance() + chars++ + } + if (depth != cDepth && input.next != newline && input.next != carriageReturn) { + if (depth < cDepth) input.acceptToken(dedent, -chars) + else input.acceptToken(indent) + } } - } }) function IndentLevel(parent, depth) { - this.parent = parent - // -1 means this is not an actual indent level but a set of brackets - this.depth = depth - this.hash = (parent ? parent.hash + parent.hash << 8 : 0) + depth + (depth << 4) + this.parent = parent + // -1 means this is not an actual indent level but a set of brackets + this.depth = depth + this.hash = (parent ? (parent.hash + parent.hash) << 8 : 0) + depth + (depth << 4) } const topIndent = new IndentLevel(null, 0) function countIndent(space) { - let depth = 0 - for (let i = 0; i < space.length; i++) - depth += space.charCodeAt(i) == tab ? 8 - (depth % 8) : 1 - return depth + let depth = 0 + for (let i = 0; i < space.length; i++) depth += space.charCodeAt(i) == tab ? 8 - (depth % 8) : 1 + return depth } export const trackIndent = new ContextTracker({ - start: topIndent, - reduce(context, term) { - return context.depth < 0 && bracketed.has(term) ? context.parent : context - }, - shift(context, term, stack, input) { - if (term == indent) return new IndentLevel(context, countIndent(input.read(input.pos, stack.pos))) - if (term == dedent) return context.parent - if (term == ParenL || term == BracketL || term == BraceL) return new IndentLevel(context, -1) - return context - }, - hash(context) { return context.hash } -}) - -export const legacyPrint = new ExternalTokenizer(input => { - for (let i = 0; i < 5; i++) { - if (input.next != "print".charCodeAt(i)) return - input.advance() - } - if (/\w/.test(String.fromCharCode(input.next))) return - for (let off = 0;; off++) { - let next = input.peek(off) - if (next == space || next == tab) continue - if (next != parenOpen && next != dot && next != newline && next != carriageReturn && next != hash) - input.acceptToken(printKeyword) - return - } + start: topIndent, + reduce(context) { + return context.depth < 0 ? context.parent : context + }, + shift(context, term, stack, input) { + if (term == indent) return new IndentLevel(context, countIndent(input.read(input.pos, stack.pos))) + if (term == dedent) return context.parent + return context + }, + hash(context) { + return context.hash + }, }) - -function formatString(quote, len, content, brace, end) { - return new ExternalTokenizer(input => { - let start = input.pos - for (;;) { - if (input.next < 0) { - break - } else if (input.next == braceOpen) { - if (input.peek(1) == braceOpen) { - input.advance(2) - } else { - if (input.pos == start) { - input.acceptToken(brace, 1) - return - } - break - } - } else if (input.next == "\\") { - input.advance() - if (input.next >= 0) input.advance() - } else if (input.next == quote && (len == 1 || input.peek(1) == quote && input.peek(2) == quote)) { - if (input.pos == start) { - input.acceptToken(end, len) - return - } - break - } else { - input.advance() - } - } - if (input.pos > start) input.acceptToken(content) - }) -} - -export const formatString1 = formatString(singleQuote, 1, formatString1Content, formatString1Brace, formatString1End) -export const formatString2 = formatString(doubleQuote, 1, formatString2Content, formatString2Brace, formatString2End) -export const formatString1l = formatString(singleQuote, 3, formatString1lContent, formatString1lBrace, formatString1lEnd) -export const formatString2l = formatString(doubleQuote, 3, formatString2lContent, formatString2lBrace, formatString2lEnd) From 9a89b548836a74c90efccd94aa32ded296a4520a Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Thu, 25 May 2023 15:47:40 +0200 Subject: [PATCH 06/16] refactored files --- src/components/inputs/Codemirror.vue | 20 -- .../lang/klipperConfig.ts | 19 +- .../KlipperConfigLanguage/lang/lint.ts | 23 +- .../KlipperConfigLanguage/parser/highlight.js | 29 +- .../parser/klipperConfig.grammar | 32 +- .../parser/klipperConfigParser.js | 14 +- .../parser/klipperConfigParser.terms.js | 25 +- .../CodemirrorLanguages/Python/highlight.js | 34 -- .../CodemirrorLanguages/Python/index.ts | 18 - .../Python/testPython.grammar | 320 ------------------ .../CodemirrorLanguages/Python/testPython.js | 28 -- .../Python/testPython.terms.js | 52 --- .../CodemirrorLanguages/Python/tokens.js | 84 ----- .../CodemirrorLanguages/printLezerTree.ts | 246 -------------- 14 files changed, 53 insertions(+), 891 deletions(-) delete mode 100644 src/plugins/CodemirrorLanguages/Python/highlight.js delete mode 100644 src/plugins/CodemirrorLanguages/Python/index.ts delete mode 100644 src/plugins/CodemirrorLanguages/Python/testPython.grammar delete mode 100644 src/plugins/CodemirrorLanguages/Python/testPython.js delete mode 100644 src/plugins/CodemirrorLanguages/Python/testPython.terms.js delete mode 100644 src/plugins/CodemirrorLanguages/Python/tokens.js delete mode 100644 src/plugins/CodemirrorLanguages/printLezerTree.ts diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index e9c966f37..5c90d7df6 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -14,19 +14,14 @@ import { EditorView, keymap } from '@codemirror/view' import { EditorState } from '@codemirror/state' import { vscodeDark } from '@uiw/codemirror-theme-vscode' import { StreamLanguage } from '@codemirror/language' -import { klipper_config } from '@/plugins/StreamParserKlipperConfig' import { gcode } from '@/plugins/StreamParserGcode' import { indentWithTab } from '@codemirror/commands' import { json } from '@codemirror/lang-json' import { css } from '@codemirror/lang-css' import { klipperConfig } from '../../plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig' import { klipperConfigLint } from '../../plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint' -import { python } from '../../plugins/CodemirrorLanguages/Python/index' -import { logTree } from '../../plugins/CodemirrorLanguages/printLezerTree' import { indentUnit } from '@codemirror/language' -import {syntaxTree} from "@codemirror/language" - @Component export default class Codemirror extends Mixins(BaseMixin) { private content = '' @@ -55,20 +50,6 @@ export default class Codemirror extends Mixins(BaseMixin) { if (newVal !== cm_value) { this.setCmValue(newVal) } - const state = this.cminstance.state - logTree( syntaxTree(state), state.doc.toString() ) - /* const state = this.cminstance.state - syntaxTree(state).iterate({ - enter: (node) => { - if (node.from >= 3600 && node.name != "BlockBody" && node.name != "Block") { - if (node.name === "BodyLine") { - console.log("-- " + state.doc.lineAt(node.from).text + " ----------------") - } else { - console.log(node.name + " (" + state.doc.sliceString(node.from, node.to)+ ")") - } - } - }} - ) */ } mounted(): void { @@ -119,7 +100,6 @@ export default class Codemirror extends Mixins(BaseMixin) { if (['cfg', 'conf'].includes(this.fileExtension)) extensions.push(klipperConfig()) else if (['gcode'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(gcode)) else if (['json'].includes(this.fileExtension)) extensions.push(json()) - else if (['py'].includes(this.fileExtension)) extensions.push(python()) else if (['css', 'scss', 'sass'].includes(this.fileExtension)) extensions.push(css()) return extensions diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts index fe877a493..83b982ebd 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts @@ -1,12 +1,5 @@ import { parser } from '../parser/klipperConfigParser.js' -import { - LRLanguage, - LanguageSupport, - StreamLanguage, - foldNodeProp, - continuedIndent, - indentNodeProp, -} from '@codemirror/language' +import { LRLanguage, LanguageSupport, StreamLanguage, foldNodeProp } from '@codemirror/language' import { parseMixed } from '@lezer/common' import { klipper_config } from '../../../StreamParserKlipperConfig' import { klipperConfigCompletionSource } from './complete.js' @@ -16,23 +9,16 @@ const jinja2Parser = StreamLanguage.define(klipper_config).parser export const klipperConfigLang = LRLanguage.define({ parser: parser.configure({ props: [ - indentNodeProp.add({ - GcodeKeyword: continuedIndent(), - Jinja2: continuedIndent(), - Parameter: () => null, - }), foldNodeProp.add({ ConfigBlock(tree) { let body = tree.lastChild if (body == null) return null - let lastOption = body.lastChild if (lastOption == null) return null - while (lastOption.name == 'Comment' || lastOption.name == 'BlankLine') { + while (lastOption.name == 'Comment') { lastOption = lastOption.prevSibling if (lastOption == null) return null } - return { from: body.from - 1, to: lastOption.to - 1 } }, }), @@ -43,7 +29,6 @@ export const klipperConfigLang = LRLanguage.define({ }), languageData: { commentTokens: { line: '#' }, - indentOnInput: /^\s*(gcode:)$/, }, }) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts index 5424e8cb4..2972eca09 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts @@ -6,30 +6,13 @@ export const klipperConfigLint = linter((view) => { syntaxTree(view.state) .cursor() .iterate((node) => { - if (node.name == '') { + if (node.type.isError) { diagnostics.push({ from: node.from, to: node.to, - severity: 'warning', - message: 'Numbers are bad', - actions: [ - { - name: 'Remove', - apply(view, from, to) { - view.dispatch({ changes: { from, to } }) - }, - }, - ], + severity: 'error', + message: 'Parse error: ' + JSON.stringify(view.state.sliceDoc(node.from, node.to)), }) - } else { - if (node.type.isError) { - diagnostics.push({ - from: node.from, - to: node.to, - severity: 'error', - message: 'Parse error: ' + JSON.stringify(view.state.sliceDoc(node.from, node.to)), - }) - } } }) return diagnostics diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js index 975f419b4..2c5c2d59e 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js @@ -1,24 +1,23 @@ import { styleTags, tags as t } from '@lezer/highlight' export const klipperConfigHighlighting = styleTags({ - ImportKeyword: t.keyword, Import: t.keyword, - ConfigBlock: t.namespace, - BlockType: t.namespace, - - Parameter: t.keyword, + ImportKeyword: t.keyword, + Parameter: t.variableName, + ConfigBlock: t.keyword, + BlockType: t.keyword, + Identifier: t.regexp, - Identifier: t.attributeName, - Comment: t.lineComment, - AutoGenerated: t.name, - Boolean: t.string, String: t.string, + Boolean: t.bool, Number: t.number, Cords: t.number, - Pin: t.atom, - Pins: t.atom, - VirtualPin: t.atom, - FilePath: t.className, - Path: t.className, - File: t.className, + Pin: t.namespace, + VirtualPin: t.namespace, + Path: t.string, + File: t.string, + FilePath: t.string, + + AutoGenerated: t.regexp, + Comment: t.lineComment, }) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar index e4660e99e..50593bd19 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar @@ -2,6 +2,11 @@ @skip { Comment newline? | AutoGenerated newline | space | blankLine } +valueBlock { indent (content newline | valueBlock)+ (dedent | eof) } +sep { content (seperator content)+ } + + + Import { "[" ImportKeyword (FilePath | File) "]" newline } ConfigBlock {"[" BlockType Identifier? "]" newline Body } @@ -11,18 +16,15 @@ Option { Parameter ":" Value | GcodeKeyword ":" Jinja2 } Value { value (newline | eof) | newline valueBlock } Jinja2 { jinja2 (newline | eof) | newline valueBlock } -valueBlock { indent (content newline | valueBlock)+ (dedent | eof) } - -value { Pin | Pins | VirtualPin | Cords | Number | String | Boolean | FilePath | Path } -Pin { pin } -Pins { pin ("," pin)+ } +value { Pin | pins | VirtualPin | VirtualPin | Cords | Number | String | Boolean | Path | FilePath } +pins { sep } +VirtualPin { string ":" string } +Cords { sep } Number { number } String { string } -Cords { number ("," number)+ } -VirtualPin { string ":" string } -Path { "/"? (string "/")+ string } -FilePath { Path "." string} File {string "." string } +Path { "/"? sep } +FilePath { Path "." string} @@ -33,6 +35,7 @@ File {string "." string } @tokens { ImportKeyword{ "include" } GcodeKeyword{ "gcode" } + BlockType { $[a-zA-Z0-9_]+ } Identifier { $[a-zA-Z0-9_.\-]+ } Parameter { $[a-zA-Z0-9_]+ } @@ -40,13 +43,7 @@ File {string "." string } jinja2 { $[ \ta-zA-Z0-9_.\-"'{}%=]+ } number { "-"? $[0-9]+ ("." $[0-9]*)? } Boolean { "True" | "False" } - pin { ("^" | "~")? "!"? "P" $[A-Z] $[0-9]+ } - - BlockType { - "mcu" | "printer" | "extruder" | "adxl345" | "resonance_tester" | "stepper_x" | "stepper_y" | "stepper_z" | - "stepper_z1" | "z_tilt" | "heater_bed" | "probe" | "bed_mesh" | "screws_tilt_adjust" | "temperature_sensor" | - "fan" | "heater_fan" | "controller_fan" | "static_digital_output" | "tmc2209" | "tmc2208" | "homing_override" - } + Pin { ("^" | "~")? "!"? "P" $[A-Z] $[0-9]+ } AutoGenerated { "#*#" ![\n\r]* } Comment { "#" ![\n\r]* } @@ -55,7 +52,8 @@ File {string "." string } @precedence { space, jinja2, string} @precedence { AutoGenerated, Comment } - @precedence { number, pin, Boolean, ImportKeyword, string } + @precedence { number, Pin, Boolean, ImportKeyword, string } + @precedence { ImportKeyword, BlockType} @precedence { GcodeKeyword, Parameter} } diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js index 676f64b12..487f7d530 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js @@ -4,17 +4,17 @@ import {indentation, newlines, trackIndent} from "./tokens.js" import {klipperConfigHighlighting} from "./highlight" export const parser = LRParser.deserialize({ version: 14, - states: "+pOcQUOOPhOSOOOpQUO'#C`OOQQ'#Cu'#CuOcQUOOOOQQ'#Cw'#CwQxQUOOP}OQO)C>yO!SQYO,58zO![QbO,59POOQQ-E6s-E6sOsQUO'#CeOOQQ-E6u-E6uPOOO/'4e/'4eO!dQUO'#CvO!lQYO'#CcO!qQYO'#CcO!vQUO'#CbO!{QUO1G.fO#QQUO1G.kO#VQUO1G.kP#[QUO'#C`OOQQ,59b,59bO#aQYO,59OO#fQUO,58}OOQQ-E6t-E6tO#tQUO'#CvO#yQYO,58}O$OQYO,58|O$TQUO7+$QO$YQrO7+$VO$bQUO7+$VOOQQ1G.j1G.jO$gQUO1G.iOOQQ1G.h1G.hOOQQ<xO!SQYO,58zO![QbO,59POOQQ-E6r-E6rOsQUO'#CeOOQQ-E6t-E6tPOOO/'4d/'4dO!dQUO'#CbO!iQUO'#CcO!qQUO1G.fO!vQYO'#CcO!{QUO1G.kO#QQUO1G.kP#VQUO'#C`O#[QYO,58|O#aQYO'#CuO#fQUO,58}O#tQYO,59OO#yQUO7+$QO$OQUO,58}O$TQrO7+$VO$]QUO7+$VOOQQ1G.h1G.hOOQQ,59a,59aOOQQ-E6s-E6sOOQQ1G.j1G.jOOQQ<w!w!}3v!}#OAc#P#QAh#Q#RAm#R#S3v#T#UAv#U#VJq#V#W!%j#W#X3v#X#Y!6Q#Y#Z!3i#Z#[!?P#[#]!E`#]#^#3g#^#a3v#a#b#|#e#f3v#f#g#Eg#g#h$&p#h#i%.S#i#n3v#n#o%Hy#o#p%m#q#r%m#r#sAm~$`_x~!U`XY$X[]%_pq$Xrs%muv%mwx%m}!O%m!O!P%m!Q![%m!_!`%m!c!}%m#R#S%m#T#o%m#o#p%m#q#r%m~%dRx~XY%_[]%_pq%_`%r^!U`XY%mpq%mrs%muv%mwx%m}!O%m!O!P%m!Q![%m!_!`%m!c!}%m#R#S%m#T#o%m#o#p%m#q#r%m~&w_x~!U`{QXY$X[]%_pq&nrs%muv%mwx%m}!O'v!O!P%m!Q!['v!_!`%m!c!}'v#R#S'v#T#o'v#o#p%m#q#r%mb'}^!U`{QXY%mpq'vrs%muv%mwx%m}!O'v!O!P%m!Q!['v!_!`%m!c!}'v#R#S'v#T#o'v#o#p%m#q#r%mR(|P!r!s)PR)SP!c!})VR)YP!Q![)]R)bP!QR!Q![)]~)jVP~OY*PZ]*P^z*Pz{*k{;'S*P;'S;=`*e<%lO*P~*UTP~OY*PZ]*P^;'S*P;'S;=`*e<%lO*P~*hP;=`<%l*P~*pVP~OY*PZ]*P^s*Pst+Vt;'S*P;'S;=`*e<%lO*P~+^TQ~P~OY+VZ]+V^;'S+V;'S;=`+m<%lO+V~+pP;=`<%l+V~+xO!R~g,R^ZS!U`{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![/V!_!`%m!c!},}#R#S,}#T#o,}#o#p%m#q#r%mf-W^ZS!U`{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![,}!_!`%m!c!},}#R#S,}#T#o,}#o#p%m#q#r%md.Z^ZS!U`XY%mpq%mrs%muv%mwx%m}!O.S!O!P.S!Q![.S!_!`%m!c!}.S#R#S.S#T#o.S#o#p%m#q#r%mg/b^ZS!U`!SR{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P0^!Q![/V!_!`%m!c!},}#R#S,}#T#o,}#o#p%m#q#r%mg0g^ZS!U`!SRXY%mpq%mrs%muv%mwx%m}!O.S!O!P.S!Q![0^!_!`%m!c!}.S#R#S.S#T#o.S#o#p%m#q#r%me1l^|PZS!U`XY%mpq%mrs%muv%mwx%m}!O.S!O!P.S!Q![.S!_!`%m!c!}.S#R#S.S#T#o.S#o#p%m#q#r%m~2mOz~o2z^ZS!U`^W!SR{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P0^!Q![2m!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mn4R^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%m~5SO!O~n5__ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#U6^#U#o3v#o#p%m#q#r%mn6i`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#`3v#`#a7k#a#o3v#o#p%m#q#r%mn7v`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#g3v#g#h8x#h#o3v#o#p%m#q#r%mn9T`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y:V#Y#o3v#o#p%m#q#r%mn:d^ZS!U`^WfQ{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo;k^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}{#i#o3v#o#p%m#q#r%mo$?W`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#]3v#]#^$@Y#^#o3v#o#p%m#q#r%mo$@e`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#V3v#V#W$Ag#W#o3v#o#p%m#q#r%mo$Ar^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S$Bn#T#o3v#o#p%m#q#r%mo$By`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#W3v#W#X$C{#X#o3v#o#p%m#q#r%mo$DW`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#]3v#]#^$EY#^#o3v#o#p%m#q#r%mo$Ee`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#Z3v#Z#[$Fg#[#o3v#o#p%m#q#r%mo$Fr`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#]3v#]#^$Gt#^#o3v#o#p%m#q#r%mo$HP`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#h3v#h#i$IR#i#o3v#o#p%m#q#r%mo$I^_ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#U$J]#U#o3v#o#p%m#q#r%mo$Jh`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#`3v#`#a$Kj#a#o3v#o#p%m#q#r%mo$Ku^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S$Lq#T#o3v#o#p%m#q#r%mo$L|`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#c3v#c#d$NO#d#o3v#o#p%m#q#r%mo$NZ`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#i3v#i#j% ]#j#o3v#o#p%m#q#r%mo% h`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#h3v#h#i%!j#i#o3v#o#p%m#q#r%mo%!u`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#d3v#d#e%#w#e#o3v#o#p%m#q#r%mo%$S`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#i3v#i#j$;P#j#o3v#o#p%m#q#r%mo%%a`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#d3v#d#e%&c#e#o3v#o#p%m#q#r%mo%&n`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#d3v#d#e%'p#e#o3v#o#p%m#q#r%mo%'{`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y%(}#Y#o3v#o#p%m#q#r%mo%)Y`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#f3v#f#g%*[#g#o3v#o#p%m#q#r%mo%*g^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S%+c#T#o3v#o#p%m#q#r%mo%+naZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#l3v#l#mIh#m#nIh#n#o%,s#o#p%m#q#r%mo%-Q`YPZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!R3v!R!SIh!S![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%._bZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y%/g#Y#a3v#a#b%Bi#b#o3v#o#p%m#q#r%mo%/r`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#a3v#a#b%0t#b#o3v#o#p%m#q#r%mo%1P`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#d3v#d#e%2R#e#o3v#o#p%m#q#r%mo%2^`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y%3`#Y#o3v#o#p%m#q#r%mo%3k`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#f3v#f#g%4m#g#o3v#o#p%m#q#r%mo%4x_ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#U%5w#U#o3v#o#p%m#q#r%mo%6S`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#h3v#h#i%7U#i#o3v#o#p%m#q#r%mo%7a`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#i3v#i#j%8c#j#o3v#o#p%m#q#r%mo%8n`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#f3v#f#g%9p#g#o3v#o#p%m#q#r%mo%9{`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#X3v#X#Y%:}#Y#o3v#o#p%m#q#r%mo%;Y^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S%p#Y#o3v#o#p%m#q#r%mo%>{`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#b3v#b#c%?}#c#o3v#o#p%m#q#r%mo%@Y`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#g3v#g#h%A[#h#o3v#o#p%m#q#r%mo%Ag`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#c3v#c#d!=r#d#o3v#o#p%m#q#r%mo%Bt`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#V3v#V#W%Cv#W#o3v#o#p%m#q#r%mo%DR`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!S3v!S!T%ET!T![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%E``ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!S3v!S!T%Fb!T![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%Fm_ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!R%Gl!R![3v!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%Gw`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q!Y3v!Y!ZIh!Z![Ih!_!`%m!c!}3v#R#S3v#T#o3v#o#p%m#q#r%mo%IU^ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S%JQ#T#o3v#o#p%m#q#r%mo%J]`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#h3v#h#i%K_#i#o3v#o#p%m#q#r%mo%Kj`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#]3v#]#^%Ll#^#o3v#o#p%m#q#r%mo%Lw`ZS!U`^W{QXY%mpq'vrs%muv%mwx%m}!O,}!O!P.S!Q![3v!_!`%m!c!}3v#R#S3v#T#`3v#`#a$;P#a#o3v#o#p%m#q#r%m", + tokenData: "!#W~RrXY#][]$cpq%rqr'}rs$qst(iuv$qwx$q|}*w}!O*|!O!P0g!P!Q1l!Q![1q![!]4V!_!`$q!c!h2|!h!i4[!i!r2|!r!s:r!s!v2|!v!w>a!w!}2|!}#OAP#P#QAU#Q#RAZ#R#S2|#T#Z2|#Z#[Ad#[#]2|#]#^G}#^#o2|#o#p$q#q#r$q#r#sAZ~#d_w~!S`XY#][]$cpq#]rs$quv$qwx$q}!O$q!O!P$q!Q![$q!_!`$q!c!}$q#R#S$q#T#o$q#o#p$q#q#r$q~$hRw~XY$c[]$cpq$c`$v^!S`XY$qpq$qrs$quv$qwx$q}!O$q!O!P$q!Q![$q!_!`$q!c!}$q#R#S$q#T#o$q#o#p$q#q#r$q~%{_w~!S`zQXY#][]$cpq%rrs$quv$qwx$q}!O&z!O!P$q!Q![&z!_!`$q!c!}&z#R#S&z#T#o&z#o#p$q#q#r$qb'R^!S`zQXY$qpq&zrs$quv$qwx$q}!O&z!O!P$q!Q![&z!_!`$q!c!}&z#R#S&z#T#o&z#o#p$q#q#r$qQ(QP!r!s(TQ(WP!c!}(ZQ(^P!Q![(aQ(fP`Q!Q![(a~(nVP~OY)TZ])T^z)Tz{)o{;'S)T;'S;=`)i<%lO)T~)YTP~OY)TZ])T^;'S)T;'S;=`)i<%lO)T~)lP;=`<%l)T~)tVP~OY)TZ])T^s)Tst*Zt;'S)T;'S;=`)i<%lO)T~*bTQ~P~OY*ZZ]*Z^;'S*Z;'S;=`*q<%lO*Z~*tP;=`<%l*Z~*|O!P~f+V^ZS!S`zQXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![.Z!_!`$q!c!},R#R#S,R#T#o,R#o#p$q#q#r$qf,[^ZS!S`zQXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![,R!_!`$q!c!},R#R#S,R#T#o,R#o#p$q#q#r$qd-_^ZS!S`XY$qpq$qrs$quv$qwx$q}!O-W!O!P-W!Q![-W!_!`$q!c!}-W#R#S-W#T#o-W#o#p$q#q#r$qf.f^ZS!S`!QQzQXY$qpq&zrs$quv$qwx$q}!O,R!O!P/b!Q![.Z!_!`$q!c!},R#R#S,R#T#o,R#o#p$q#q#r$qf/k^ZS!S`!QQXY$qpq$qrs$quv$qwx$q}!O-W!O!P-W!Q![/b!_!`$q!c!}-W#R#S-W#T#o-W#o#p$q#q#r$qe0p^{PZS!S`XY$qpq$qrs$quv$qwx$q}!O-W!O!P-W!Q![-W!_!`$q!c!}-W#R#S-W#T#o-W#o#p$q#q#r$q~1qOy~o2Q^ZS!S`^W!QQzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P/b!Q![1q!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$qo3Z^ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$q~4[O}~o4i_ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#U5h#U#o2|#o#p$q#q#r$qo5u`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#`2|#`#a6w#a#o2|#o#p$q#q#r$qo7U`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#g2|#g#h8W#h#o2|#o#p$q#q#r$qo8e`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#X2|#X#Y9g#Y#o2|#o#p$q#q#r$qo9v^ZS!S`^WeQzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$qo;P^ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!};{#R#S2|#T#o2|#o#p$q#q#r$qon`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#f2|#f#g?p#g#o2|#o#p$q#q#r$qo?}`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#i2|#i#j8W#j#o2|#o#p$q#q#r$q~AUOx~~AZO|~QA^Qqr'}!r!s(ToAq`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#V2|#V#WBs#W#o2|#o#p$q#q#r$qoCQ`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#c2|#c#dDS#d#o2|#o#p$q#q#r$qoDa`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#W2|#W#XEc#X#o2|#o#p$q#q#r$qoEp`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#X2|#X#YFr#Y#o2|#o#p$q#q#r$qoGR^ZS!S`fW^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$qoH[`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#b2|#b#cI^#c#o2|#o#p$q#q#r$qoIk`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#V2|#V#WJm#W#o2|#o#p$q#q#r$qoJz`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#`2|#`#aK|#a#o2|#o#p$q#q#r$qoLZ`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#i2|#i#jM]#j#o2|#o#p$q#q#r$qoMj`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#W2|#W#XNl#X#o2|#o#p$q#q#r$qoNy`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#X2|#X#Y! {#Y#o2|#o#p$q#q#r$qo!![^ZS!S`^WTPzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$q", tokenizers: [indentation, newlines, 0, 1, 2, 3, 4], topRules: {"Program":[0,3]}, - tokenPrec: 393 + tokenPrec: 388 }) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js index 4b50d17a6..c77048c75 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js @@ -1,10 +1,10 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. export const - indent = 34, - dedent = 35, - newline = 36, - blankLine = 37, - eof = 38, + indent = 33, + dedent = 34, + newline = 35, + blankLine = 36, + eof = 37, Comment = 1, AutoGenerated = 2, Program = 3, @@ -21,11 +21,10 @@ export const Parameter = 14, Value = 15, Pin = 16, - Pins = 17, - VirtualPin = 18, - Cords = 19, - Number = 20, - String = 21, - Boolean = 22, - GcodeKeyword = 23, - Jinja2 = 24 + VirtualPin = 17, + Cords = 18, + Number = 19, + String = 20, + Boolean = 21, + GcodeKeyword = 22, + Jinja2 = 23 diff --git a/src/plugins/CodemirrorLanguages/Python/highlight.js b/src/plugins/CodemirrorLanguages/Python/highlight.js deleted file mode 100644 index 65547d9c3..000000000 --- a/src/plugins/CodemirrorLanguages/Python/highlight.js +++ /dev/null @@ -1,34 +0,0 @@ -import {styleTags, tags as t} from "@lezer/highlight" - -export const pythonHighlighting = styleTags({ - "async \"*\" \"**\" FormatConversion FormatSpec": t.modifier, - "for while if elif else try except finally return raise break continue with pass assert await yield match case": t.controlKeyword, - "in not and or is del": t.operatorKeyword, - "from def class global nonlocal lambda": t.definitionKeyword, - import: t.moduleKeyword, - "with as print": t.keyword, - Boolean: t.bool, - None: t.null, - VariableName: t.variableName, - "CallExpression/VariableName": t.function(t.variableName), - "FunctionDefinition/VariableName": t.function(t.definition(t.variableName)), - "ClassDefinition/VariableName": t.definition(t.className), - PropertyName: t.propertyName, - "CallExpression/MemberExpression/PropertyName": t.function(t.propertyName), - Comment: t.lineComment, - Number: t.number, - String: t.string, - FormatString: t.special(t.string), - UpdateOp: t.updateOperator, - "ArithOp!": t.arithmeticOperator, - BitOp: t.bitwiseOperator, - CompareOp: t.compareOperator, - AssignOp: t.definitionOperator, - Ellipsis: t.punctuation, - At: t.meta, - "( )": t.paren, - "[ ]": t.squareBracket, - "{ }": t.brace, - ".": t.derefOperator, - ", ;": t.separator -}) diff --git a/src/plugins/CodemirrorLanguages/Python/index.ts b/src/plugins/CodemirrorLanguages/Python/index.ts deleted file mode 100644 index fbd219d4a..000000000 --- a/src/plugins/CodemirrorLanguages/Python/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { parser } from './testPython.js' -import { LRLanguage, LanguageSupport } from '@codemirror/language' - -export const testPython = LRLanguage.define({ - parser: parser, - languageData: { - commentTokens: { line: '#' }, - }, -}) - -export function python() { - return new LanguageSupport(testPython) -} - -/* -to generate the parser run: -npx @lezer/generator testPython.grammar -o testPython.js - */ diff --git a/src/plugins/CodemirrorLanguages/Python/testPython.grammar b/src/plugins/CodemirrorLanguages/Python/testPython.grammar deleted file mode 100644 index 4f30091da..000000000 --- a/src/plugins/CodemirrorLanguages/Python/testPython.grammar +++ /dev/null @@ -1,320 +0,0 @@ -@precedence { - cond, - trail, - power @right, - prefix, - times @left, - plus @left, - shift @left, - bitand @left, - xor @left, - bitor @left, - compare @left, - as @left, - and @left, - or @left -} - -@top Script { statement+ } - -@skip { space | Comment | blankLine } - -Decorator { At dottedName ArgList? newline } - -FunctionDefinition { - kw<"async">? kw<"def"> VariableName - ParamList - TypeDef { "->" test }? - Body -} - -ParamList { "(" commaSep? ")" } - -MatchStatement { - skw<"match"> "*"? expression MatchBody { ":" newline indent MatchClause+ (dedent | eof) } -} - -MatchClause { - skw<"case"> commaSep Guard { kw<"if"> expression }? Body -} - -pattern[@isGroup=Pattern] { - CapturePattern { VariableName } | - LiteralPattern | - AsPattern { pattern !as kw<"as"> VariableName } | - OrPattern { pattern (!or LogicOp{"|"} pattern)+ } | - AttributePattern | - SequencePattern | - MappingPattern | - StarPattern { "*" !prefix pattern } | - ClassPattern { (VariableName | AttributePattern) PatternArgList } -} - -AttributePattern { VariableName ("." PropertyName)+ } - -LiteralPattern { - ArithOp{"-"}? Number (ArithOp{"+"|"-"} Number)? | - String | - kw<"None"> | - @specialize[@name=Boolean] -} - -PatternArgList { "(" commaSep "]" | "(" commaSep ")" } - -MappingPattern { "{" commaSep<"**" pattern | (VariableName | LiteralPattern) ":" pattern> "}" } - -ClassDefinition { kw<"class"> VariableName ArgList? Body } - -param { VariableName TypeDef? (AssignOp{"="} test)? | "*" VariableName? | "**" VariableName | "/" } - -TypeDef { ":" test } - -statement[@isGroup=Statement] { simpleStatement | compoundStatement } - -simpleStatement { - smallStatement (newline | eof) | - StatementGroup { smallStatement (";" smallStatement?)+ (newline | eof) } -} - -smallStatement { - AssignStatement { expressions (TypeDef? (AssignOp{"="} (YieldExpression | expressions))+ | TypeDef) } | - UpdateStatement { expressions UpdateOp (YieldExpression | commaSep) } | - ExpressionStatement { expressions } | - DeleteStatement { kw<"del"> commaSep } | - PassStatement { kw<"pass"> } | - BreakStatement { kw<"break"> } | - ContinueStatement { kw<"continue"> } | - ReturnStatement { kw<"return"> commaSep? } | - YieldStatement { yield } | - RaiseStatement { kw<"raise"> (test (kw<"from"> test | ("," test ("," test)?))?)? } | - ImportStatement | - ScopeStatement { (kw<"global"> | kw<"nonlocal">) commaSep } | - AssertStatement { kw<"assert"> commaSep } -} - -expressions { commaSep<"*" expression | test> } - -ImportStatement { - kw<"import"> dottedName (kw<"as"> VariableName)? | - kw<"from"> (("." | "...")+ dottedName? | dottedName) kw<"import"> ("*" | importList | importedNames) -} -importedNames { commaSep VariableName> } -importList[@export] { "(" importedNames ")" } - -commaSep { expr ("," expr)* ","? } - -compoundStatement { - IfStatement | - WhileStatement { kw<"while"> testNamed Body elseClause? } | - ForStatement { kw<"async">? kw<"for"> commaSep<"*"? expression> kw<"in"> commaSep Body elseClause? } | - TryStatement | - WithStatement { kw<"async">? kw<"with"> commaSep VariableName)?> Body } | - FunctionDefinition | - ClassDefinition | - DecoratedStatement { Decorator+ (ClassDefinition | FunctionDefinition) } | - MatchStatement -} - -elseClause { kw<"else"> Body } - -IfStatement { - kw<"if"> testNamed Body - (kw<"elif"> testNamed? Body)* - elseClause? -} - -TryStatement { - kw<"try"> Body - (kw<"except"> (test ((kw<"as"> | ",") VariableName)?)? Body)* - elseClause? - (kw<"finally"> Body)? -} - -Body { ":" (simpleStatement | newline indent statement+ (dedent | eof)) } - -lambdaParam { VariableName (AssignOp{"="} test)? | "*" VariableName? | "**" VariableName } - -lambdaParams[@name="ParamList"] { (lambdaParam ("," lambdaParam)*)? } - -test { - testInner | - ConditionalExpression { testInner !cond kw<"if"> testInner kw<"else"> test } | - LambdaExpression { kw<"lambda"> lambdaParams ":" test } -} - -testNoCond { - testInner | - LambdaExpression { kw<"lambda"> lambdaParams ":" testNoCond } -} - -testNamed { - test | NamedExpression { test AssignOp{":="} test } -} - -testInner { binaryTest | unaryTest | expression } - -binaryTest[@name="BinaryExpression"] { - testInner !or kw<"or"> testInner | - testInner !and kw<"and"> testInner | - testInner !compare (CompareOp | kw<"in"> | kw<"not"> kw<"in"> | kw<"is"> kw<"not">?) testInner -} - -unaryTest[@name="UnaryExpression"] { kw<"not"> testInner } - -expression[@isGroup=Expression] { - BinaryExpression | - UnaryExpression { !prefix (ArithOp{"+" | "-"} | BitOp{"~"}) expression } | - AwaitExpression { kw<"await"> expression } | - ParenthesizedExpression | - TupleExpression | - ComprehensionExpression | - ArrayExpression | - ArrayComprehensionExpression | - DictionaryExpression | - DictionaryComprehensionExpression | - SetExpression | - SetComprehensionExpression | - CallExpression { expression !trail ArgList } | - MemberExpression { expression !trail (subscript | "." PropertyName) } | - VariableName | - Number | - String | - ContinuedString { (String) (String)+ } | - "..." | - kw<"None"> | - @specialize[@name=Boolean] -} - -subscript[@export] { - "[" commaSep "]" -} - -ParenthesizedExpression { "(" (testNamed | "*" expression | YieldExpression) ")" } - -TupleExpression { "(" ((testNamed | "*" expression) (("," (testNamed | "*" expression))+ ","? | ","))? ")" } -ComprehensionExpression { "(" (testNamed | "*" expression) compFor ")" } - -ArrayExpression { "[" commaSep? "]" } -ArrayComprehensionExpression { "[" (testNamed | "*" expression) compFor "]" } - -DictionaryExpression { "{" commaSep? "}" } -DictionaryComprehensionExpression { "{" (test ":" test | "**" expression) compFor "}" } - -SetExpression { "{" commaSep "}" } -SetComprehensionExpression { "{" (test | "*" expression) compFor "}" } - -yield { kw<"yield"> (kw<"from"> test | commaSep) } - -YieldExpression { yield } - -BinaryExpression { - expression !bitor BitOp{"|"} expression | - expression !xor BitOp{"^"} expression | - expression !bitand BitOp{"&"} expression | - expression !shift BitOp{"<<" | ">>"} expression | - expression !plus ArithOp{"+" | "-"} expression | - expression !times ArithOp{"*" | "@" | "/" | "%" | "//"} expression | - expression !power ArithOp{"**"} expression -} - -ArgList { "(" commaSep? ")" } - -argument { test compFor? | VariableName AssignOp{"=" | ":="} test | "**" test | "*" test } - -compFor { - kw<"async">? kw<"for"> commaSep kw<"in"> testInner (compFor | compIf)? -} - -compIf { - kw<"if"> testNoCond (compFor | compIf)? -} - -// FIXME Is it possible to distinguish between VariableName and VariableDefinition? - -VariableName { identifier } - -PropertyName { word } - -dottedName { VariableName ("." VariableName)* } - -kw { @specialize[@name={term}] } - -skw { @extend[@name={term}] } - -@skip {} { - String { - shortString | - longStringStart<"'"> longString1Content* "'''" | - longStringStart<'"'> longString2Content* '"""' - } - - blankLine { - blankLineStart space? Comment? newline - } -} - -@context trackIndent from "./tokens.js" - -@external tokens indentation from "./tokens" { indent, dedent } - -@external tokens newlines from "./tokens" { newline, blankLineStart, eof } - -@tokens { - CompareOp { "<" | ">" | $[<>=!] "=" | "<>" } - - UpdateOp { ($[+\-@%&|^] | "<<" | ">>" | "*" "*"? | "/" "/"?) "=" } - - @precedence { - longStringStart<"'">, longStringStart<'"'>, - shortString, - identifier - } - - identifierChar { @asciiLetter | $[_\u{a1}-\u{10ffff}] } - - word { identifierChar (@digit | identifierChar)* } - - identifier { word } - - stringPrefix { $[rRuUbB] | $[bB] $[rR] | $[rR] $[bR] } - - shortString { stringPrefix? ("'" (!['\\\n\r] | "\\" _)* "'"? | '"' (!["\\\n\r] | "\\" _)* '"'?) } - - longStringStart { stringPrefix? quote quote quote } - - longString1Content { (!['\\] | "\\" _ | "'" longString1_2)+ } - longString1_2 { !['\\] | "\\" _ | "'" longString1_3 } - longString1_3 { !['\\] | "\\" _ } - - longString2Content { (!["\\] | "\\" _ | '"' longString2_2)+ } - longString2_2 { !["\\] | "\\" _ | '"' longString2_3 } - longString2_3 { !["\\] | "\\" _ } - - Number { - (@digit ("_" | @digit)* ("." @digit ("_" | @digit)*)? | "." @digit ("_" | @digit)*) - ($[eE] $[+\-]? @digit ("_" | @digit)*)? $[jJ]? | - "0" $[bB] $[_01]+ | - "0" $[oO] $[_0-7]+ | - "0" $[xX] $[_0-9a-fA-F]+ - } - - Comment { "#" ![\n\r]* } - - space { ($[ \t\f] | "\\" $[\n\r])+ } - - At { "@" } - - "..."[@name=Ellipsis] - - "("[@export=ParenL] ")" - "["[@export=BracketL] "]" - "{"[@export=BraceL] "}" - - "." "," ";" ":" "@" "*" "**" -} - -@external propSource pythonHighlighting from "./highlight" - -@detectDelim diff --git a/src/plugins/CodemirrorLanguages/Python/testPython.js b/src/plugins/CodemirrorLanguages/Python/testPython.js deleted file mode 100644 index e843af7cf..000000000 --- a/src/plugins/CodemirrorLanguages/Python/testPython.js +++ /dev/null @@ -1,28 +0,0 @@ -// This file was generated by lezer-generator. You probably shouldn't edit it. -import {LRParser} from "@lezer/lr" -import {indentation, newlines} from "./tokens" -import {trackIndent} from "./tokens.js" -import {pythonHighlighting} from "./highlight" -const spec_identifier = {__proto__:null,await:38, or:48, and:50, in:54, not:56, is:58, if:64, else:66, lambda:70, yield:88, from:90, async:96, for:98, None:142, True:144, False:144, del:158, pass:162, break:166, continue:170, return:174, raise:180, import:184, as:186, global:190, nonlocal:192, assert:196, elif:206, while:210, try:216, except:218, finally:220, with:224, def:228, class:238, match:249, case:255} -export const parser = LRParser.deserialize({ - version: 14, - states: "!GnO]QUOOP#{OQOOO%UQYO'#GoOOQQ'#Cl'#ClOOQQ'#Cm'#CmO&qQUO'#CkO(WQYO'#GnOOQQ'#Go'#GoOOQQ'#DR'#DROOQQ'#Gn'#GnO(tQUO'#D[O)XQUO'#DcO)iQUO'#DgOOQQ'#Dr'#DrO)|O`O'#DrO*UOpO'#DrO,TQYO'#G`OOQQ'#G`'#G`O&qQUO'#G_O-WQYO'#G_OOQQ'#EW'#EWOOQQ'#G^'#G^O-oQUO'#G]OOQR'#G]'#G]O-zQUO'#EyOOQQ'#Fz'#FzO.PQUO'#ExOOQR'#H^'#H^OOQR'#G['#G[OOQR'#Fb'#FbQ]QUOOO&qQUO'#CnO._QUO'#CzO.fQUO'#DOO.tQUO'#GsO/UQYO'#D{O&qQUO'#D|OOQQ'#EO'#EOOOQQ'#EQ'#EQOOQQ'#ES'#ESO/jQUO'#EUO0QQUO'#EXO-zQUO'#EZO0eQYO'#EZO-zQUO'#E^O0pQUO'#EaO0pQUO'#EeO0pQUO'#EhO0zQUO'#EjO1RQUO'#EoO1^QUO'#EkO0pQUO'#EoO-zQUO'#EqO-zQUO'#EvO1cQUO'#E{P1jOUO'#GZPOOO)CA})CA}OOQQ'#Cb'#CbOOQQ'#Cc'#CcOOQQ'#Cd'#CdOOQQ'#Ce'#CeOOQQ'#Cf'#CfOOQQ'#Cg'#CgOOQQ'#Ci'#CiO&qQUO,58{O&qQUO,58{O&qQUO,58{O&qQUO,58{O&qQUO,58{O&qQUO,58{O1uQUO'#DlOOQQ,5:V,5:VO2YQUO'#G}OOQQ,5:Y,5:YO2gQ!dO,5:YO2lQYO,59VO._QUO,59_O._QUO,59_O._QUO,59_O5XQUO,59_O5^QUO,59_O5eQUO,59gO5lQUO'#GnO6oQUO'#GmOOQQ'#Gm'#GmOOQQ'#DX'#DXO7WQUO,59^O&qQUO,59^O7fQUO,59^OOQQ,59v,59vO7kQUO,5:OO&qQUO,5:OOOQQ,59},59}O7yQUO,59}O8OQUO,5:UO&qQUO,5:UO&qQUO,5:SOOQQ,5:R,5:RO8aQUO,5:RO8fQUO,5:TOOOO'#Fj'#FjO8kO`O,5:^OOQQ,5:^,5:^OOOO'#Fk'#FkO8sOpO,5:^OOQQ'#Fl'#FlO8{QYO,5:_O;qQYO,5pQUO,5:}OOQR,5{QYO'#HYO?dQUO,5;eOOQQ-E9x-E9xOOQR,5;d,5;dO1XQUO'#EqOOQR-E9`-E9`O?lQYO,59YOApQYO,59fOBZQUO'#GpOBfQUO'#GpO-zQUO'#GpOBqQUO'#DQOByQUO,59jOCOQUO'#GtO&qQUO'#GtO0pQUO,5=_OOQQ,5=_,5=_O0pQUO'#DwOOQQ'#Dx'#DxOCdQUO'#FnOCtQUO,58yOCtQUO,58yO(zQUO,5:eODSQYO'#GvOOQQ,5:h,5:hOOQQ,5:p,5:pODgQUO,5:sODxQUO,5:uOOQQ'#Fq'#FqOEWQYO,5:uOEfQUO,5:uOEkQUO'#H]OOQQ,5:x,5:xOEyQUO'#HXOOQQ,5:{,5:{O1^QUO,5;PO1^QUO,5;SOF[QYO'#H_O&qQUO'#H_OFfQUO,5;UO0zQUO,5;UO0pQUO,5;ZO-zQUO,5;]OFkQUO'#EfOGqQVO,5;VOJsQUO'#H`O1^QUO,5;ZOKOQUO,5;]OKTQUO,5;bOK]QYO,5;gO&qQUO,5;gPOOO,5zQUO'#FwO1^QUO1G0qO1^QUO1G0qO!?XQUO,5=zO!?fQUO,5=zO-zQUO,5=zOOQR1G0u1G0uO!?nQUO'#EsO!@PQ!dO1G0wOOQR1G0|1G0|O1^QUO1G0|O!@XQUO'#E}OOQR1G1R1G1ROK]QYO1G1RPOOO1G2a1G2aP!@^OQO1G2aOOQQ,5=h,5=hOOQQ'#Dm'#DmO0pQUO,5=hO!@cQUO,5=gO!@vQUO,5=gOOQQ1G/r1G/rO!AOQUO,5=jO!A`QUO,5=jO!AhQUO,5=jO!A{QUO,5=jO!B]QUO,5=jOOQQ1G3T1G3TOOQQ7+$e7+$eO!1[QUO7+$mO!C{QUO1G.yO!DSQUO1G.yOOQQ1G/]1G/]OOQQ,5zQUO'#FuO1^QUO7+&VO1^QUO7+&YO# rQYO,5SAN>SO#9pQUO<`AN>`O0pQUO1G1mO#:QQYO1G1mP#:[QUO'#FgO#:iQUO7+(POOQQAN?PAN?PO#;SQUO,5<^O#;hQUO1G3bOOQQ-E9p-E9pO#;yQUO1G3bOOQQ1G3a1G3aOOQRAN?]AN?]OOQR1G1{1G1{O1^QUOAN?bO#<[QVOAN?bOOQRAN?iAN?iOOQR<OO#KiQUO,5>OO-zQUO,5;pO#KzQUO,5;tO#LPQUO,5;tO#@RQUO'#HfO#LUQUO'#HfO#LZQUO,5;uOOQQ,5;v,5;vO&qQUO'#FaOOQR1G1U1G1UO1^QUO1G1UOOQQAN@aAN@aO#L`QUOG27bO#LpQUO,59zOOQQ1G2}1G2}OOQQ,5QO#@RQUO,5>QOOQQ1G1a1G1aO$ aQYO,5;{OOQR7+&p7+&pO#BOQUO1G/fO#@RQUO,5;yO$ hQUO,5>RO$ oQUO,5>ROOQQ1G1d1G1dOOQQ7+&s7+&sP#@RQUO'#GQO$ wQUO1G3lO$!RQUO1G3lO$!ZQUO1G3lOOQQ7+%Q7+%QO$!iQUO1G1eO$!wQYO'#FQO$#OQUO,5hswo]P!T%vSOY]!P!Q$w!Q![!?V![!d$w!d!e!@w!e!g$w!g!h!5s!h!l$w!l!m!9R!m!q$w!q!r!CP!r!z$w!z!{!ER!{#O$w#O#P-g#P#R$w#R#S!?V#S#U$w#U#V!@w#V#X$w#X#Y!5s#Y#^$w#^#_!9R#_#c$w#c#d!CP#d#l$w#l#m!ER#m;'S$w;'S;=`.j<%lO$w}!>dZ%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q![!4X![#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w}!?`g!eq%vS%yWOr$wrs%ksw$wwx)ix!O$w!O!P!>]!P!Q$w!Q![!?V![!g$w!g!h!5s!h!l$w!l!m!9R!m#O$w#O#P-g#P#R$w#R#S!?V#S#X$w#X#Y!5s#Y#^$w#^#_!9R#_;'S$w;'S;=`.j<%lO$w}!AO^%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q!R!Az!R!S!Az!S#O$w#O#P-g#P#R$w#R#S!Az#S;'S$w;'S;=`.j<%lO$w}!BT^!eq%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q!R!Az!R!S!Az!S#O$w#O#P-g#P#R$w#R#S!Az#S;'S$w;'S;=`.j<%lO$w}!CW]%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q!Y!DP!Y#O$w#O#P-g#P#R$w#R#S!DP#S;'S$w;'S;=`.j<%lO$w}!DY]!eq%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q!Y!DP!Y#O$w#O#P-g#P#R$w#R#S!DP#S;'S$w;'S;=`.j<%lO$w}!EYa%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q![!F_![!c$w!c!i!F_!i#O$w#O#P-g#P#R$w#R#S!F_#S#T$w#T#Z!F_#Z;'S$w;'S;=`.j<%lO$w}!Fha!eq%vS%yWOr$wrs%ksw$wwx)ix!Q$w!Q![!F_![!c$w!c!i!F_!i#O$w#O#P-g#P#R$w#R#S!F_#S#T$w#T#Z!F_#Z;'S$w;'S;=`.j<%lO$w!a!GvZx!T%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`!Hi!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w_!HrX%fR%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P!IhX#Ws%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P!J^]jR%vS%yWOr$wrs%ksw$wwx)ix!^$w!^!_!KV!_!`1[!`!a1[!a#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!O!K`Z%WQ%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P!L[Z%es%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`1[!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P!MW[jR%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`1[!`!a!M|!a#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!O!NVZ%XQ%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P# TZ[Q#nP%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!a#!Rb%vS%yW%s`%`sOr$wrs%ksw$wwx)ix!Q$w!Q![# v![!c$w!c!}# v!}#O$w#O#P-g#P#R$w#R#S# v#S#T$w#T#o# v#o$g$w$g;'S# v;'S;=`##Z<%lO# v!a##^P;=`<%l# v!a##lf%vS%yW%s`%`sOr$wrs#%Qsw$wwx#'bx!Q$w!Q![# v![!c$w!c!t# v!t!u#)r!u!}# v!}#O$w#O#P-g#P#R$w#R#S# v#S#T$w#T#f# v#f#g#)r#g#o# v#o$g$w$g;'S# v;'S;=`##Z<%lO# v!P#%X]%vS%tsOY3QYZ$wZ]3Q]^$w^r3Qrs#&Qsw3Qwx4vx#O3Q#O#P9k#P;'S3Q;'S;=`:|<%lO3Q!P#&XX%vS%tsOr$wrs#&tsw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$ww#&{V%vS%xsOw&}wx'ix#O&}#O#P(h#P;'S&};'S;=`)c<%lO&}!P#'i]%yW%tsOY! SYZ$wZ]! S]^$w^r! Srs!!Usw! Swx#(bx#O! S#O#P!'m#P;'S! S;'S;=`!)O<%lO! S!P#(iX%yW%tsOr$wrs%ksw$wwx#)Ux#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w{#)]V%yW%usOr*{rs+gs#O*{#O#P,f#P;'S*{;'S;=`-a<%lO*{!a#)}b%vS%yW%s`%`sOr$wrs#%Qsw$wwx#'bx!Q$w!Q![# v![!c$w!c!}# v!}#O$w#O#P-g#P#R$w#R#S# v#S#T$w#T#o# v#o$g$w$g;'S# v;'S;=`##Z<%lO# v!a#+bf%vS%yW%s`%`sOr$wrs#%Qsw$wwx#'bx!Q$w!Q![# v![!c$w!c!t# v!t!u#)r!u!}# v!}#O$w#O#P-g#P#R$w#R#S# v#S#T$w#T#U# v#U#V#)r#V#o# v#o$g$w$g;'S# v;'S;=`##Z<%lO# v!P#-PX!Us%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w_#-uX!TR%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!O#.kZ%UQ%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w}#/gX!Yq%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w!P#0]Z%TR%vS%yWOr$wrs%ksw$wwx)ix!_$w!_!`Lb!`#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w_#1XX!XR%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w}#1}X%_q%vS%yWOr$wrs%ksw$wwx)ix#O$w#O#P-g#P;'S$w;'S;=`.j<%lO$w", - tokenizers: [indentation, newlines, 0, 1, 2, 3, 4, 5], - topRules: {"Script":[0,2]}, - specialized: [{term: 200, get: value => spec_identifier[value] || -1}], - tokenPrec: 6599 -}) diff --git a/src/plugins/CodemirrorLanguages/Python/testPython.terms.js b/src/plugins/CodemirrorLanguages/Python/testPython.terms.js deleted file mode 100644 index 51ac2a4da..000000000 --- a/src/plugins/CodemirrorLanguages/Python/testPython.terms.js +++ /dev/null @@ -1,52 +0,0 @@ -// This file was generated by lezer-generator. You probably shouldn't edit it. -export const - indent = 176, - dedent = 177, - newline = 178, - blankLineStart = 179, - eof = 180, - Comment = 1, - Script = 2, - BinaryExpression = 5, - ParenL = 21, - ParenthesizedExpression = 22, - binaryTest = 23, - CompareOp = 26, - unaryTest = 30, - lambdaParams = 36, - VariableName = 37, - YieldExpression = 43, - TupleExpression = 46, - ComprehensionExpression = 47, - BracketL = 52, - ArrayExpression = 53, - ArrayComprehensionExpression = 54, - BraceL = 56, - DictionaryExpression = 57, - DictionaryComprehensionExpression = 58, - SetExpression = 59, - SetComprehensionExpression = 60, - ArgList = 62, - subscript = 217, - PropertyName = 66, - Number = 67, - String = 68, - TypeDef = 73, - UpdateOp = 76, - ImportStatement = 91, - importList = 229, - IfStatement = 101, - Body = 102, - TryStatement = 107, - FunctionDefinition = 113, - ParamList = 115, - ClassDefinition = 118, - Decorator = 121, - At = 122, - MatchStatement = 123, - MatchClause = 126, - LiteralPattern = 129, - AttributePattern = 135, - SequencePattern = 136, - MappingPattern = 137, - PatternArgList = 140 diff --git a/src/plugins/CodemirrorLanguages/Python/tokens.js b/src/plugins/CodemirrorLanguages/Python/tokens.js deleted file mode 100644 index e7eebded8..000000000 --- a/src/plugins/CodemirrorLanguages/Python/tokens.js +++ /dev/null @@ -1,84 +0,0 @@ -/* ref: https://github.com/lezer-parser/python/blob/main/src/tokens.js */ -import { ExternalTokenizer, ContextTracker } from '@lezer/lr' - -import { newline as newlineToken, eof, blankLineStart, indent, dedent } from './testPython.terms' - -const newline = 10, - carriageReturn = 13, - space = 32, - tab = 9 - -function isLineBreak(ch) { - return ch == newline || ch == carriageReturn -} - -export const newlines = new ExternalTokenizer( - (input, stack) => { - let prev - if (input.next < 0) { - input.acceptToken(eof) - } else if (((prev = input.peek(-1)) < 0 || isLineBreak(prev)) && stack.canShift(blankLineStart)) { - let spaces = 0 - while (input.next == space || input.next == tab) { - input.advance() - spaces++ - } - if (input.next == newline || input.next == carriageReturn) input.acceptToken(blankLineStart, -spaces) - } else if (isLineBreak(input.next)) { - input.acceptToken(newlineToken, 1) - } - }, - { contextual: true } -) - -export const indentation = new ExternalTokenizer((input, stack) => { - let cDepth = stack.context.depth - if (cDepth < 0) return - let prev = input.peek(-1), - depth - if (prev == newline || prev == carriageReturn) { - let depth = 0, - chars = 0 - for (;;) { - if (input.next == space) depth++ - else if (input.next == tab) depth += 8 - (depth % 8) - else break - input.advance() - chars++ - } - if (depth != cDepth && input.next != newline && input.next != carriageReturn) { - if (depth < cDepth) input.acceptToken(dedent, -chars) - else input.acceptToken(indent) - } - } -}) - -function IndentLevel(parent, depth) { - this.parent = parent - // -1 means this is not an actual indent level but a set of brackets - this.depth = depth - this.hash = (parent ? (parent.hash + parent.hash) << 8 : 0) + depth + (depth << 4) -} - -const topIndent = new IndentLevel(null, 0) - -function countIndent(space) { - let depth = 0 - for (let i = 0; i < space.length; i++) depth += space.charCodeAt(i) == tab ? 8 - (depth % 8) : 1 - return depth -} - -export const trackIndent = new ContextTracker({ - start: topIndent, - reduce(context) { - return context.depth < 0 ? context.parent : context - }, - shift(context, term, stack, input) { - if (term == indent) return new IndentLevel(context, countIndent(input.read(input.pos, stack.pos))) - if (term == dedent) return context.parent - return context - }, - hash(context) { - return context.hash - }, -}) diff --git a/src/plugins/CodemirrorLanguages/printLezerTree.ts b/src/plugins/CodemirrorLanguages/printLezerTree.ts deleted file mode 100644 index ce1e60910..000000000 --- a/src/plugins/CodemirrorLanguages/printLezerTree.ts +++ /dev/null @@ -1,246 +0,0 @@ -// MIT License -// -// Copyright (c) 2021 Matthijs Steen -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import { Text } from "@codemirror/state" -import { Input, NodeType, SyntaxNode, Tree, TreeCursor } from "@lezer/common" - -class StringInput implements Input { - constructor(private readonly input: string) {} - - get length() { - return this.input.length - } - - chunk(from: number): string { - return this.input.slice(from) - } - - lineChunks = false - - read(from: number, to: number): string { - return this.input.slice(from, to) - } -} - -export function sliceType(cursor: TreeCursor, input: Input, type: number): string | null { - if (cursor.type.id === type) { - const s = input.read(cursor.from, cursor.to) - cursor.nextSibling() - return s - } - return null -} - -export function isType(cursor: TreeCursor, type: number): boolean { - const cond = cursor.type.id === type - if (cond) cursor.nextSibling() - return cond -} - -export type CursorNode = { type: NodeType; from: number; to: number; isLeaf: boolean } - -function cursorNode({ type, from, to }: TreeCursor, isLeaf = false): CursorNode { - return { type, from, to, isLeaf } -} - -export type TreeTraversal = { - beforeEnter?: (cursor: TreeCursor) => void - onEnter: (node: CursorNode) => false | void - onLeave?: (node: CursorNode) => false | void -} - -type TreeTraversalOptions = { - from?: number - to?: number - includeParents?: boolean -} & TreeTraversal - -export function traverseTree( - cursor: TreeCursor | Tree | SyntaxNode, - { - from = -Infinity, - to = Infinity, - includeParents = false, - beforeEnter, - onEnter, - onLeave, - }: TreeTraversalOptions, -): void { - if (!(cursor instanceof TreeCursor)) cursor = cursor instanceof Tree ? cursor.cursor() : cursor.cursor - for (;;) { - let node = cursorNode(cursor) - let leave = false - if (node.from <= to && node.to >= from) { - const enter = !node.type.isAnonymous && (includeParents || (node.from >= from && node.to <= to)) - if (enter && beforeEnter) beforeEnter(cursor) - node.isLeaf = !cursor.firstChild() - if (enter) { - leave = true - if (onEnter(node) === false) return - } - if (!node.isLeaf) continue - } - for (;;) { - node = cursorNode(cursor, node.isLeaf) - if (leave && onLeave) if (onLeave(node) === false) return - leave = cursor.type.isAnonymous - node.isLeaf = false - if (cursor.nextSibling()) break - if (!cursor.parent()) return - leave = true - } - } -} - -function isChildOf(child: CursorNode, parent: CursorNode): boolean { - return ( - child.from >= parent.from && child.from <= parent.to && child.to <= parent.to && child.to >= parent.from - ) -} - -export function validatorTraversal( - input: Input | string, - { fullMatch = true }: { fullMatch?: boolean } = {}, -) { - if (typeof input === "string") input = new StringInput(input) - const state = { - valid: true, - parentNodes: [] as CursorNode[], - lastLeafTo: 0, - } - return { - state, - traversal: { - onEnter(node) { - state.valid = true - if (!node.isLeaf) state.parentNodes.unshift(node) - if (node.from > node.to || node.from < state.lastLeafTo) { - state.valid = false - } else if (node.isLeaf) { - if (state.parentNodes.length && !isChildOf(node, state.parentNodes[0])) state.valid = false - state.lastLeafTo = node.to - } else { - if (state.parentNodes.length) { - if (!isChildOf(node, state.parentNodes[0])) state.valid = false - } else if (fullMatch && (node.from !== 0 || node.to !== input.length)) { - state.valid = false - } - } - }, - onLeave(node) { - if (!node.isLeaf) state.parentNodes.shift() - }, - } as TreeTraversal, - } -} - -export function validateTree( - tree: TreeCursor | Tree | SyntaxNode, - input: Input | string, - options?: { fullMatch?: boolean }, -): boolean { - const { state, traversal } = validatorTraversal(input, options) - traverseTree(tree, traversal) - return state.valid -} - -enum Color { - Red = 31, - Green = 32, - Yellow = 33, -} - -function colorize(value: any, color: number): string { - return /* "\u001b[" + color + "m" + */String(value)/* + "\u001b[39m" */ -} - -type PrintTreeOptions = { from?: number; to?: number; start?: number; includeParents?: boolean } - -export function printTree( - cursor: TreeCursor | Tree | SyntaxNode, - input: Input | string, - { from, to, start = 0, includeParents }: PrintTreeOptions = {}, -): string { - const inp = typeof input === "string" ? new StringInput(input) : input - const text = Text.of(inp.read(0, inp.length).split("\n")) - const state = { - output: "", - prefixes: [] as string[], - hasNextSibling: false, - } - const validator = validatorTraversal(inp) - traverseTree(cursor, { - from, - to, - includeParents, - beforeEnter(cursor) { - state.hasNextSibling = cursor.nextSibling() && cursor.prevSibling() - }, - onEnter(node) { - validator.traversal.onEnter(node) - const isTop = state.output === "" - const hasPrefix = !isTop || node.from > 0 - if (hasPrefix) { - state.output += (!isTop ? "\n" : "") + state.prefixes.join("") - if (state.hasNextSibling) { - state.output += " ├─ " - state.prefixes.push(" │ ") - } else { - state.output += " └─ " - state.prefixes.push(" ") - } - } - const hasRange = node.from !== node.to - state.output += - (node.type.isError || !validator.state.valid ? colorize(node.type.name, Color.Red) : node.type.name) + - " " + - (hasRange - ? "[" + - colorize(locAt(text, start + node.from), Color.Yellow) + - ".." + - colorize(locAt(text, start + node.to), Color.Yellow) + - "]" - : colorize(locAt(text, start + node.from), Color.Yellow)) - if (hasRange && node.isLeaf) { - state.output += ": " + colorize(JSON.stringify(inp.read(node.from, node.to)), Color.Green) - } - }, - onLeave(node) { - validator.traversal.onLeave!(node) - state.prefixes.pop() - }, - }) - return state.output -} - -function locAt(text: Text, pos: number): string { - const line = text.lineAt(pos) - return line.number + ":" + (pos - line.from) -} - -export function logTree( - tree: TreeCursor | Tree | SyntaxNode, - input: string, - options?: PrintTreeOptions, -): void { - console.log(printTree(tree, input, options)) -} From cbf6eb2ddae8bb4b35bf50643ba7d86722b37e03 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sat, 27 May 2023 15:18:27 +0200 Subject: [PATCH 07/16] fixed checks (prefer-const and styling) --- .../KlipperConfigLanguage/lang/klipperConfig.ts | 2 +- .../CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts | 2 +- .../KlipperConfigLanguage/parser/highlight.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts index 83b982ebd..721ec8e37 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts @@ -11,7 +11,7 @@ export const klipperConfigLang = LRLanguage.define({ props: [ foldNodeProp.add({ ConfigBlock(tree) { - let body = tree.lastChild + const body = tree.lastChild if (body == null) return null let lastOption = body.lastChild if (lastOption == null) return null diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts index 2972eca09..83c6a0625 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts @@ -2,7 +2,7 @@ import { syntaxTree } from '@codemirror/language' import { linter, Diagnostic } from '@codemirror/lint' export const klipperConfigLint = linter((view) => { - let diagnostics: Diagnostic[] = [] + const diagnostics: Diagnostic[] = [] syntaxTree(view.state) .cursor() .iterate((node) => { diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js index 2c5c2d59e..1e7dbc1de 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js @@ -14,7 +14,7 @@ export const klipperConfigHighlighting = styleTags({ Cords: t.number, Pin: t.namespace, VirtualPin: t.namespace, - Path: t.string, + Path: t.string, File: t.string, FilePath: t.string, From 4c5440eb2ae8d639d3ae822234d04d11c4a3bd7d Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Mon, 29 May 2023 00:17:11 +0200 Subject: [PATCH 08/16] prettier ignore auto generated files --- .prettierignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.prettierignore b/.prettierignore index 62aabd968..9030b3bb5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,5 @@ dist/ public/ components.d.ts CHANGELOG.md +src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js +src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js From 555a6c999b7f1179196ecd9c26933c6cd824f4ed Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Mon, 29 May 2023 00:31:31 +0200 Subject: [PATCH 09/16] removed auto completion --- .../KlipperConfigLanguage/lang/complete.ts | 79 ------------------- .../lang/klipperConfig.ts | 5 +- 2 files changed, 1 insertion(+), 83 deletions(-) delete mode 100644 src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/complete.ts diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/complete.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/complete.ts deleted file mode 100644 index ef25f1801..000000000 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/complete.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { CompletionContext } from '@codemirror/autocomplete' -import { syntaxTree } from '@codemirror/language' -import { EditorState } from '@codemirror/state' -import { SyntaxNode } from '@lezer/common' - -const blockTypeOptions = ['mcu', 'printer', 'adxl345', 'resonance_tester', 'stepper_x'].map((tag) => ({ - label: tag, - type: 'namespace', -})) -const mcuParameterOptions = ['serial', 'baud', 'canbus_uuid', 'canbus_interface', 'restart_method'].map((tag) => ({ - label: tag + ': ', - type: 'keyword', -})) -const printerParameterOptions = ['kinematics', 'max_velocity', 'max_accel', 'max_z_velocity', 'max_z_accel'].map( - (tag) => ({ - label: tag + ': ', - type: 'keyword', - }) -) -const adxl345Options = ['cs_pin'].map((tag) => ({ - label: tag + ': ', - type: 'keyword', -})) - -export function klipperConfigCompletionSource(context: CompletionContext) { - const parent = syntaxTree(context.state).resolveInner(context.pos, -1) - if (!parent) return null - const tagBefore = getTagBefore(context.state, parent.from, context.pos) - - if (parent.type.name === 'Parameter') { - const typeNode = findTypeNode(parent) - if (!typeNode) return null - const blocktype = context.state.sliceDoc(typeNode.from, typeNode.to) - const options = getOptionsByBlockType(blocktype) - return { - from: tagBefore ? parent.from + tagBefore.index : context.pos, - options: options, - validFor: /^(\w*)?$/, - } - } - - if (parent.parent?.type.name === 'ConfigBlock') { - return { - from: tagBefore ? parent.from + tagBefore.index : context.pos, - options: blockTypeOptions, - validFor: /^(\w*)?$/, - } - } - - return null -} - -function findTypeNode(node: SyntaxNode | null) { - while (node) { - if (node.type.name === 'ConfigBlock') { - return node.firstChild - } - node = node.parent - } - return null -} - -function getTagBefore(state: EditorState, from: number, pos: number) { - const textBefore = state.sliceDoc(from, pos) - return /\w*$/.exec(textBefore) -} - -function getOptionsByBlockType(blocktype: string) { - switch (blocktype) { - case 'mcu': - return mcuParameterOptions - case 'printer': - return printerParameterOptions - case 'adxl345': - return adxl345Options - default: - return null - } -} diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts index 721ec8e37..cb4d533f7 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts @@ -2,7 +2,6 @@ import { parser } from '../parser/klipperConfigParser.js' import { LRLanguage, LanguageSupport, StreamLanguage, foldNodeProp } from '@codemirror/language' import { parseMixed } from '@lezer/common' import { klipper_config } from '../../../StreamParserKlipperConfig' -import { klipperConfigCompletionSource } from './complete.js' const jinja2Parser = StreamLanguage.define(klipper_config).parser @@ -33,9 +32,7 @@ export const klipperConfigLang = LRLanguage.define({ }) export function klipperConfig() { - return new LanguageSupport(klipperConfigLang, [ - klipperConfigLang.data.of({ autocomplete: klipperConfigCompletionSource }), - ]) + return new LanguageSupport(klipperConfigLang) } /* From 919936b81e111a8d12a997ce1ae997d21c703de3 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sat, 10 Jun 2023 23:08:07 +0200 Subject: [PATCH 10/16] little tweaks fix parsing errors: - paths with "~" - special characters in [respond] - gcode also appear after "_gcode:" --- .../parser/klipperConfig.grammar | 23 ++++++----- .../parser/klipperConfigParser.js | 16 ++++---- .../parser/klipperConfigParser.terms.js | 41 +++++++++---------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar index 50593bd19..e2590e2a6 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar @@ -1,4 +1,6 @@ -@top Program { Import* ConfigBlock+ } +@precedence { str @cut } + +@top Program { (Import | ConfigBlock)+ } @skip { Comment newline? | AutoGenerated newline | space | blankLine } @@ -7,8 +9,8 @@ sep { content (seperator content)+ } -Import { "[" ImportKeyword (FilePath | File) "]" newline } -ConfigBlock {"[" BlockType Identifier? "]" newline Body } +Import { "[" ImportKeyword FilePath "]" newline } +ConfigBlock {"[" BlockType Identifier? "]" newline Body? } Body { Option+ } Option { Parameter ":" Value | GcodeKeyword ":" Jinja2 } @@ -22,8 +24,7 @@ VirtualPin { string ":" string } Cords { sep } Number { number } String { string } -File {string "." string } -Path { "/"? sep } +Path { ("/"|"~/")? !str string ("/" string)* } FilePath { Path "." string} @@ -34,12 +35,12 @@ FilePath { Path "." string} @tokens { ImportKeyword{ "include" } - GcodeKeyword{ "gcode" } + GcodeKeyword{ $[a-zA-Z0-9_.\-]* "gcode" } BlockType { $[a-zA-Z0-9_]+ } Identifier { $[a-zA-Z0-9_.\-]+ } Parameter { $[a-zA-Z0-9_]+ } - string { $[ a-zA-Z0-9_\-]+ } + string { ($[ a-zA-Z0-9_\-!:]+ | "//") } jinja2 { $[ \ta-zA-Z0-9_.\-"'{}%=]+ } number { "-"? $[0-9]+ ("." $[0-9]*)? } Boolean { "True" | "False" } @@ -50,11 +51,11 @@ FilePath { Path "." string} space { $[ \t\f]+ } - @precedence { space, jinja2, string} + @precedence { space, jinja2, string } @precedence { AutoGenerated, Comment } - @precedence { number, Pin, Boolean, ImportKeyword, string } - @precedence { ImportKeyword, BlockType} - @precedence { GcodeKeyword, Parameter} + @precedence { number, Pin, Boolean, ImportKeyword, string, "/" } + @precedence { ImportKeyword, BlockType } + @precedence { GcodeKeyword, Parameter } } @external propSource klipperConfigHighlighting from "./highlight" diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js index 487f7d530..c1709c89e 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js @@ -4,17 +4,17 @@ import {indentation, newlines, trackIndent} from "./tokens.js" import {klipperConfigHighlighting} from "./highlight" export const parser = LRParser.deserialize({ version: 14, - states: "+jOcQUOOPhOSOOOpQUO'#C`OOQQ'#Ct'#CtOcQUOOOOQQ'#Cv'#CvQxQUOOP}OQO)C>xO!SQYO,58zO![QbO,59POOQQ-E6r-E6rOsQUO'#CeOOQQ-E6t-E6tPOOO/'4d/'4dO!dQUO'#CbO!iQUO'#CcO!qQUO1G.fO!vQYO'#CcO!{QUO1G.kO#QQUO1G.kP#VQUO'#C`O#[QYO,58|O#aQYO'#CuO#fQUO,58}O#tQYO,59OO#yQUO7+$QO$OQUO,58}O$TQrO7+$VO$]QUO7+$VOOQQ1G.h1G.hOOQQ,59a,59aOOQQ-E6s-E6sOOQQ1G.j1G.jOOQQ<vO}QYO,58zO!YQbO,59OOOQQ-E6q-E6qPOOO/'4b/'4bO!bQUO'#CcO!pQYO'#CcO!uQUO'#CbO!zQUO1G.fO#PQUO1G.jO#UQUO1G.jO#ZQYO'#CtO#`QUO,58}O#`QUO,58}O#nQYO,58|O#sQUO7+$QO#xQrO7+$UO$WQUO7+$UOOQQ,59`,59`OOQQ-E6r-E6rO$]QUO1G.iOOQQ1G.h1G.hOOQQ<a!w!}2|!}#OAP#P#QAU#Q#RAZ#R#S2|#T#Z2|#Z#[Ad#[#]2|#]#^G}#^#o2|#o#p$q#q#r$q#r#sAZ~#d_w~!S`XY#][]$cpq#]rs$quv$qwx$q}!O$q!O!P$q!Q![$q!_!`$q!c!}$q#R#S$q#T#o$q#o#p$q#q#r$q~$hRw~XY$c[]$cpq$c`$v^!S`XY$qpq$qrs$quv$qwx$q}!O$q!O!P$q!Q![$q!_!`$q!c!}$q#R#S$q#T#o$q#o#p$q#q#r$q~%{_w~!S`zQXY#][]$cpq%rrs$quv$qwx$q}!O&z!O!P$q!Q![&z!_!`$q!c!}&z#R#S&z#T#o&z#o#p$q#q#r$qb'R^!S`zQXY$qpq&zrs$quv$qwx$q}!O&z!O!P$q!Q![&z!_!`$q!c!}&z#R#S&z#T#o&z#o#p$q#q#r$qQ(QP!r!s(TQ(WP!c!}(ZQ(^P!Q![(aQ(fP`Q!Q![(a~(nVP~OY)TZ])T^z)Tz{)o{;'S)T;'S;=`)i<%lO)T~)YTP~OY)TZ])T^;'S)T;'S;=`)i<%lO)T~)lP;=`<%l)T~)tVP~OY)TZ])T^s)Tst*Zt;'S)T;'S;=`)i<%lO)T~*bTQ~P~OY*ZZ]*Z^;'S*Z;'S;=`*q<%lO*Z~*tP;=`<%l*Z~*|O!P~f+V^ZS!S`zQXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![.Z!_!`$q!c!},R#R#S,R#T#o,R#o#p$q#q#r$qf,[^ZS!S`zQXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![,R!_!`$q!c!},R#R#S,R#T#o,R#o#p$q#q#r$qd-_^ZS!S`XY$qpq$qrs$quv$qwx$q}!O-W!O!P-W!Q![-W!_!`$q!c!}-W#R#S-W#T#o-W#o#p$q#q#r$qf.f^ZS!S`!QQzQXY$qpq&zrs$quv$qwx$q}!O,R!O!P/b!Q![.Z!_!`$q!c!},R#R#S,R#T#o,R#o#p$q#q#r$qf/k^ZS!S`!QQXY$qpq$qrs$quv$qwx$q}!O-W!O!P-W!Q![/b!_!`$q!c!}-W#R#S-W#T#o-W#o#p$q#q#r$qe0p^{PZS!S`XY$qpq$qrs$quv$qwx$q}!O-W!O!P-W!Q![-W!_!`$q!c!}-W#R#S-W#T#o-W#o#p$q#q#r$q~1qOy~o2Q^ZS!S`^W!QQzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P/b!Q![1q!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$qo3Z^ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$q~4[O}~o4i_ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#U5h#U#o2|#o#p$q#q#r$qo5u`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#`2|#`#a6w#a#o2|#o#p$q#q#r$qo7U`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#g2|#g#h8W#h#o2|#o#p$q#q#r$qo8e`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#X2|#X#Y9g#Y#o2|#o#p$q#q#r$qo9v^ZS!S`^WeQzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$qo;P^ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!};{#R#S2|#T#o2|#o#p$q#q#r$qon`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#f2|#f#g?p#g#o2|#o#p$q#q#r$qo?}`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#i2|#i#j8W#j#o2|#o#p$q#q#r$q~AUOx~~AZO|~QA^Qqr'}!r!s(ToAq`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#V2|#V#WBs#W#o2|#o#p$q#q#r$qoCQ`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#c2|#c#dDS#d#o2|#o#p$q#q#r$qoDa`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#W2|#W#XEc#X#o2|#o#p$q#q#r$qoEp`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#X2|#X#YFr#Y#o2|#o#p$q#q#r$qoGR^ZS!S`fW^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$qoH[`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#b2|#b#cI^#c#o2|#o#p$q#q#r$qoIk`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#V2|#V#WJm#W#o2|#o#p$q#q#r$qoJz`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#`2|#`#aK|#a#o2|#o#p$q#q#r$qoLZ`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#i2|#i#jM]#j#o2|#o#p$q#q#r$qoMj`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#W2|#W#XNl#X#o2|#o#p$q#q#r$qoNy`ZS!S`^WzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#X2|#X#Y! {#Y#o2|#o#p$q#q#r$qo!![^ZS!S`^WTPzQYPXY$qpq&zrs$quv$qwx$q}!O,R!O!P-W!Q![2|!_!`$q!c!}2|#R#S2|#T#o2|#o#p$q#q#r$q", + repeatNodeCount: 7, + tokenData: "!=[~RrXY#][]$cpq%rqr(xrs$qst+juv$qwx$q|}-x}!O-}!O!PBh!P!QCs!Q![DQ![!]Nw!_!`$q!c!hEi!h!i! h!i!rEi!r!s!)^!s!vEi!v!w!-q!w!}Ei!}#O!0y#P#Q!1O#Q#R!1T#R#SEi#T#ZEi#Z#[GO#[#]Ei#]#^!1x#^#oEi#o#p$q#q#r$q#r#s!e#Y#Z/`#Z#[8e#[#o/`#o#p$q#q#r$qn>pbYS!R`eWyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![/`![!]'Q!_!`$q!c!}/`#R#S/`#T#Z/`#Z#[8e#[#o/`#o#p$q#q#r$qn@TbYS!R`!PQyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!PA]!Q![?x![!]'Q!_!`$q!c!}/`#R#S/`#T#Z/`#Z#[8e#[#o/`#o#p$q#q#r$qnAf`YS!R`!PQXY$qpq$qrs$quv$qwx$q}!O0q!O!P0q!Q![A]!_!`$q!c!}0q#R#S0q#T#Z0q#Z#[1z#[#o0q#o#p$q#q#r$qmBq`zPYS!R`XY$qpq$qrs$quv$qwx$q}!O0q!O!P0q!Q![0q!_!`$q!c!}0q#R#S0q#T#Z0q#Z#[1z#[#o0q#o#p$q#q#r$q~CxPw~!P!QC{QDQOyQoDabYS!R`]W!PQXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!PA]!Q![DQ![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoEvbYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoG]dYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#VEi#V#WHk#W#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoHxdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#cEi#c#dJW#d#oEi#o#p$q#q#r$qoJedYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#WEi#W#XKs#X#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoLQdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#XEi#X#YM`#Y#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoMobYS!R`eW]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qR! OW|PyQpq'Qqr'Q}!O'Q!Q!['Q![!]'Q!c!}'Q#R#S'Q#T#o'Qo! ucYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#U!#Q#U#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!#_dYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#`Ei#`#a!$m#a#oEi#o#p$q#q#r$qo!$zdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#gEi#g#h!&Y#h#oEi#o#p$q#q#r$qo!&gdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#XEi#X#Y!'u#Y#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!(UbYS!R`]WdQXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!)kbYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}!*s#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!+QbYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![!,Y![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!,ibYS!R`]W_QXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![!,Y![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!.OdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#fEi#f#g!/^#g#oEi#o#p$q#q#r$qo!/kdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#iEi#i#j!&Y#j#oEi#o#p$q#q#r$q~!1OOv~~!1TO{~Q!1WQqr!1^!r!s!1dQ!1aP!r!s!1dQ!1gP!c!}!1jQ!1mP!Q![!1pQ!1uP_Q!Q![!1po!2VdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#bEi#b#c!3e#c#oEi#o#p$q#q#r$qo!3rdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#VEi#V#W!5Q#W#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!5_dYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#`Ei#`#a!6m#a#oEi#o#p$q#q#r$qo!6zdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#iEi#i#j!8Y#j#oEi#o#p$q#q#r$qo!8gdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#WEi#W#X!9u#X#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!:SdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#XEi#X#Y!;b#Y#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!;qbYS!R`]WTPXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$q~!<|Rqr!1^!P!Q!=V!r!s!1d~!=[Ox~", tokenizers: [indentation, newlines, 0, 1, 2, 3, 4], topRules: {"Program":[0,3]}, - tokenPrec: 388 + tokenPrec: 381 }) diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js index c77048c75..04766ba2b 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js +++ b/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js @@ -1,10 +1,10 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. export const - indent = 33, - dedent = 34, - newline = 35, - blankLine = 36, - eof = 37, + indent = 31, + dedent = 32, + newline = 33, + blankLine = 34, + eof = 35, Comment = 1, AutoGenerated = 2, Program = 3, @@ -12,19 +12,18 @@ export const ImportKeyword = 5, FilePath = 6, Path = 7, - File = 8, - ConfigBlock = 9, - BlockType = 10, - Identifier = 11, - Body = 12, - Option = 13, - Parameter = 14, - Value = 15, - Pin = 16, - VirtualPin = 17, - Cords = 18, - Number = 19, - String = 20, - Boolean = 21, - GcodeKeyword = 22, - Jinja2 = 23 + ConfigBlock = 8, + BlockType = 9, + Identifier = 10, + Body = 11, + Option = 12, + Parameter = 13, + Value = 14, + Pin = 15, + VirtualPin = 16, + Cords = 17, + Number = 18, + String = 19, + Boolean = 20, + GcodeKeyword = 21, + Jinja2 = 22 From 44283e81a32650814e8580be9c4fdcadaba43f1a Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sun, 18 Jun 2023 21:49:27 +0200 Subject: [PATCH 11/16] renamed/moved files --- src/components/inputs/Codemirror.vue | 8 ++++---- .../KlipperCfgLang/lang/klipperCfg.ts} | 12 ++++++------ .../KlipperCfgLang}/parser/highlight.js | 0 .../KlipperCfgLang/parser/klipperCfg.grammar} | 3 +++ .../KlipperCfgLang/parser/klipperCfgParser.js} | 0 .../KlipperCfgLang/parser/klipperCfgParser.terms.js} | 0 .../KlipperCfgLang}/parser/tokens.js | 4 ++-- .../lang/lint.ts => Codemirror/parseErrorLint.ts} | 2 +- 8 files changed, 16 insertions(+), 13 deletions(-) rename src/plugins/{CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts => Codemirror/KlipperCfgLang/lang/klipperCfg.ts} (81%) rename src/plugins/{CodemirrorLanguages/KlipperConfigLanguage => Codemirror/KlipperCfgLang}/parser/highlight.js (100%) rename src/plugins/{CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar => Codemirror/KlipperCfgLang/parser/klipperCfg.grammar} (95%) rename src/plugins/{CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js => Codemirror/KlipperCfgLang/parser/klipperCfgParser.js} (100%) rename src/plugins/{CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js => Codemirror/KlipperCfgLang/parser/klipperCfgParser.terms.js} (100%) rename src/plugins/{CodemirrorLanguages/KlipperConfigLanguage => Codemirror/KlipperCfgLang}/parser/tokens.js (94%) rename src/plugins/{CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts => Codemirror/parseErrorLint.ts} (91%) diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 5c90d7df6..2789a7430 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -18,8 +18,8 @@ import { gcode } from '@/plugins/StreamParserGcode' import { indentWithTab } from '@codemirror/commands' import { json } from '@codemirror/lang-json' import { css } from '@codemirror/lang-css' -import { klipperConfig } from '../../plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig' -import { klipperConfigLint } from '../../plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint' +import { klipperCfg } from '../../plugins/Codemirror/KlipperCfgLang/lang/klipperCfg' +import { parseErrorLint } from '../../plugins/Codemirror/parseErrorLint' import { indentUnit } from '@codemirror/language' @Component @@ -87,7 +87,7 @@ export default class Codemirror extends Mixins(BaseMixin) { basicSetup, vscodeDark, indentUnit.of(' '.repeat(this.tabSize)), - klipperConfigLint, + parseErrorLint, keymap.of([indentWithTab]), EditorView.updateListener.of((update) => { this.content = update.state?.doc.toString() @@ -97,7 +97,7 @@ export default class Codemirror extends Mixins(BaseMixin) { }), ] - if (['cfg', 'conf'].includes(this.fileExtension)) extensions.push(klipperConfig()) + if (['cfg', 'conf'].includes(this.fileExtension)) extensions.push(klipperCfg()) else if (['gcode'].includes(this.fileExtension)) extensions.push(StreamLanguage.define(gcode)) 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/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts b/src/plugins/Codemirror/KlipperCfgLang/lang/klipperCfg.ts similarity index 81% rename from src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts rename to src/plugins/Codemirror/KlipperCfgLang/lang/klipperCfg.ts index cb4d533f7..b14a24b49 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/klipperConfig.ts +++ b/src/plugins/Codemirror/KlipperCfgLang/lang/klipperCfg.ts @@ -1,11 +1,11 @@ -import { parser } from '../parser/klipperConfigParser.js' +import { parser } from '../parser/klipperCfgParser.js' import { LRLanguage, LanguageSupport, StreamLanguage, foldNodeProp } from '@codemirror/language' import { parseMixed } from '@lezer/common' -import { klipper_config } from '../../../StreamParserKlipperConfig' +import { klipper_config } from '../../../StreamParserKlipperConfig.js' const jinja2Parser = StreamLanguage.define(klipper_config).parser -export const klipperConfigLang = LRLanguage.define({ +export const klipperCfgLang = LRLanguage.define({ parser: parser.configure({ props: [ foldNodeProp.add({ @@ -31,11 +31,11 @@ export const klipperConfigLang = LRLanguage.define({ }, }) -export function klipperConfig() { - return new LanguageSupport(klipperConfigLang) +export function klipperCfg() { + return new LanguageSupport(klipperCfgLang) } /* to generate the parser run: -npx @lezer/generator klipperConfig.grammar -o klipperConfigParser.js +npx @lezer/generator klipperCfg.grammar -o klipperCfgParser.js */ diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js b/src/plugins/Codemirror/KlipperCfgLang/parser/highlight.js similarity index 100% rename from src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/highlight.js rename to src/plugins/Codemirror/KlipperCfgLang/parser/highlight.js diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar similarity index 95% rename from src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar rename to src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar index e2590e2a6..0e51c8766 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar +++ b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar @@ -61,3 +61,6 @@ FilePath { Path "." string} @external propSource klipperConfigHighlighting from "./highlight" @detectDelim + +// to generate the parser run: +// npx @lezer/generator klipperCfg.grammar -o klipperCfgParser.js \ No newline at end of file diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js similarity index 100% rename from src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js rename to src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.terms.js similarity index 100% rename from src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js rename to src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.terms.js diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js b/src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js similarity index 94% rename from src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js rename to src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js index ef023b7e8..7a470e31a 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/tokens.js +++ b/src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js @@ -1,7 +1,7 @@ /* ref: https://github.com/lezer-parser/python/blob/main/src/tokens.js */ import { ExternalTokenizer, ContextTracker } from '@lezer/lr' -import { newline as newlineToken, eof, blankLine, indent, dedent } from '../parser/klipperConfigParser.terms.js' +import { newline as newlineToken, eof, blankLine, indent, dedent } from '../parser/klipperCfgParser.terms.js' const newline = 10, carriageReturn = 13, @@ -44,7 +44,7 @@ export const indentation = new ExternalTokenizer((input, stack) => { input.advance() chars++ } - if (depth != cDepth && input.next != newline && input.next != carriageReturn) { + if (depth != cDepth && !isLineBreak(input.next)) { if (depth < cDepth) input.acceptToken(dedent, -chars) else input.acceptToken(indent) } diff --git a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts b/src/plugins/Codemirror/parseErrorLint.ts similarity index 91% rename from src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts rename to src/plugins/Codemirror/parseErrorLint.ts index 83c6a0625..ae717f6f5 100644 --- a/src/plugins/CodemirrorLanguages/KlipperConfigLanguage/lang/lint.ts +++ b/src/plugins/Codemirror/parseErrorLint.ts @@ -1,7 +1,7 @@ import { syntaxTree } from '@codemirror/language' import { linter, Diagnostic } from '@codemirror/lint' -export const klipperConfigLint = linter((view) => { +export const parseErrorLint = linter((view) => { const diagnostics: Diagnostic[] = [] syntaxTree(view.state) .cursor() From bd37747a2481f861a959dbb41e709e34b690cd67 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sat, 1 Jul 2023 23:09:02 +0200 Subject: [PATCH 12/16] added debugging and tests, added value types, fixed bugs fixed package-lock fixed prettier and eslint errors --- .gitignore | 4 +- .prettierignore | 2 - package-lock.json | 586 +++++++++++++++++- package.json | 10 +- src/components/inputs/Codemirror.vue | 10 + src/plugins/Codemirror/.mocharc.json | 4 + .../KlipperCfgLang/lang/klipperCfg.ts | 4 +- .../KlipperCfgLang/parser/highlight.js | 4 + .../KlipperCfgLang/parser/klipperCfg.grammar | 77 +-- .../KlipperCfgLang/parser/klipperCfgParser.js | 20 - .../parser/klipperCfgParser.terms.js | 29 - .../KlipperCfgLang/parser/tokens.js | 4 +- .../KlipperCfgLang/rollup.config.js | 19 + .../KlipperCfgLang/test/test-klipperCfg.js | 27 + .../test/testCases/blocktype.txt | 25 + .../test/testCases/commentBlankline.txt | 121 ++++ .../KlipperCfgLang/test/testCases/import.txt | 25 + .../test/testCases/parameter.txt | 86 +++ .../test/testCases/structure.txt | 87 +++ .../KlipperCfgLang/test/testCases/value.txt | 296 +++++++++ .../test/testConfigs/KlipperScreen.conf | 101 +++ .../test/testConfigs/basic_macro.cfg | 54 ++ .../test/testConfigs/bed_mesh.cfg | 133 ++++ .../test/testConfigs/caselight.cfg | 29 + .../test/testConfigs/crowsnest.conf | 41 ++ .../test/testConfigs/debug_macro.cfg | 67 ++ .../test/testConfigs/display_menu.cfg | 527 ++++++++++++++++ .../KlipperCfgLang/test/testConfigs/fan.cfg | 167 +++++ .../test/testConfigs/filament.cfg | 176 ++++++ .../test/testConfigs/flexplate.cfg | 212 +++++++ .../test/testConfigs/force_move.cfg | 32 + .../test/testConfigs/heater.cfg | 90 +++ .../test/testConfigs/heater_verify.cfg | 14 + .../test/testConfigs/homing.cfg | 107 ++++ .../test/testConfigs/input_shaper.cfg | 151 +++++ .../KlipperCfgLang/test/testConfigs/lcd.cfg | 303 +++++++++ .../KlipperCfgLang/test/testConfigs/macro.cfg | 356 +++++++++++ .../test/testConfigs/magprobe.cfg | 286 +++++++++ .../test/testConfigs/moonraker.conf | 187 ++++++ .../test/testConfigs/park_macro.cfg | 20 + .../KlipperCfgLang/test/testConfigs/power.cfg | 90 +++ .../test/testConfigs/pressure_advance.cfg | 185 ++++++ .../test/testConfigs/printer.cfg | 465 ++++++++++++++ .../test/testConfigs/printtime.cfg | 167 +++++ .../test/testConfigs/probe_qgl.cfg | 121 ++++ .../test/testConfigs/runout.cfg | 94 +++ .../test/testConfigs/stepper.cfg | 86 +++ .../KlipperCfgLang/test/testConfigs/tmc.cfg | 163 +++++ .../test/testConfigs/webclient.cfg | 109 ++++ .../test/testConfigs/z_calibration.cfg | 77 +++ src/plugins/Codemirror/mochaFileTests.ts | 107 ++++ src/plugins/Codemirror/package.json | 11 + src/plugins/Codemirror/printLezerTree.ts | 231 +++++++ 53 files changed, 6272 insertions(+), 127 deletions(-) create mode 100644 src/plugins/Codemirror/.mocharc.json delete mode 100644 src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js delete mode 100644 src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.terms.js create mode 100644 src/plugins/Codemirror/KlipperCfgLang/rollup.config.js create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/test-klipperCfg.js create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testCases/blocktype.txt create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testCases/commentBlankline.txt create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testCases/import.txt create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testCases/parameter.txt create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testCases/structure.txt create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testCases/value.txt create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg create mode 100644 src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg create mode 100644 src/plugins/Codemirror/mochaFileTests.ts create mode 100644 src/plugins/Codemirror/package.json create mode 100644 src/plugins/Codemirror/printLezerTree.ts diff --git a/.gitignore b/.gitignore index b7c9604ca..5c169384c 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,5 @@ cypress/screenshots/ cypress/videos/ components.d.ts -src/plugins/languages/dist -src/plugins/languages/KlipperConfigLanguage/*.d.ts +src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js +src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.terms.js \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 9030b3bb5..62aabd968 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,5 +3,3 @@ dist/ public/ components.d.ts CHANGELOG.md -src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.terms.js -src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js diff --git a/package-lock.json b/package-lock.json index 95449227b..cd60311c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,7 +56,9 @@ }, "devDependencies": { "@intlify/vite-plugin-vue-i18n": "^2.5.0", + "@lezer/generator": "^1.3.0", "@mdi/js": "^7.0.0", + "@rollup/plugin-node-resolve": "^15.1.0", "@types/file-saver": "^2.0.5", "@types/jmuxer": "^2.0.3", "@types/lodash.kebabcase": "^4.1.6", @@ -72,9 +74,12 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jsonc": "^2.2.1", "eslint-plugin-vue": "^9.0.0", + "mocha": "^10.2.0", "prettier": "^2.5.1", + "rollup": "^2.79.1", "sass": "~1.32", "start-server-and-test": "^1.14.0", + "ts-node": "^10.9.1", "typescript": "^4.5.5", "unplugin-vue-components": "^0.22.12", "vite": "^3.2.7", @@ -2281,6 +2286,28 @@ "node": ">=0.1.90" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@cypress/request": { "version": "2.88.10", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", @@ -2703,9 +2730,9 @@ } }, "node_modules/@lezer/common": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.1.tgz", - "integrity": "sha512-8TR5++Q/F//tpDsLd5zkrvEX5xxeemafEaek7mUp7Y+bI8cKQXdSqhzTOBaOogETcMOVr0pT3BBPXp13477ciw==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.3.tgz", + "integrity": "sha512-JH4wAXCgUOcCGNekQPLhVeUtIqjH0yPBs7vvUdSjyQama9618IOKFJwkv2kcqdhF0my8hQEgCTEJU0GIgnahvA==" }, "node_modules/@lezer/css": { "version": "1.0.0", @@ -2716,6 +2743,19 @@ "@lezer/lr": "^1.0.0" } }, + "node_modules/@lezer/generator": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-1.3.0.tgz", + "integrity": "sha512-7HfulDoOMOkskb97fnwgpC6StwPVSob4ptc0iuOH72rapNQBbp6lVj05y7vc5IM0E9pjFjiLmNQeiBiSbLpCtA==", + "dev": true, + "dependencies": { + "@lezer/common": "^1.0.2", + "@lezer/lr": "^1.3.0" + }, + "bin": { + "lezer-generator": "dist/lezer-generator.cjs" + } + }, "node_modules/@lezer/highlight": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.1.tgz", @@ -2734,9 +2774,9 @@ } }, "node_modules/@lezer/lr": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.3.tgz", - "integrity": "sha512-qpB7rBzH8f6Mzjv2AVZRahcm+2Cf7nbIH++uXbvVOL1yIRvVWQ3HAM/saeBLCyz/togB7LGo76qdJYL1uKQlqA==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.7.tgz", + "integrity": "sha512-ssHKb3p0MxhJXT2i7UBmgAY1BIM3Uq/D772Qutu3EVmxWIyNMU12nQ0rL3Fhu+MiFtiTzyTmd3xGwEf3ON5PSA==", "dependencies": { "@lezer/common": "^1.0.0" } @@ -2829,46 +2869,56 @@ "dev": true }, "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz", + "integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==", "dev": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", "is-module": "^1.0.0", - "resolve": "^1.19.0" + "resolve": "^1.22.1" }, "engines": { - "node": ">= 10.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "rollup": "^2.78.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", "dev": true, "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">= 8.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@rollup/plugin-node-resolve/node_modules/estree-walker": { + "node_modules/@rollup/plugin-node-resolve/node_modules/@types/estree": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "dev": true }, "node_modules/@rollup/plugin-replace": { @@ -2983,6 +3033,30 @@ "sourcemap-codec": "^1.4.8" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@types/estree": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", @@ -3071,13 +3145,10 @@ } }, "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true }, "node_modules/@types/scheduler": { "version": "0.16.2", @@ -3590,6 +3661,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -3712,6 +3792,12 @@ } ] }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3993,6 +4079,12 @@ "node": ">=8" } }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "node_modules/browserslist": { "version": "4.21.9", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", @@ -4290,6 +4382,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/codemirror": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", @@ -4419,6 +4522,12 @@ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/crelt": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", @@ -4946,6 +5055,18 @@ } } }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4992,6 +5113,15 @@ "node": ">=0.4.0" } }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -6110,6 +6240,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -6274,6 +6413,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", @@ -6777,6 +6925,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -6934,6 +7097,15 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -7582,6 +7754,12 @@ "node": ">=12" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", @@ -7682,6 +7860,135 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/mocha/node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -8312,6 +8619,15 @@ "throttleit": "^1.0.0" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -8425,7 +8741,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", @@ -9110,6 +9425,58 @@ "punycode": "^2.1.0" } }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/tslib": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", @@ -9527,6 +9894,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -9755,6 +10128,21 @@ "node": ">= 8" } }, + "node_modules/vite/node_modules/rollup": { + "version": "2.78.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", + "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/vscode-jsonrpc": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", @@ -10361,6 +10749,52 @@ "ajv": ">=8" } }, + "node_modules/workbox-build/node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/workbox-build/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/workbox-build/node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/workbox-build/node_modules/ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -10377,6 +10811,12 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/workbox-build/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, "node_modules/workbox-build/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -10519,6 +10959,12 @@ "workbox-core": "7.0.0" } }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -10550,6 +10996,15 @@ "node": ">=12" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -10584,6 +11039,60 @@ "node": ">=4" } }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", @@ -10594,6 +11103,15 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 7de1c59f2..9e0e0d218 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,12 @@ "scripts": { "serve": "vite serve", "build": "vite build && npm run build.zip", + "build:lang": "npm run build:parser:klipperCfg && npm run build:lang:klipperCfg", + "build:lang:klipperCfg": "rollup --config src/plugins/Codemirror/KlipperCfgLang/rollup.config.js", + "build:parser:klipperCfg": "lezer-generator src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar -o src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js", "format": "npm run format:base -- --write", "format:base": "prettier .", "format:check": "npm run format:base -- --check", - "build-parser": "npx @lezer/generator src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfig.grammar -o src/plugins/CodemirrorLanguages/KlipperConfigLanguage/parser/klipperConfigParser.js", "lint": "eslint --ignore-path .gitignore src", "lint:fix": "npm run lint -- --fix", "build.zip": "cd ./dist && zip -r mainsail.zip ./ -x '**.DS_Store' ./ && cd ..", @@ -21,6 +23,7 @@ "start": "vite build && vite preview", "test": "start-server-and-test preview http://127.0.0.1:4173/ 'cypress run'", "test:ui": "cypress open", + "test:parser:klipperCfg": "mocha --config src/plugins/Codemirror/.mocharc.json src/plugins/Codemirror/KlipperCfgLang/test/test-klipperCfg.js", "changelog": "git cliff v0.0.4..$(git describe --tags $(git rev-list --tags --max-count=1)) --output CHANGELOG.md" }, "dependencies": { @@ -72,7 +75,9 @@ }, "devDependencies": { "@intlify/vite-plugin-vue-i18n": "^2.5.0", + "@lezer/generator": "^1.3.0", "@mdi/js": "^7.0.0", + "@rollup/plugin-node-resolve": "^15.1.0", "@types/file-saver": "^2.0.5", "@types/jmuxer": "^2.0.3", "@types/lodash.kebabcase": "^4.1.6", @@ -88,9 +93,12 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jsonc": "^2.2.1", "eslint-plugin-vue": "^9.0.0", + "mocha": "^10.2.0", "prettier": "^2.5.1", + "rollup": "^2.79.1", "sass": "~1.32", "start-server-and-test": "^1.14.0", + "ts-node": "^10.9.1", "typescript": "^4.5.5", "unplugin-vue-components": "^0.22.12", "vite": "^3.2.7", diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue index 2789a7430..3c1d2599d 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -22,6 +22,11 @@ import { klipperCfg } from '../../plugins/Codemirror/KlipperCfgLang/lang/klipper import { parseErrorLint } from '../../plugins/Codemirror/parseErrorLint' import { indentUnit } from '@codemirror/language' +// for lezer grammar debugging +/* import { logTree } from '../../plugins/Codemirror/printLezerTree' +import { syntaxTree } from '@codemirror/language' +import { parser } from '../../plugins/Codemirror/KlipperCfgLang/dist/klipperCfgParser.es.js' */ + @Component export default class Codemirror extends Mixins(BaseMixin) { private content = '' @@ -50,6 +55,11 @@ export default class Codemirror extends Mixins(BaseMixin) { if (newVal !== cm_value) { this.setCmValue(newVal) } + // for lezer grammar debugging + /* const state = this.cminstance?.state ?? EditorState.create({}) + logTree(syntaxTree(state), state.doc.toString()) + const text = state.doc.toString() + console.log(parser.parse(text) + '') */ } mounted(): void { diff --git a/src/plugins/Codemirror/.mocharc.json b/src/plugins/Codemirror/.mocharc.json new file mode 100644 index 000000000..fbd14399f --- /dev/null +++ b/src/plugins/Codemirror/.mocharc.json @@ -0,0 +1,4 @@ +{ + "extensions": ["ts"], + "node-option": ["loader=ts-node/esm"] +} diff --git a/src/plugins/Codemirror/KlipperCfgLang/lang/klipperCfg.ts b/src/plugins/Codemirror/KlipperCfgLang/lang/klipperCfg.ts index b14a24b49..a6aa5c5e7 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/lang/klipperCfg.ts +++ b/src/plugins/Codemirror/KlipperCfgLang/lang/klipperCfg.ts @@ -1,4 +1,4 @@ -import { parser } from '../parser/klipperCfgParser.js' +import { parser } from '../dist/klipperCfgParser.es.js' import { LRLanguage, LanguageSupport, StreamLanguage, foldNodeProp } from '@codemirror/language' import { parseMixed } from '@lezer/common' import { klipper_config } from '../../../StreamParserKlipperConfig.js' @@ -37,5 +37,5 @@ export function klipperCfg() { /* to generate the parser run: -npx @lezer/generator klipperCfg.grammar -o klipperCfgParser.js +npx lezer-generator klipperCfg.grammar -o klipperCfgParser.js */ diff --git a/src/plugins/Codemirror/KlipperCfgLang/parser/highlight.js b/src/plugins/Codemirror/KlipperCfgLang/parser/highlight.js index 1e7dbc1de..5920fff37 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/parser/highlight.js +++ b/src/plugins/Codemirror/KlipperCfgLang/parser/highlight.js @@ -12,11 +12,15 @@ export const klipperConfigHighlighting = styleTags({ Boolean: t.bool, Number: t.number, Cords: t.number, + Resolution: t.number, + Ratio: t.number, Pin: t.namespace, VirtualPin: t.namespace, Path: t.string, File: t.string, FilePath: t.string, + Ipv4: t.number, + Ipv6: t.number, AutoGenerated: t.regexp, Comment: t.lineComment, diff --git a/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar index 0e51c8766..719233e82 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar +++ b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar @@ -1,32 +1,24 @@ -@precedence { str @cut } +@top Program { (Import | ConfigBlock )+ } -@top Program { (Import | ConfigBlock)+ } +@skip { AutoGenerated (newline | eof) | space | blankLine | Comment newline? } -@skip { Comment newline? | AutoGenerated newline | space | blankLine } - -valueBlock { indent (content newline | valueBlock)+ (dedent | eof) } +valueBlock { indent (content (newline | eof) | valueBlock)+ (dedent | eof) } sep { content (seperator content)+ } +Import { "[" ImportKeyword FilePath "]" (newline | eof) } +ConfigBlock {"[" BlockType Identifier* "]" ( newline Body? | newline? eof ) } -Import { "[" ImportKeyword FilePath "]" newline } -ConfigBlock {"[" BlockType Identifier? "]" newline Body? } - -Body { Option+ } -Option { Parameter ":" Value | GcodeKeyword ":" Jinja2 } +Body { Option+ eof? } +Option { Parameter ":" Value | GcodeKeyword Jinja2 } -Value { value (newline | eof) | newline valueBlock } -Jinja2 { jinja2 (newline | eof) | newline valueBlock } +Value { value (newline | eof) | value? newline valueBlock } +Jinja2 { jinja2 (newline | eof) | jinja2? newline valueBlock } -value { Pin | pins | VirtualPin | VirtualPin | Cords | Number | String | Boolean | Path | FilePath } -pins { sep } -VirtualPin { string ":" string } +value { Pin | pins | VirtualPin | Cords | Number | String | Boolean | Path | FilePath | Resolution | Ratio | Ipv4 | Ipv6 } +pins { sep<(Pin | VirtualPin), ","> } Cords { sep } Number { number } -String { string } -Path { ("/"|"~/")? !str string ("/" string)* } -FilePath { Path "." string} - @context trackIndent from "./tokens.js" @@ -34,28 +26,43 @@ FilePath { Path "." string} @external tokens newlines from "./tokens.js" { newline, blankLine, eof } @tokens { + extAscii { $[a-zA-Z0-9_\-.] } + unixPath { ![/<>|:&{}\t\f #;\[\]\n\r] } + ImportKeyword{ "include" } - GcodeKeyword{ $[a-zA-Z0-9_.\-]* "gcode" } - BlockType { $[a-zA-Z0-9_]+ } - Identifier { $[a-zA-Z0-9_.\-]+ } - Parameter { $[a-zA-Z0-9_]+ } - - string { ($[ a-zA-Z0-9_\-!:]+ | "//") } - jinja2 { $[ \ta-zA-Z0-9_.\-"'{}%=]+ } + GcodeKeyword{ extAscii* "gcode:" } + BlockType { extAscii+ } + Identifier { extAscii+ } + Parameter { extAscii+ } + Path { ("/"|"~/") unixPath+ ("/" unixPath+)* } + FilePath { (Path | unixPath+) "." unixPath+ } + Resolution { $[0-9]+ "x" $[0-9]+ } + Ratio { $[0-9]+ ":" $[0-9]+ } + Ipv4 { $[0-9]+ "." $[0-9]+ "." $[0-9]+ "." $[0-9]+ ((":"|"/") $[0-9]+)? } + hex { $[0-9a-fA-F] } + Ipv6 { (("::" (hex+ ":")* hex+) + | (hex+ (":" hex+)* "::") + | ((hex+ ":")+ (":" hex+)+) + | ((hex+ ":" hex+ ":" hex+ ":" hex+ ":" hex+ ":" hex+))) + ("/" $[0-9]+)?} + + String { ![#;\n\r]+ } + jinja2 { ![#;\n\r]+ } number { "-"? $[0-9]+ ("." $[0-9]*)? } - Boolean { "True" | "False" } - Pin { ("^" | "~")? "!"? "P" $[A-Z] $[0-9]+ } + Boolean { "True" | "False" | "true" | "false" } + Pin { ("^" | "~")? "!"? "P" $[A-Z]? $[0-9.]+ } + VirtualPin { ("^" | "~")? "!"? extAscii+ ":" extAscii+ } AutoGenerated { "#*#" ![\n\r]* } - Comment { "#" ![\n\r]* } + Comment { ("#"|";") ![\n\r]* } space { $[ \t\f]+ } - @precedence { space, jinja2, string } - @precedence { AutoGenerated, Comment } - @precedence { number, Pin, Boolean, ImportKeyword, string, "/" } - @precedence { ImportKeyword, BlockType } - @precedence { GcodeKeyword, Parameter } + @precedence { space, jinja2, String } // because spaces are allowed in string/jinja2 + @precedence { AutoGenerated, Comment } // AutoGenerated also starts with a # + @precedence { Resolution, Ipv4, Ipv6, Ratio, number, Pin, VirtualPin, Boolean, ImportKeyword, FilePath, Path, String } + @precedence { ImportKeyword, BlockType }// because the ImportKeyword can be canerated with extAscii + @precedence { GcodeKeyword, Parameter } // because the GcodeKeyword can be canerated with extAscii } @external propSource klipperConfigHighlighting from "./highlight" @@ -63,4 +70,4 @@ FilePath { Path "." string} @detectDelim // to generate the parser run: -// npx @lezer/generator klipperCfg.grammar -o klipperCfgParser.js \ No newline at end of file +// npx lezer-generator klipperCfg.grammar -o klipperCfgParser.js \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js deleted file mode 100644 index c1709c89e..000000000 --- a/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js +++ /dev/null @@ -1,20 +0,0 @@ -// This file was generated by lezer-generator. You probably shouldn't edit it. -import {LRParser} from "@lezer/lr" -import {indentation, newlines, trackIndent} from "./tokens.js" -import {klipperConfigHighlighting} from "./highlight" -export const parser = LRParser.deserialize({ - version: 14, - states: "*[OcQUOOPhOSOOOpQUO'#CdOOQQ'#Cs'#CsQcQUOOPxOQO)C>vO}QYO,58zO!YQbO,59OOOQQ-E6q-E6qPOOO/'4b/'4bO!bQUO'#CcO!pQYO'#CcO!uQUO'#CbO!zQUO1G.fO#PQUO1G.jO#UQUO1G.jO#ZQYO'#CtO#`QUO,58}O#`QUO,58}O#nQYO,58|O#sQUO7+$QO#xQrO7+$UO$WQUO7+$UOOQQ,59`,59`OOQQ-E6r-E6rO$]QUO1G.iOOQQ1G.h1G.hOOQQ<e#Y#Z/`#Z#[8e#[#o/`#o#p$q#q#r$qn>pbYS!R`eWyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![/`![!]'Q!_!`$q!c!}/`#R#S/`#T#Z/`#Z#[8e#[#o/`#o#p$q#q#r$qn@TbYS!R`!PQyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!PA]!Q![?x![!]'Q!_!`$q!c!}/`#R#S/`#T#Z/`#Z#[8e#[#o/`#o#p$q#q#r$qnAf`YS!R`!PQXY$qpq$qrs$quv$qwx$q}!O0q!O!P0q!Q![A]!_!`$q!c!}0q#R#S0q#T#Z0q#Z#[1z#[#o0q#o#p$q#q#r$qmBq`zPYS!R`XY$qpq$qrs$quv$qwx$q}!O0q!O!P0q!Q![0q!_!`$q!c!}0q#R#S0q#T#Z0q#Z#[1z#[#o0q#o#p$q#q#r$q~CxPw~!P!QC{QDQOyQoDabYS!R`]W!PQXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!PA]!Q![DQ![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoEvbYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoG]dYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#VEi#V#WHk#W#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoHxdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#cEi#c#dJW#d#oEi#o#p$q#q#r$qoJedYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#WEi#W#XKs#X#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoLQdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#XEi#X#YM`#Y#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qoMobYS!R`eW]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qR! OW|PyQpq'Qqr'Q}!O'Q!Q!['Q![!]'Q!c!}'Q#R#S'Q#T#o'Qo! ucYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#U!#Q#U#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!#_dYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#`Ei#`#a!$m#a#oEi#o#p$q#q#r$qo!$zdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#gEi#g#h!&Y#h#oEi#o#p$q#q#r$qo!&gdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#XEi#X#Y!'u#Y#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!(UbYS!R`]WdQXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!)kbYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}!*s#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!+QbYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![!,Y![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!,ibYS!R`]W_QXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![!,Y![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!.OdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#fEi#f#g!/^#g#oEi#o#p$q#q#r$qo!/kdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#iEi#i#j!&Y#j#oEi#o#p$q#q#r$q~!1OOv~~!1TO{~Q!1WQqr!1^!r!s!1dQ!1aP!r!s!1dQ!1gP!c!}!1jQ!1mP!Q![!1pQ!1uP_Q!Q![!1po!2VdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#bEi#b#c!3e#c#oEi#o#p$q#q#r$qo!3rdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#VEi#V#W!5Q#W#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!5_dYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#`Ei#`#a!6m#a#oEi#o#p$q#q#r$qo!6zdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#iEi#i#j!8Y#j#oEi#o#p$q#q#r$qo!8gdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#WEi#W#X!9u#X#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!:SdYS!R`]WXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#XEi#X#Y!;b#Y#ZEi#Z#[GO#[#oEi#o#p$q#q#r$qo!;qbYS!R`]WTPXPyQXY$qpq'oqr'Qrs$quv$qwx$q}!O/`!O!P0q!Q![Ei![!]'Q!_!`$q!c!}Ei#R#SEi#T#ZEi#Z#[GO#[#oEi#o#p$q#q#r$q~!<|Rqr!1^!P!Q!=V!r!s!1d~!=[Ox~", - tokenizers: [indentation, newlines, 0, 1, 2, 3, 4], - topRules: {"Program":[0,3]}, - tokenPrec: 381 -}) diff --git a/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.terms.js b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.terms.js deleted file mode 100644 index 04766ba2b..000000000 --- a/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.terms.js +++ /dev/null @@ -1,29 +0,0 @@ -// This file was generated by lezer-generator. You probably shouldn't edit it. -export const - indent = 31, - dedent = 32, - newline = 33, - blankLine = 34, - eof = 35, - Comment = 1, - AutoGenerated = 2, - Program = 3, - Import = 4, - ImportKeyword = 5, - FilePath = 6, - Path = 7, - ConfigBlock = 8, - BlockType = 9, - Identifier = 10, - Body = 11, - Option = 12, - Parameter = 13, - Value = 14, - Pin = 15, - VirtualPin = 16, - Cords = 17, - Number = 18, - String = 19, - Boolean = 20, - GcodeKeyword = 21, - Jinja2 = 22 diff --git a/src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js b/src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js index 7a470e31a..d343a0468 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js +++ b/src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js @@ -21,7 +21,7 @@ export const newlines = new ExternalTokenizer( while (input.next == space || input.next == tab) { input.advance() } - if (input.next == newline || input.next == carriageReturn) input.acceptToken(blankLine, 1) + if (isLineBreak(input.next)) input.acceptToken(blankLine, 1) } else if (isLineBreak(input.next)) { input.acceptToken(newlineToken, 1) } @@ -72,7 +72,7 @@ export const trackIndent = new ContextTracker({ return context.depth < 0 ? context.parent : context }, shift(context, term, stack, input) { - if (term == indent) return new IndentLevel(context, countIndent(input.read(input.pos, stack.pos))) + if (term == indent) return new IndentLevel(context, countIndent(input.read(input.pos, stack.pos)) >= 1 ? 1 : 0) if (term == dedent) return context.parent return context }, diff --git a/src/plugins/Codemirror/KlipperCfgLang/rollup.config.js b/src/plugins/Codemirror/KlipperCfgLang/rollup.config.js new file mode 100644 index 000000000..306f7eeb3 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/rollup.config.js @@ -0,0 +1,19 @@ +import { nodeResolve } from '@rollup/plugin-node-resolve' + +export default { + input: 'src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js', + output: [ + { + format: 'cjs', + file: 'src/plugins/Codemirror/KlipperCfgLang/dist/klipperCfgParser.cjs', + }, + { + format: 'es', + file: 'src/plugins/Codemirror/KlipperCfgLang/dist/klipperCfgParser.es.js', + }, + ], + external(id) { + return !/^[\.\/]/.test(id) + }, + plugins: [nodeResolve()], +} diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/test-klipperCfg.js b/src/plugins/Codemirror/KlipperCfgLang/test/test-klipperCfg.js new file mode 100644 index 000000000..e26c728a4 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/test-klipperCfg.js @@ -0,0 +1,27 @@ +import { parser } from '../dist/klipperCfgParser.cjs' +import { fileTests } from '../../mochaFileTests.js' +import * as fs from 'fs' +import * as path from 'path' + +const caseDir = 'src/plugins/Codemirror/KlipperCfgLang/test/testCases' +const testConfigsDir = 'src/plugins/Codemirror/KlipperCfgLang/test/testConfigs' + +for (let file of fs.readdirSync(caseDir)) { + if (!/\.txt$/.test(file)) continue + + let result = /^[^.]+/.exec(file) + let name = result ? result[0] : 'default-name' + describe(name, () => { + for (let { name, run } of fileTests(fs.readFileSync(path.join(caseDir, file), 'utf8'), file)) + it(name, () => run(parser)) + }) +} + +for (let file of fs.readdirSync(testConfigsDir)) { + let result = /^[^.]+/.exec(file) + let name = result ? result[0] : 'default-name' + describe(name, () => { + for (let { name, run } of fileTests(fs.readFileSync(path.join(testConfigsDir, file), 'utf8'), file, true)) + it(name, () => run(parser)) + }) +} diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testCases/blocktype.txt b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/blocktype.txt new file mode 100644 index 000000000..ead029e1c --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/blocktype.txt @@ -0,0 +1,25 @@ +# 1) block type with special characters +[test_-2a] +==> +Program(ConfigBlock(BlockType)) + + + +# 2) block type with non valid characters +[mcu123.:%=] +==> +error + + + +# 3) block type and identifier with special characters +[mcu test123_-4] +==> +Program(ConfigBlock(BlockType,Identifier)) + + + +# 4) block type and identifier with non valid characters +[mcu test123.:%=] +==> +error \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testCases/commentBlankline.txt b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/commentBlankline.txt new file mode 100644 index 000000000..3d9bf3996 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/commentBlankline.txt @@ -0,0 +1,121 @@ +# 1) Comment lines at the beginning with configuration underneath +# test comment +# test comment +[include test.cfg] +[include test2.cfg] +==> +Program( + Comment, + Comment, + Import(ImportKeyword,FilePath), + Import(ImportKeyword,FilePath)) + + + +# 2) blank lines at the beginning with configuration underneath + + +[include test.cfg] +[include test2.cfg] +==> +Program( + Import(ImportKeyword,FilePath), + Import(ImportKeyword,FilePath)) + + + +# 3) comment + blank line as first line with configuration underneath +# test comment + +[include test.cfg] +[include test2.cfg] +==> +Program( + Comment, + Import(ImportKeyword,FilePath), + Import(ImportKeyword,FilePath)) + + + +# 4) Comment line between config blocks / parameters +[mcu] +serial: /dev/ttyAMA0 +# test comment +restart_method: command +# test comment +[adxl345] +cs_pin: rpi:None +==> +Program( + ConfigBlock(BlockType,Body( + Option(Parameter,Value(Path)), + Comment, + Option(Parameter,Value(String)))), + Comment, + ConfigBlock(BlockType,Body( + Option(Parameter,Value(VirtualPin))))) + + + +# 5) blank line between config blocks / parameters +[mcu] +serial: /dev/ttyAMA0 + +restart_method: command + +[adxl345] +cs_pin: rpi:None +==> +Program( + ConfigBlock(BlockType,Body( + Option(Parameter,Value(Path)), + Option(Parameter,Value(String)))), + ConfigBlock(BlockType,Body( + Option(Parameter,Value(VirtualPin))))) + + + +# 6) Comment after a [Block], a parameter, and after a value +[mcu] # test comment +serial: /dev/ttyAMA0 # test comment +restart_method: # test comment + command # test comment +==> +Program( + ConfigBlock(BlockType,Comment,Body( + Option(Parameter,Value(Path,Comment)), + Option(Parameter,Comment,Value(String,Comment))))) + + + + +# 7) Comment after all value types +[test] +path: /dev/ttyAMA0 # test comment +filepath: /dev/test.txt # test comment +string: command # test comment +number: 1 # test comment +cords: 1,2 # test comment +pin: PE3 # test comment +pins: PE3,PE4 # test comment +virtualPin: rpi:None # test comment +boolean: true # test comment +resolution: 1x2 # test comment +ipv4: 10.22.22.2 # test comment +ipv6: ::1/128 # test comment +==> +Program( + ConfigBlock(BlockType,Body( + Option(Parameter,Value(Path,Comment)), + Option(Parameter,Value(FilePath,Comment)), + Option(Parameter,Value(String,Comment)), + Option(Parameter,Value(Number,Comment)), + Option(Parameter,Value(Cords,Comment)), + Option(Parameter,Value(Pin,Comment)), + Option(Parameter,Value(Pin,Pin,Comment)), + Option(Parameter,Value(VirtualPin,Comment)), + Option(Parameter,Value(Boolean,Comment)), + Option(Parameter,Value(Resolution,Comment)), + Option(Parameter,Value(Ipv4,Comment)), + Option(Parameter,Value(Ipv6,Comment)) + ))) \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testCases/import.txt b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/import.txt new file mode 100644 index 000000000..d86802eb4 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/import.txt @@ -0,0 +1,25 @@ +# 1) import with wrong syntax (missing bracket) +[include test.cfg +==> +error + + + +# 2) import with wrong syntax (missing file path) +[include ] +==> +error + + + +# 3) import with wrong syntax (wrong keyword) +[includ test.cfg] +==> +Program(ConfigBlock(BlockType,Identifier)) + + + +# 4) korrect import +[include test.cfg] +==> +Program(Import(ImportKeyword,FilePath)) \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testCases/parameter.txt b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/parameter.txt new file mode 100644 index 000000000..ecfa52ecd --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/parameter.txt @@ -0,0 +1,86 @@ +# 1) parameter at non valid positions +speed: 50 +[mcu] +serial: /dev/ttyAMA0 +[include test.cfg] +restart_method: command +==> +Program( + ConfigBlock(⚠,BlockType,⚠,Identifier,⚠), + ConfigBlock(BlockType,Body( + Option(Parameter,Value(Path)))), + Import(ImportKeyword,FilePath), + ConfigBlock(⚠,BlockType,⚠,Identifier,⚠)) + + + +# 2) parameter without following ":" + value/valueBlock +[mcu] +serial +[adxl345] +==> +error + + + +# 3) parameter-name with special characters +[mcu] +serial_tem-3: 1 +==> +Program( + ConfigBlock(BlockType,Body( + Option(Parameter,Value(Number))))) + + + +# 4) parameter-name with non-valid characters +[mcu] +serial@: /dev/ttyAMA0 +==> +error + + + +# 5) parameter with normal value +[mcu] +num: 100 +==> +Program( + ConfigBlock(BlockType,Body( + Option(Parameter,Value(Number))))) + + + +# 6) parameter with valueBlock +[mcu] +cords: + 10, 20 + 220, 210 +==> +Program( + ConfigBlock(BlockType,Body( + Option(Parameter,Value(Cords,Cords))))) + + + +# 7) parameter ending on "gcode" + value +[commands] +start_gcode: M106 S0 +==> +Program( + ConfigBlock(BlockType,Body( + Option(GcodeKeyword,Jinja2)))) + + + +# 8) parameter ending on "gcode" + valueBlock +[commands] +end_gcode: + M104 S0 + M140 S0 +# comment +==> +Program( + ConfigBlock(BlockType, + Body(Option(GcodeKeyword,Jinja2))), + Comment) \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testCases/structure.txt b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/structure.txt new file mode 100644 index 000000000..51d19cda5 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/structure.txt @@ -0,0 +1,87 @@ +# 1) only import +[include test.cfg] +==> +Program(Import(ImportKeyword,FilePath)) + + + +# 2) only empty config block +[mcu] +==> +Program(ConfigBlock(BlockType)) + + + +# 3) only config block +[mcu] +serial: /dev/ttyAMA0 +restart_method: command +==> +Program( + ConfigBlock(BlockType,Body( + Option(Parameter,Value(Path)), + Option(Parameter,Value(String))))) + + + +# 4) import between config blocks +[mcu] +serial: /dev/ttyAMA0 +[include test.cfg] +[adxl345] +cs_pin: rpi:None +==> +Program( + ConfigBlock(BlockType,Body(Option(Parameter,Value(Path)))), + Import(ImportKeyword,FilePath), + ConfigBlock(BlockType,Body(Option(Parameter,Value(VirtualPin))))) + + + +# 5) import + eof +[include test.cfg]==> +Program(Import(ImportKeyword,FilePath)) + + + +# 6) empty config block + eof +[mcu]==> +Program(ConfigBlock(BlockType)) + + + +# 7) config block + value + eof +[mcu] +restart_method: command==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String))))) + + + +# 8) config block + valueBlock + eof +[mcu] +restart_method: + command==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String))))) + + + +# 9) config block + comment + eof +[mcu] +restart_method: command +# test==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String)))),Comment) + + + +# 10) config block + value + comment + eof +[mcu] +restart_method: command # test==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String)))),Comment) + + + + + + + + diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testCases/value.txt b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/value.txt new file mode 100644 index 000000000..8d7891134 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testCases/value.txt @@ -0,0 +1,296 @@ +# 1) normal Pin +[stepper] +pin: PE1 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Pin))))) + + + +# 2) inverted Pin +[stepper] +pin: !PE1 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Pin))))) + + + +# 3) pullup/low Pin +[stepper] +pin: ^PE1 +pin: ~PE2 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Pin)),Option(Parameter,Value(Pin))))) + + + +# 4) combination of iverted and pullup/low pin +[stepper] +pin: ^!PE1 +pin: ~!PE2 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Pin)),Option(Parameter,Value(Pin))))) + + + +# 5) wrong combination of iverted and pullup/low pin +[stepper] +pin: !^PE1 +pin: !+PE1 +pin: ~^PE2 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String)),Option(Parameter,Value(String)),Option(Parameter,Value(String))))) + + + +# 6) lowercase Pin +[stepper] +pin: pe1 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String))))) + + + +# 7) pins +[stepper] +pin: PE1, PE2 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Pin,Pin))))) + + + +# 8) virtual pin +[stepper] +pin: rpi:None +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(VirtualPin))))) + + + +# 9) virtual pin with non valid characters +[stepper] +pin: rpi!:None* +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String))))) + + + +# 10) number +[stepper] +microsteps: 32 +homing_speed: 30.3 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Number)),Option(Parameter,Value(Number))))) + + + +# 11) negativ number +[stepper] +microsteps: -32 +homing_speed: -30.3 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Number)),Option(Parameter,Value(Number))))) + + + +# 12) float but "," instead of "." +[stepper] +homing_speed: -30,3 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Cords))))) + + + +# 13) cords +[resonance_tester] +points3d: 110,110,20 +points2d: 110,-110 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Cords)),Option(Parameter,Value(Cords))))) + + + +# 14) mixing float/int in cords +[resonance_tester] +points3d: 110,110.23,20.6 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Cords))))) + + + +# 15) normal string +[printer] +kinematics: coreXY123 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String))))) + + + +# 16) string with whitespaces +[printer] +kinematics: core xy +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String))))) + + + +# 17) string with special characters +[printer] +kinematics: corexy!_:/-gtX +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String))))) + + + +# 18) string with special characters 2 +[printer] +kinematics: {'%05.1f' % (printer.toolhead)} +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String))))) + + + +# 19) boolean +[tmc] +interpolate: True +interpolate: true +interpolate: False +interpolate: false +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Boolean)),Option(Parameter,Value(Boolean)),Option(Parameter,Value(Boolean)),Option(Parameter,Value(Boolean))))) + + + +# 20) Path +[mcu] +serial: /tmp/klipper_host_mcu +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Path))))) + + + +# 21) FilePath +[mcu] +serial: /tmp/test.txt +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(FilePath))))) + + + +# 22) path of a file in same directory +[mcu] +serial: test.txt +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(FilePath))))) + + + +# 23) parth starting with "./", "../", "~/" or without "/" +[mcu] +serial: ./tmp/test.txt +serial: ../tmp/test.txt +serial: ~/tmp/test.txt +serial: tmp/test.txt +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(String)),Option(Parameter,Value(String)),Option(Parameter,Value(FilePath)),Option(Parameter,Value(String))))) + + + +# 24) Resolution +[display] +resolution: 1280x720 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Resolution))))) + + + +# 25) non valid Resolution +[display] +resolution: 1280x720.8 +==> +error + + + +# 26) Ipv4 +[server] +host: 0.0.0.0 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Ipv4))))) + + + +# 27) Ipv4 with port +[server] +host: 0.0.0.0:8123 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Ipv4))))) + + + +# 28) ipv4 with subnetsize +[server] +host: 0.0.0.0/24 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Ipv4))))) + + + +# 29) Ipv4 with wrong syntax +[server] +host: 0.0.0/24 +==> +error + + + +# 30) Ipv6 +[server] +host: ::1 +host: FE80:: +host: FE80::1 +host: FE80:1::1:1 +host: 1:1:1:1:1:1 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Ipv6)),Option(Parameter,Value(Ipv6)),Option(Parameter,Value(Ipv6)),Option(Parameter,Value(Ipv6)),Option(Parameter,Value(Ipv6))))) + + + +# 31) ipv6 with subnetsize +[server] +host: ::1/128 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Ipv6))))) + + + +# 32) Ipv6 with wrong syntax +[server] +host: 1:1/128 +==> +error + + + +# 33) Empty value: +[server] +host: +restart_method: command +==> +error + + + +# 35) Empty value with whitespaces: +[server] +host: +restart_method: command +==> +error + + + +# 36) Value with leading and trailing whitespaces: +[mcu] +serial: 16x16 +==> +Program(ConfigBlock(BlockType,Body(Option(Parameter,Value(Resolution))))) \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf new file mode 100644 index 000000000..9f150dc5c --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf @@ -0,0 +1,101 @@ +[main] +# Invert axis in move panel. Default is False. Change to true to invert +invert_x: False +invert_y: False +invert_z: False +# Time (seconds) before the Job Status page reverts to main menu after a successful job +job_complete_timeout: 30 +# Time (seconds) before the Job Status page reverts to main menu after a successful job. +# If this option is 0, the user must click on a button to go back to the main menu. +job_error_timeout: 0 +# Specify the language +# The language can be specified here instead of using the system default language. +language: en +# Allows the cursor to be displayed on the screen +show_cursor: False + +[printer Voron V2.660] +# Define the moonraker host/port if different from 127.0.0.1 and 7125 +moonraker_host: 127.0.0.1 +moonraker_port: 7125 +# Moonraker API key if this is not connecting from a trusted client IP +moonraker_api_key: False +# Define the z_babystep intervals in a CSV list. Currently only 2 are supported +z_babystep_values: 0.1, 0.05 + +#~# --- Do not edit below this line. This section is auto generated --- #~# + +#~# +#~# [main] +#~# language = en +#~# print_sort_dir = date_desc +#~# screen_blanking = 300 +#~# theme = colorized +#~# side_macro_shortcut = False +#~# +#~# [displayed_macros Printer] +#~# bed_mesh_calibrate = False +#~# cancel_print = False +#~# dump_parameters = False +#~# dump_config = False +#~# dump_settings = False +#~# mesh_load = False +#~# m204 = False +#~# m141 = False +#~# man_resonances = False +#~# m600 = False +#~# mesh_store = False +#~# prime_line = False +#~# m300 = False +#~# _caselight_off = False +#~# pause = False +#~# resume = False +#~# _display_plate = False +#~# rst_service = False +#~# rst_filter = False +#~# print_end = False +#~# _extruder_on = False +#~# _display_on = False +#~# _filament_ball = False +#~# test_probe_accuracy = False +#~# quad_gantry_level = False +#~# _list_plates = False +#~# _lcd_knob = False +#~# _add_new_plate = False +#~# _filter_info = False +#~# print_start = False +#~# _runout_info = False +#~# _display_state = False +#~# _add_print_time = False +#~# _extruder_off = False +#~# _set_filter = False +#~# _bed_off = False +#~# _caselight_on = False +#~# _psu_off = False +#~# _vent_info = False +#~# _g32 = False +#~# _bed_on = False +#~# _print_info1 = False +#~# _set_plate_offset = False +#~# _print_info2 = False +#~# _print_ar = False +#~# _filter_on = False +#~# _display_print_time = False +#~# _set_caselight = False +#~# _cg28 = False +#~# _heater_on = False +#~# _display_off = False +#~# _change_plate_name = False +#~# _change_plate_offset = False +#~# _set_z_current = False +#~# _sd_printer_stats = False +#~# _sd_print_stats = False +#~# _wipe = False +#~# _remove_plate = False +#~# _init_plate_array = False +#~# _print_time = False +#~# _set_acc = False +#~# _set_plate = False +#~# _select_pa = False +#~# _shutdown_pi = False +#~# diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg new file mode 100644 index 000000000..484d2b15e --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg @@ -0,0 +1,54 @@ +##################################################################### +# Macro +##################################################################### +# +# This section contains basic macros that needed in several other +# files. Getting them all to a single place should help to only +# use what needed without hunting down several other files. +# +##################################################################### +## Clear display output after Duration in seconds +## Use: UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=1 +[delayed_gcode _CLEAR_DISPLAY] +gcode: + M117 + +## Reset SD File after Print_END or CANCEL_PRINT +## This will avoid the reprint option in Mainsail after a print is done +[delayed_gcode _DELAY_SDCARD_RESET_FILE] +gcode: + SDCARD_RESET_FILE + +[gcode_macro DIRECT_MOVE] +gcode: + {% set out_param = ["G0"] %} + {% set _dummy = out_param.append("X%s" % params.X) if params.X %} + {% set _dummy = out_param.append("Y%s" % params.Y) if params.Y %} + {% set _dummy = out_param.append("Z%s" % params.Z) if params.Z %} + {% set _dummy = out_param.append("E%s" % params.E) if params.E %} + {% set _dummy = out_param.append("F%s" % params.F) if params.F %} + {out_param|join(" ")} + +## action_respond_info will be always executed at the beginning of an macro evaluation. +## Use _PRINT_AR if you need the order of several console outputs in the order given by the macro +## Use: _PRINT_AR T="QGL forced by PRINT_START" +[gcode_macro _PRINT_AR] +description: Helper: Action response +gcode: + {% if params.SHOW_LCD|default('false') == 'true' %} M117 {params.T} {% endif %} + {action_respond_info(params.T)} + +[gcode_macro M115] +description: Print host and mcu version +rename_existing: M115.1 +gcode: + {% set out = ['mcu build version:'] %} + {% for name1 in printer %} + {% for name2 in printer[name1] %} + {% if name2 is in ['mcu_version'] %} + {% set _dummy = out.append("%s: %s" % (name1, printer[name1][name2])) %} + {% endif %} + {% endfor %} + {% endfor %} + {action_respond_info(out|join("\n"))} + M115.1 diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg new file mode 100644 index 000000000..a30d7e44e --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg @@ -0,0 +1,133 @@ +##################################################################### +# Bed Mesh Definition +##################################################################### +[bed_mesh] +## Start end end point of mesh +mesh_min: 30,30 +mesh_max: 320,320 +speed: 1000 +## The height (in mm) that the head should be commanded to move to +## just prior to starting a probe operation. The default is 5. +horizontal_move_z: 7.5 ; MagProbe Klicky +#horizontal_move_z: 4 ; Vinda or Omron +probe_count: 9,9 +## The interpolation algorithm to use. May be either "lagrange" +## or "bicubic". This option will not affect 3x3 grids, which +## are forced to use lagrange sampling. Default is lagrange. +algorithm: bicubic +##[(7x7)-1] / 2 = 24 +##[(5x5)-1] / 2 = 12 +relative_reference_index: 40 +## The gcode z position in which to start phasing out z-adjustment +## when fade is enabled. Default is 1.0. +#fade_start: 1 +## The gcode z position in which phasing out completes. When set +## to a value below fade_start, fade is disabled. It should be +## noted that fade may add unwanted scaling along the z-axis of a +## print. If a user wishes to enable fade, a value of 10.0 is +## recommended. Default is 0.0, which disables fade. +#fade_end: 10 +## The z position in which fade should converge. When this value is set +## to a non-zero value it must be within the range of z-values in the mesh. +## Users that wish to converge to the z homing position should set this to 0. +## Default is the average z value of the mesh. +#fade_target: 0 +## The distance (in mm) along a move to check for split_delta_z. +## This is also the minimum length that a move can be split. Default +## is 5.0. +move_check_distance: 3 +## The amount of Z difference (in mm) along a move that will +## trigger a split. Default is .025. +split_delta_z: 0.0125 +## A comma separated pair of integers (X,Y) defining the number of +## points per segment to interpolate in the mesh along each axis. A +## "segment" can be defined as the space between each probed +## point. The user may enter a single value which will be applied +## to both axes. Default is 2,2. +mesh_pps: 2,2 +## When using the bicubic algorithm the tension parameter above +## may be applied to change the amount of slope interpolated. +## Larger numbers will increase the amount of slope, which +## results in more curvature in the mesh. Default is .2. +#bicubic_tension: 0.2 + +##################################################################### +# Macros +##################################################################### +# +# Warning: If you use the flexplate names insight your stored mesh's than: +# - insure that it does not contain spaces +# - insure that it does not contain special charakters +# - insure that it does not contain german "umlaut" (äöü and ß) +# +# All macros are writen in the way that they will work without a [save_variables] +# block and also without the flexplate.cfg +# +##################################################################### +[gcode_macro BED_MESH_CALIBRATE] +description: Perform QGL and bed mesh leveling +rename_existing: BED_MESH_CALIBRATE_BASE +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% if "xyz" not in printer.toolhead.homed_axes %} G28 {% endif %} + BED_MESH_CLEAR + {% if not printer.quad_gantry_level.applied %} QUAD_GANTRY_LEVEL PARK=false {% endif %} + {% if user.hw.mag_probe.ena %} ATTACH_PROBE {% endif %} + BED_MESH_CALIBRATE_BASE {rawparams} + {% if user.hw.mag_probe.ena %} DETACH_PROBE {% endif %} + +## use BED_MESH_STORE -> generate MESH and park in the middle +## use BED_MESH_STORE SAVE=now -> generate MESH and park in the middle and save immediately +## use BED_MESH_STORE PARK=false -> generate MESH +## use BED_MESH_STORE SAVE=later -> generate MESH and park in the middle and save it later +[gcode_macro BED_MESH_STORE] +description: Generate a mesh, name it and run save_config if requested +variable_save_at_end: False +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set name = '' if printer.save_variables.variables.plates is not defined + else printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].name + '-' %} + {% set mesh_name = name + "Bed_Temp-" + printer.heater_bed.target|int|string + "C" %} + {action_respond_info("BED_MESH: Generate \"%s\"" % mesh_name)} + BED_MESH_CALIBRATE PROFILE={mesh_name} + {% if params.PARK|default('true')|lower == 'true' %} + G90 ; set absolute + G0 Z{user.park.bed.z} F{user.speed.z_hop} ; lift first + G0 X{user.park.bed.x} Y{user.park.bed.y} F{user.speed.travel} ; park toolhead + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set it back to relative + {% endif %} + {% if params.SAVE|default('none')|lower == 'now' %} + _PRINT_AR T="BED_MESH: Save Config!" + SAVE_CONFIG + {% elif params.SAVE|default('none')|lower == 'later' %} + _PRINT_AR T="BED_MESH: Save Config after print done" + SET_GCODE_VARIABLE MACRO=BED_MESH_STORE VARIABLE=save_at_end VALUE=True + {% endif %} + +## use BED_MESH_LOAD -> load an existing MESH +## use BED_MESH_LOAD AUTO=true -> load an existing MESH or generate a new one and prepare it to be saved after print end +[gcode_macro BED_MESH_LOAD] +description: Load an existing mesh or generate a new one +gcode: + {% set name = '' if printer.save_variables.variables.plates is not defined + else printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].name + '-' %} + {% set mesh_name = name + "Bed_Temp-" + printer.heater_bed.target|int|string + "C" %} + {% if printer.configfile.config["bed_mesh " + mesh_name] is defined %} + {action_respond_info("BED_MESH: \"%s\" loaded" % mesh_name)} + BED_MESH_CLEAR + BED_MESH_PROFILE LOAD={mesh_name} + {% elif params.AUTO|default('false')|lower == 'true' %} + {action_respond_info("BED_MESH: \"%s\" needs to be generated" % mesh_name)} + BED_MESH_STORE SAVE=none PARK=false + {% else %} + {action_respond_info("BED_MESH: ERROR \"%s\" not defined" % mesh_name)} + {% endif %} + +## add this to your PRINT_END to save a mesh if needed 10 seconds after print ended +## UPDATE_DELAYED_GCODE ID=_BED_MESH_SAVE DURATION=10 +[delayed_gcode _BED_MESH_SAVE] +gcode: + {% if printer["gcode_macro MESH_STORE"].save_at_end %} + {action_respond_info("BED_MESH: Save Config!")} + SAVE_CONFIG + {% endif %} \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg new file mode 100644 index 000000000..2faeda0b0 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg @@ -0,0 +1,29 @@ +##################################################################### +# Caselight pin Definition +##################################################################### +## Caselight - XYE board, HB Connector +[output_pin caselight] +pin: P2.5 +pwm: true +hardware_pwm: true +shutdown_value: 0 +cycle_time: 0.0001 + +##################################################################### +# Macros +##################################################################### +[gcode_macro _CASELIGHT_ON] +description: Helper: Light on +gcode: + SET_PIN PIN=caselight VALUE={printer['gcode_macro _USER_VARIABLE'].peripheral.caselight.on_val} + {action_respond_info("Caselight on")} + +[gcode_macro _CASELIGHT_OFF] +description: Helper: Light off +gcode: + SET_PIN PIN=caselight VALUE=0.0 + {action_respond_info("Caselight off")} + +[gcode_macro CASELIGHT] +description: Toggle light +gcode: {% if printer['output_pin caselight'].value == 0 %} _CASELIGHT_ON {% else %} _CASELIGHT_OFF {% endif %} \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf new file mode 100644 index 000000000..f233bf84d --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf @@ -0,0 +1,41 @@ +#### crowsnest.conf +#### This is mainsail / MainsailOS default config. +#### See: +#### https://github.com/mainsail-crew/crowsnest/blob/master/README.md +#### for details to configure to your needs. + + +##################################################################### +#### ##### +#### Information about ports and according URL's ##### +#### ##### +##################################################################### +#### ##### +#### Port 8080 equals /webcam/?action=[stream/snapshot] ##### +#### Port 8081 equals /webcam2/?action=[stream/snapshot] ##### +#### Port 8082 equals /webcam3/?action=[stream/snapshot] ##### +#### Port 8083 equals /webcam4/?action=[stream/snapshot] ##### +#### ##### +##################################################################### +[crowsnest] +log_path: ~/klipper_logs/crowsnest.log # Default logfile in ~/klipper_logs/crowsnest.log +log_level: verbose # Valid Options are quiet/verbose/debug +delete_log: false # Deletes log on every restart, if set to true + +[cam Main] +mode: mjpg # mjpg/rtsp +port: 8080 # Port +device: /dev/v4l/by-id/usb-046d_HD_Pro_Webcam_C920_BAB4B21F-video-index0 +resolution: 1920x1080 # widthxheight format +max_fps: 30 # If Hardware Supports this it will be forced, ohterwise ignored/coerced. +v4l2ctl: focus_auto=0,focus_absolute=30 +#custom_flags: # You can run the Stream Services with custom flags. + +#[cam test] +#streamer: mjpg +#port: 8081 +#device: /dev/v4l/by-id/usb-HD_USB_Camera_HD_USB_Camera_2020042508-video-index0 +#resolution: 1280x960 +#max_fps: 15 +#custom_flags: -pl 50hz -ex 300 -co 40 --gain 2 + diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg new file mode 100644 index 000000000..f9df81228 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg @@ -0,0 +1,67 @@ +# Use: +# - DUMP_PARAMETER print all parameter expect configfile +# - DUMP_PARAMETER P='gcode_macro _TEST' print the defined parameter group +# - DUMP_PARAMETER C='printer' print the defined config values +# - DUMP_PARAMETER S='printer' print the defined settings values +[gcode_macro DUMP_PARAMETER] +description: Debug: Print entries of the printer object +gcode: + {% set config = True if params.C or params.S else False %} + {% set path = 'config' if params.C + else 'settings' if params.S %} + {% set search = params.C if params.C + else params.S if params.S + else params.P if params.P %} + {% set out = [] %} + {% for name1 in printer|sort %} + {% if config %} ; print the searched printer.configfile[path] parameter + {% if name1 is in ['configfile'] %} + {% for name2 in printer[name1][path]|sort %} + {% if name2 is in [search] %} + {% for name3, value in printer[name1][path][name2].items()|sort %} + {% set _dummy = out.append("printer.configfile.%s['%s'].%s = %s" % + (path, name2, name3, value)) %} + {% endfor %} + {% endif %} + {% endfor %} + {% endif %} + {% else %} + {% for name2, value in printer[name1].items()|sort %} ; search for anything expext printer.configfile + {% if search is not defined and name1 is not in ['configfile'] %} ; print all printer. parameter + {% set _dummy = out.append("printer['%s'].%s = %s" % (name1, name2, value)) %} + {% elif search is defined and name1 is in [search] %} ; print the searched printer. parameter + {% set _dummy = out.append("printer['%s'].%s = %s" % (name1, name2, value)) %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% if out|length > 0 %} + {action_respond_info(out|join("\n"))} + {% else %} + {action_respond_info("Nothing found for \"DUMP_PARAMETER %s\"" % rawparams)} + {% endif %} + +[gcode_macro DUMP_PRINT_AREA_LIMITS] +description: Debug: Print information about print volume and probeable area +gcode: + {% set min = printer.toolhead.axis_minimum %} + {% set max = printer.toolhead.axis_maximum %} + {% set probe_offset = {'x' : printer.configfile.settings.probe.x_offset, + 'y' : printer.configfile.settings.probe.y_offset} %} + {% set probe_area = {'min' : {'x' : [min.x,(min.x-probe_offset.x)]|max, + 'y' : [min.y,(min.y-probe_offset.y)]|max}, + 'max' : {'x' : [max.x,(max.x-probe_offset.x)]|min, + 'y' : [max.y,(max.y-probe_offset.y)]|min}} %} + {action_respond_info("Print Volume Limits: + Min X:%7.1f, Y:%7.1f, Z:%7.1f + Max X:%7.1f, Y:%7.1f, Z:%7.1f + Probe Area Limits: + Min X:%7.1f, Y:%7.1f + Max X:%7.1f, Y:%7.1f" % + (min.x,min.y,min.z,max.x,max.y,max.z,probe_area.min.x,probe_area.min.y, probe_area.max.x,probe_area.max.y))} + +##################################################################### +# Macros needed for several debug activities +##################################################################### + + diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg new file mode 100644 index 000000000..292f177ef --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg @@ -0,0 +1,527 @@ +# Main +# + Power Off +# + Flexplate +# + Set Name +# + Offset 0.0 +# + Tune +# + Speed: 0% +# + Flow: 0% +# + Offset Z:0.0 +# + SD Card +# + Show loaded file +# + Load File +# + Unload File +# + Start printing +# + Pause printing +# + Resume printing +# + Cancel printing +# + Control +# + Fan +# + Cooling +# + Toggle: OFF +# + Speed: 0% +# + Chamber +# + Toggle: OFF +# + Temp: 0C +# + Filter +# + Toggle: OFF +# + Speed: 0% +# + Lights +# + Toggle: OFF +# + Dim: 0% +# + Runout +# + Runout: ON +# + Toolhead: ON +# + Home [ALL / Z / X Y] +# + Park +# + Move +# + Move Step: 0 +# + Move X: 0.0 +# + Move Y: 0.0 +# + Move Z: 0.0 +# + Move E: +0.0 +# + Steppers off +# + Temperature +# + E0: 0.0 (0.0) +# + Bed: 0.0 (0.0) +# + Filament +# + Load +# + Unload +# + Feed: 0.0 +# + Satistic +# + Time of Operation +# + Total Filament used +# + Time since Filter change +# + Time since Service +# + Reset Filter time +# + Reset Service time + +[gcode_macro _MENU_LIMITS] +variable_move: {} +gcode: + {% set list = [0.1,0.5,1,5,10,50,100] %} ; define your input list + {% set max = printer.toolhead.axis_maximum %} + {% set min = printer.toolhead.axis_minimum %} + {% set index = params.INDEX|int if params.INDEX is defined and params.INDEX|int < list|length else 0 %} + {% set move = {'index': {'i': index, 'list': list }, + 'step' : list[index], + 'max' : {'x': ((max.x - min.x) / list[index])|int, + 'y': ((max.y - min.y) / list[index])|int, + 'z': ( max.z / list[index])|int, + 'e': (printer.configfile.settings.extruder.max_extrude_only_distance / list[index])|int}} %} + SET_GCODE_VARIABLE MACRO=_MENU_LIMITS VARIABLE=move VALUE="{move}" + +[menu __voron_main] +type: list +name: Main + +[menu __voron_main __power_off] +type: command +enable: {not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused") and + 'gcode_macro PRINTER_OFF' in printer} +name: Power Off +gcode: {menu.exit()} PRINTER_OFF + +[menu __voron_main __flexplate] +type: list +name: Flexplate: {printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].name} +enable: {'plates' in printer.save_variables.variables and + not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused")} + +[menu __voron_main __flexplate __set] +type: input +name: Set: {printer.save_variables.variables.plates.array[menu.input|int].name} +input: {printer.save_variables.variables.plates.index} +input_min: 0 +input_max: {printer.save_variables.variables.plates.array|length - 1} +gcode: SET_PLATE INDEX={menu.input|int} + +[menu __voron_main __flexplate __offset] +type: input +name: Offset:{'%01.3f' % menu.input} +input: {printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].offset} +input_min: -1.0 +input_max: 1.0 +input_step: 0.001 +gcode: CHANGE_PLATE_VALUE OFFSET={menu.input|float} + +[menu __voron_main __tune] +type: list +enable: {printer.print_stats.state == "printing" or printer.print_stats.state == "paused"} +name: Tune + +[menu __voron_main __tune __speed] +type: input +name: Speed: {'%3d' % (menu.input*100)}% +input: {printer.gcode_move.speed_factor} +input_min: 0.01 +input_max: 5 +input_step: 0.01 +realtime: True +gcode: M220 S{'%d' % (menu.input*100)} + +[menu __voron_main __tune __flow] +type: input +name: Flow: {'%3d' % (menu.input*100)}% +input: {printer.gcode_move.extrude_factor} +input_min: 0.01 +input_max: 2 +input_step: 0.01 +realtime: True +gcode: M221 S{'%d' % (menu.input*100)} + +[menu __voron_main __tune __offsetz] +type: input +name: Offset Z:{'%05.3f' % menu.input} +input: {printer.gcode_move.homing_origin.z} +input_min: -5 +input_max: 5 +input_step: 0.005 +realtime: True +gcode: SET_GCODE_OFFSET Z={'%.3f' % menu.input} MOVE=1 + +[menu __voron_main __sdcard] +type: list +enable: {'virtual_sdcard' in printer} +name: SD Card + +[menu __voron_main __sdcard __file] +type: command +name: File: {printer.print_stats.filename} + +[menu __voron_main __sdcard __load] +type: vsdlist +enable: {not printer.virtual_sdcard.file_path and not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused")} +name: Load file + +[menu __voron_main __sdcard __unload] +type: command +enable: {printer.virtual_sdcard.file_path and not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused")} +name: Unload file +gcode: + {menu.back()} SDCARD_RESET_FILE + +[menu __voron_main __sdcard __start] +type: command +enable: {printer.virtual_sdcard.file_path and not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused")} +name: Start print +gcode: + {menu.exit()} + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + M24 + +[menu __voron_main __sdcard __pause] +type: command +enable: {printer.print_stats.state == "printing"} +name: Pause print +gcode: + {menu.back()} PAUSE + +[menu __voron_main __sdcard __resume] +type: command +enable: {printer.print_stats.state == "paused"} +name: Resume print +gcode: + {menu.exit()} + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + RESUME + +[menu __voron_main __sdcard __cancel] +type: command +enable: {printer.print_stats.state == "paused"} +name: Cancel print +gcode: + {menu.exit()} + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + CANCEL_PRINT + +[menu __voron_main __control] +type: list +name: Control + +[menu __voron_main __control __fan] +type: list +name: Fan + +[menu __voron_main __control __fan __partcooling] +type: list +enable: {'fan' in printer} +name: Cooling {'%3d%s' % (printer.fan.speed*100,'%') if printer.fan.speed else 'OFF'} + +[menu __voron_main __control __fan __partcooling __fanonoff] +type: input +name: Toggle: {'ON' if menu.input else 'OFF'} +input: {printer.fan.speed} +input_min: 0 +input_max: 1 +input_step: 1 +gcode: M106 S{255 if menu.input else 0} + +[menu __voron_main __control __fan __partcooling __fanspeed] +type: input +name: Speed: {'%3d%s' % (menu.input*100,'%') if menu.input else 'OFF'} +input: {printer.fan.speed} +input_min: 0 +input_max: 1 +input_step: 0.01 +gcode: M106 S{'%d' % (menu.input*255)} + +[menu __voron_main __control __fan __chamber] +type: list +enable: {'temperature_fan chamber' in printer} +name: Chamber {'%2dC' % (printer['temperature_fan chamber'].target) if printer['temperature_fan chamber'].target else 'OFF'} + +[menu __voron_main __control __fan __chamber __chamberonoff] +type: input +name: Toggle: {'ON' if menu.input else 'OFF'} +input: {printer['temperature_fan chamber'].target} +input_min: 0 +input_max: 1 +input_step: 1 +gcode: M141 S{printer["gcode_macro _USER_VARIABLE"].vent_on if menu.input else 0} + +[menu __voron_main __control __fan __chamber __chamberfanspeed] +type: input +name: Temp: {'%2dC' % (menu.input) if menu.input else 'OFF'} +input: {printer['temperature_fan chamber'].target} +input_min: {printer.configfile.settings['temperature_fan chamber'].min_temp|int} +input_max: {printer.configfile.settings['temperature_fan chamber'].max_temp|int} +input_step: 1 +gcode: M141 S{'%d' % (menu.input)} + +[menu __voron_main __control __fan __filter] +type: list +enable: {'fan_generic filter' in printer} +name: Filter {'%3d%s' % (printer['fan_generic filter'].speed*100,'%') if printer['fan_generic filter'].speed else 'OFF'} + +[menu __voron_main __control __fan __filter __filteronoff] +type: input +name: Toggle: {'ON ' if menu.input else 'OFF'} +input: {printer['fan_generic filter'].speed} +input_min: 0 +input_max: 1 +input_step: 1 +gcode: {% if menu.input %} _FILTER_ON {% else %} _SET_FILTER S=0.0 {% endif %} + +[menu __voron_main __control __fan __filter __filterspeed] +type: input +name: Speed: {'%3d%s' % (menu.input*100,'%') if menu.input else 'OFF'} +input: {printer['fan_generic filter'].speed} +input_min: 0 +input_max: 1 +input_step: 0.01 +gcode: _SET_FILTER S={menu.input} + +[menu __voron_main __control __lights] +type: list +enable: {'output_pin caselight' in printer} +name: Lights {'ON' if printer['output_pin caselight'].value != 0 else 'OFF'} + +[menu __voron_main __control __lights __caselightonoff] +type: input +enable: {'output_pin caselight' in printer} +name: Toggle: {'ON ' if menu.input else 'OFF'} +input: {printer['output_pin caselight'].value} +input_min: 0 +input_max: 1 +input_step: 1 +gcode: {% if menu.input %} _CASELIGHT_ON {% else %} _CASELIGHT_OFF {% endif %} + +[menu __voron_main __control __lights __caselightpwm] +type: input +enable: {'output_pin caselight' in printer} +name: Dim: {'%3d%s' % (menu.input*100,'%') if menu.input else 'OFF'} +input: {printer['output_pin caselight'].value} +input_min: 0.0 +input_max: 1.0 +input_step: 0.01 +gcode: SET_PIN PIN=caselight VALUE={menu.input} + +[menu __voron_main __control __runout] +type: list +enable: {printer['gcode_macro _USER_VARIABLE'].hw.runout.sensor or + 'filament_switch_sensor toolhead_runout' in printer.configfile.settings} +name: Runout + +[menu __voron_main __control __runout __runoutonoff] +type: input +enable: {printer['gcode_macro _USER_VARIABLE'].hw.runout.sensor} +name: Runout: {'ON ' if menu.input else 'OFF'} +input: {printer["filament_" + printer['gcode_macro _USER_VARIABLE'].hw.runout.type + "_sensor runout"].enabled} +input_min: 0 +input_max: 1 +input_step: 1 +gcode: SET_FILAMENT_SENSOR SENSOR=runout ENABLE={menu.input|int} + +[menu __voron_main __control __runout __toolhead_runoitonoff] +type: input +enable: {'filament_switch_sensor toolhead_runout' in printer.configfile.settings} +name: Toolhead: {'ON ' if menu.input else 'OFF'} +input: {printer['filament_switch_sensor toolhead_runout'].enabled} +input_min: 0 +input_max: 1 +input_step: 1 +gcode: SET_FILAMENT_SENSOR SENSOR=toolhead_runout ENABLE={menu.input|int} + +[menu __voron_main __control __home] +type: input +enable: {not printer.print_stats.state == "printing" } +name: Home: {['ALL','Z','X Y'][menu.input|int]} +input: 0 +input_min: 0 +input_max: 2 +gcode: {['G28','G28 Z','G28 X Y'][menu.input|int]} + +[menu __voron_main __control __park_pos] +type: input +enable: {not printer.print_stats.state == "printing" } +name: Park: {['Bed','Center','Rear','Front','FrontLow'][menu.input|int]} +input: 0 +input_min: 0 +input_max: 4 +gcode: PARK P={['BED','CENTER','REAR','FRONT', 'FRONTLOW'][menu.input|int]} + +[menu __voron_main __control __move] +type: list +enable: {not printer.print_stats.state == "printing"} +name: Move + +[menu __voron_main __control __move __move_select] +type: input +name: Move Step: {printer['gcode_macro _MENU_LIMITS'].move.index.list[menu.input|int]} +input: {printer['gcode_macro _MENU_LIMITS'].move.index.i} +input_min: 0 +input_max: {printer['gcode_macro _MENU_LIMITS'].move.index.list|length - 1} +input_step: 1 +gcode: _MENU_LIMITS INDEX={menu.input|int} + +[menu __voron_main __control __move __move_x] +type: input +name: Move X: {'%05.1f' % (printer.toolhead.axis_minimum.x + menu.input * printer['gcode_macro _MENU_LIMITS'].move.step) if 'x' in printer.toolhead.homed_axes else 'unhomed' } +input: {((printer.gcode_move.gcode_position.x - printer.toolhead.axis_minimum.x) / printer['gcode_macro _MENU_LIMITS'].move.step)|int} +input_min: 0 +input_max: {printer['gcode_macro _MENU_LIMITS'].move.max.x} +input_step: 1 +realtime: True +gcode: + SAVE_GCODE_STATE NAME=__move__axis + G90 + G1 X{printer.toolhead.axis_minimum.x + menu.input * printer['gcode_macro _MENU_LIMITS'].move.step} F6000 + RESTORE_GCODE_STATE NAME=__move__axis + +[menu __voron_main __control __move __move_y] +type: input +name: Move Y: {'%05.1f' % (printer.toolhead.axis_minimum.y + menu.input * printer['gcode_macro _MENU_LIMITS'].move.step) if 'y' in printer.toolhead.homed_axes else 'unhomed' } +input: {((printer.gcode_move.gcode_position.y - printer.toolhead.axis_minimum.y) / printer['gcode_macro _MENU_LIMITS'].move.step)|int} +input_min: 0 +input_max: {printer['gcode_macro _MENU_LIMITS'].move.max.y} +input_step: 1 +realtime: True +gcode: + SAVE_GCODE_STATE NAME=__move__axis + G90 + G1 Y{printer.toolhead.axis_minimum.y + menu.input * printer['gcode_macro _MENU_LIMITS'].move.step} F6000 + RESTORE_GCODE_STATE NAME=__move__axis + +[menu __voron_main __control __move __move_z] +type: input +name: Move Z: {'%05.1f' % (menu.input * printer['gcode_macro _MENU_LIMITS'].move.step) if 'z' in printer.toolhead.homed_axes else 'unhomed' } +input: {((printer.gcode_move.gcode_position.z - printer.toolhead.axis_minimum.z) / printer['gcode_macro _MENU_LIMITS'].move.step)|int} +input_min: 0 +input_max: {printer['gcode_macro _MENU_LIMITS'].move.max.z} +input_step: 1 +realtime: True +gcode: + SAVE_GCODE_STATE NAME=__move__axis + G90 + G1 Z{printer.toolhead.axis_minimum.z + menu.input * printer['gcode_macro _MENU_LIMITS'].move.step} F900 + RESTORE_GCODE_STATE NAME=__move__axis + +[menu __voron_main __control __move __move_e] +type: input +name: Move E: {'%+06.1f' % (menu.input * printer['gcode_macro _MENU_LIMITS'].move.step) if printer.extruder.can_extrude else 'to cold'} +input: 0 +input_min: -{printer['gcode_macro _MENU_LIMITS'].move.max.e} +input_max: {printer['gcode_macro _MENU_LIMITS'].move.max.e} +input_step: 1 +gcode: + SAVE_GCODE_STATE NAME=__move__axis + M83 + G1 E{menu.input * printer['gcode_macro _MENU_LIMITS'].move.step} F240 + RESTORE_GCODE_STATE NAME=__move__axis + +[menu __voron_main __control __disable] +type: command +name: Steppers off +enable: {not printer.print_stats.state == "printing"} +gcode: M84 + +[menu __voron_main __temp] +type: list +name: Temperature + +[menu __voron_main __temp __hotend0_target] +type: input +enable: {('extruder' in printer) and ('extruder' in printer.heaters.available_heaters)} +name: {"E0: %3.0f (%4.0f)" % (menu.input, printer.extruder.temperature)} +input: {printer.extruder.target} +input_min: 0 +input_max: {printer.configfile.config.extruder.max_temp} +input_step: 1 +gcode: M104 T0 S{'%.0f' % menu.input} + +[menu __voron_main __temp __hotbed_target] +type: input +enable: {'heater_bed' in printer} +name: {"Bed:%3.0f (%4.0f)" % (menu.input, printer.heater_bed.temperature)} +input: {printer.heater_bed.target} +input_min: 0 +input_max: {printer.configfile.config.heater_bed.max_temp} +input_step: 1 +gcode: M140 S{'%.0f' % menu.input} + +[menu __voron_main __filament] +type: list +name: Filament + +[menu __voron_main __filament __load] +type: command +name: Load +gcode: FILAMENT_LOAD + +[menu __voron_main __filament __unload] +type: command +name: Unload +gcode: FILAMENT_UNLOAD + +[menu __voron_main __filament __feed] +type: input +name: Feed: {'%.1f' % menu.input if printer.extruder.can_extrude else 'to cold'} +input: 5 +input_min: -{printer.configfile.settings.extruder.max_extrude_only_distance} +input_max: {printer.configfile.settings.extruder.max_extrude_only_distance} +input_step: 0.1 +gcode: + SAVE_GCODE_STATE NAME=__filament__load + M83 + G1 E{'%.1f' % menu.input} F60 + RESTORE_GCODE_STATE NAME=__filament__load + +[menu __voron_main __statistic] +type: list +enable: {'print_stats' in printer.save_variables.variables} +name: Satistic + +[menu __voron_main __statistic __totaltime] +type: command +name: Time of Operation +gcode: + {menu.exit()} + _DISPLAY_PRINT_TIME PREFIX=Total SECONDS={printer.save_variables.variables.print_stats.time.total} + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + +[menu __voron_main __statistic __filament] +type: command +name: Total Filament used +gcode: + {menu.exit()} + M117 Filerment {'%.4f' % (printer.save_variables.variables.print_stats.filament|float / 1000.0)}m + {action_respond_info("Total Filament printed: %.4fm" % (printer.save_variables.variables.print_stats.filament|float / 1000.0))} + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=10 + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + +[menu __voron_main __statistic __filtertime] +type: command +name: Time since Filter change +gcode: + {menu.exit()} + _DISPLAY_PRINT_TIME PREFIX=Filter SECONDS={printer.save_variables.variables.print_stats.time.filter} + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + +[menu __voron_main __statistic __servicetime] +type: command +name: Time since Service +gcode: + {menu.exit()} + _DISPLAY_PRINT_TIME PREFIX=Service SECONDS={printer.save_variables.variables.print_stats.time.service} + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + + +[menu __voron_main __statistic __rst_filter] +type: command +enable: {not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused")} +name: Reset Filter time +gcode: + {menu.exit()} + RST_FILTER + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + + +[menu __voron_main __statistic __rst_service] +type: command +enable: {not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused")} +name: Reset Service time +gcode: + {menu.exit()} + RST_SERVICE + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg new file mode 100644 index 000000000..80c837a9a --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg @@ -0,0 +1,167 @@ +##################################################################### +# Fan Control +##################################################################### +## Hotend Fan - XYE board, E1 Connector +[heater_fan hotend_fan] +pin: P2.4 +max_power: 1.0 +fan_speed: 1 +kick_start_time: 0 +heater: extruder +heater_temp: 50.0 + +## Print Cooling Fan (24V Fan 4 wire) +## Z board, X Endstop (PWM) +## Z board, E1det (Tacho) +[fan] +pin: z:P1.29 +cycle_time: 0.0001 #10 kHz PWM signal +hardware_pwm: False +kick_start_time: 0 +off_below: 0.05 +tachometer_pin: z:P1.25 +tachometer_ppr: 2 + +## Controller fan (5V Fan 4 wire) +## Z board, NeoPixel Connector (PWM) +## Z board, Y Endstop (Tacho) +[heater_fan controller_fan] +pin: z:P1.24 +max_power: 1.0 +shutdown_speed: 1.0 +cycle_time: 0.0001 #10 kHz PWM signal +hardware_pwm: False +kick_start_time: 0 +fan_speed: 0.9 +heater: heater_bed +heater_temp: 45.0 +tachometer_pin: z:P1.28 +tachometer_ppr: 2 + +## Chamber temp / Exhaust fan (24V Fan 4 wire) +## XYE board, NeoPixel Connector (PWM) +## XYE board, TH1 Connector +## XYE board, Z Endstop (Tacho) +[temperature_fan chamber] +pin: P1.24 +max_power: 1.0 +shutdown_speed: 0.0 +cycle_time: 0.0005 #2 kHz PWM signal +hardware_pwm: False +kick_start_time: 0 +sensor_type: ATC Semitec 104GT-2 +sensor_pin: P0.23 +min_temp: 0 +max_temp: 70 +target_temp: 0 +max_speed: 0.7 +min_speed: 0.1 +control: pid +pid_Kp: 2.0 ;40 +pid_Ki: 5.0 ;0.2 +pid_Kd: 0.5 ;0.1 +pid_deriv_time: 2.0 +gcode_id: C +tachometer_pin: P1.27 +tachometer_ppr: 2 + +## Nevermore Micro filter +## - Z board, E1 Connector +[fan_generic filter] +pin: z:P2.4 +max_power: 1.0 +kick_start_time: 0.5 +off_below: 0.10 + +[temperature_sensor RPi] +sensor_type: temperature_host +min_temp: 10 +max_temp: 100 +gcode_id: PI + +## Z board, TH1 Connector +[temperature_sensor endstop] +sensor_type: Generic 3950 +sensor_pin: z:P0.23 +min_temp: 10 +max_temp: 100 +gcode_id: E + +## dummy output to get an switch in Mainsail +## any unused mcu pin can be defined you will not connect anything +## as I use the rPi as mcu I will use a pin from it +## Off -> M106 will update fan +## On -> M106 can not uodate fan +[output_pin lock_M106] +pin: rpi: gpio16 +value:0 + +##################################################################### +# Macros +##################################################################### +# M106 with lock and manual set feature +# M106 S128 M1 will update the fan in any case +[gcode_macro M106] +description: set fan with manual override and lock option +rename_existing: M106.1 +gcode: + {% if printer['output_pin lock_M106'].value|int == 0 or params.M|default(0) == '1' %} + M106.1 {rawparams} + {% else %} + {action_respond_info("M106 update is locked")} + {% endif %} + +[gcode_macro M141] +description: Set temperature of chamber fan +gcode: SET_TEMPERATURE_FAN_TARGET temperature_fan=chamber target={params.S|default(0)} + +[gcode_macro _SET_FILTER] +description: Helper: Set Nevermore filter speed +gcode: SET_FAN_SPEED FAN=filter SPEED={params.S|default(0)} + +[gcode_macro _FILTER_ON] +description: Helper: Nevermore on +gcode: _SET_FILTER S={printer['gcode_macro _USER_VARIABLE'].peripheral.filter.on_val} + +[gcode_macro FILTER] +description: Toggle Nevermore fan +gcode: + {% if printer['fan_generic filter'].speed|float > 0.0 %} _SET_FILTER {% else %} _FILTER_ON {% endif %} + _FILTER_INFO + +[delayed_gcode _DELAY_FILTER_OFF] +gcode: + {% if printer.print_stats.state|lower != "paused" and printer.print_stats.state|lower != "printing" %} + _SET_FILTER + _FILTER_INFO + {% endif %} + +## Chamber Ventilation Control in Mainsail +[gcode_macro VENT] +description: Toggle Chamber fan +gcode: + {% if printer['temperature_fan chamber'].target|float > 0 and + printer['temperature_fan chamber'].target|float <= printer['gcode_macro _USER_VARIABLE'].peripheral.vent.on_val|float %} + M141 + {% else %} + M141 S{printer['gcode_macro _USER_VARIABLE'].peripheral.vent.on_val} + {% endif %} + _VENT_INFO + +[delayed_gcode _DELAY_VENT_OFF] +gcode: + {% if printer.print_stats.state|lower != "paused" and printer.print_stats.state|lower != "printing" %} + M141 + _VENT_INFO + {% endif %} + +[gcode_macro _VENT_INFO] +description: Helper: Print chamber fan temperature +gcode: + {% set txt = "off" if printer['temperature_fan chamber'].target == 0 + else "target temp: %2dC" % printer['temperature_fan chamber'].target %} + {action_respond_info("Chamber fan %s" % txt)} + +[gcode_macro _FILTER_INFO] +description: Helper: Print Nevermore speed +gcode: {action_respond_info("Filter fan %s" % 'on' if printer['fan_generic filter'].speed|float > 0.0 else 'off')} \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg new file mode 100644 index 000000000..2c2dd27f3 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg @@ -0,0 +1,176 @@ +[firmware_retraction] +retract_length: 0.75 ; length of filament (in mm) at G10/G11 +unretract_extra_length: 0 ; length of additional filament (in mm) at G11 +retract_speed: 50 +unretract_speed: 30 + +##################################################################### +# Macro +##################################################################### +[gcode_macro _FILAMENT_BALL] +description: Helper: Round the filament tip +gcode: + G92 E0 ; zero the extruder + M83 ; relative extrusion + G1 E2 F{printer['gcode_macro _USER_VARIABLE'].speed.retract * 2} + G1 E-2 + G1 E4 + G1 E-4 + G1 E8 + G1 E-8 + G1 E-25 + G4 P{params.WAIT|default(0)|int * 1000} + +[gcode_macro FILAMENT_LOAD] +description: Load filament and disable rounout while running +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set pos = printer['gcode_macro _USER_VARIABLE'].purge.purge %} + {% set move_z = [user.z_hop,printer.toolhead.position.z]|max %} ; calc movement high + {% if printer.idle_timeout.state != "Printing" or printer.pause_resume.is_paused|lower == "true" %} + {% if user.hw.runout.type == 'motion' %} SET_FILAMENT_SENSOR SENSOR=runout ENABLE=0 {% endif %} + _CG28 ; home if not already homed + G90 ; absolute positioning + G1 Z{move_z} F{user.speed.z_hop} ; move head to minimum + G1 X{pos.x} Y{pos.y} F{user.speed.travel} ; move to purge bucket location + {% if user.hw.display.ena %} _LCD_KNOB COLOR=BLUE {% endif %} + {% if not printer.extruder.can_extrude %} + {action_respond_info("Extruder Temp to low heat to %3.1f°C" % printer.configfile.settings.extruder.min_extrude_temp)} + M109 S{printer.configfile.settings.extruder.min_extrude_temp} + {% endif %} + {% if user.hw.display.ena %} _LCD_KNOB {% endif %} + G1 Z{pos.z} F{user.speed.z_hop} + M83 ; set extruder to relative + G1 E{user.filament.load_distance} F{user.speed.load} ; quickly load filament + {% if user.hw.runout.type == 'motion' %} + _PRINT_AR T="RUNOUT Motion Sensor Enable: true" + SET_FILAMENT_SENSOR SENSOR=runout ENABLE=1 + {% endif %} + G1 E{user.filament.load_extrude} F{user.speed.retract} ; slower load filament + G1 E-{user.filament.retract.pause} + _WIPE ; clean nozzle + G1 Z{move_z} F{user.speed.z_hop} + G1 X{pos.x} Y{pos.y} F{user.speed.travel} ; move to purge bucket location + M109 S{printer.extruder.target} ; restore old extruder temperature + _PRINT_AR T="Filament loaded" + SAVE_VARIABLE VARIABLE=filament_loaded VALUE=True + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set it back to relativ + {% if printer.gcode_move.absolute_extrude %} M82 {% endif %} ; set it back to absolute + {% else %} + _PRINT_AR T="Filament loading disabled while printing!" + {% endif %} + +[gcode_macro FILAMENT_UNLOAD] +description: Unload filament and disable rounout while running +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% if printer.idle_timeout.state != "Printing" or printer.pause_resume.is_paused|lower == "true" %} + {% if user.hw.runout.type == 'motion' %} + _PRINT_AR T="RUNOUT Motion Sensor Enable: false" + SET_FILAMENT_SENSOR SENSOR=runout ENABLE=0 + {% endif %} + {% if user.hw.display.ena %} _LCD_KNOB COLOR=BLUE {% endif %} + {% if not printer.extruder.can_extrude %} + {action_respond_info("Extruder Temp to low heat to %3.1f°C" % printer.configfile.settings.extruder.min_extrude_temp)} + M109 S{printer.configfile.settings.extruder.min_extrude_temp} + {% endif %} + {% if user.hw.display.ena %} _LCD_KNOB {% endif %} + _FILAMENT_BALL WAIT=3 ; ball up the filament tip and retract out past the extruder gears + G1 E-{user.filament.unload_distance} F{user.speed.load} + M109 S{printer.extruder.target} ; restore old extruder temperature + _PRINT_AR T="Filament unloaded" + SAVE_VARIABLE VARIABLE=filament_loaded VALUE=False + {% if printer.gcode_move.absolute_extrude %} M82 {% endif %} ; set it back to absolute + {% else %} + _PRINT_AR T="Filament unloading disabled while printing!" + {% endif %} + +[gcode_macro NOZZLECLEAN] +description: Move to bucket and purge and scrub nozzle +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set pos = user.purge.purge %} + {% set move_z = [user.z_hop,printer.toolhead.position.z]|max %} ; calc movement high + SET_GCODE_OFFSET Z=0.0 + _PRINT_AR T="Clean Nozzle" SHOW_LCD=true + _CG28 ; home if not already homed + G90 ; absolute positioning + G1 Z{move_z} F{user.speed.z_hop} ; move head up + G1 X{pos.x} Y{pos.y} F{user.speed.travel} ; move to purge bucket location + G1 Z{pos.z} F{user.speed.z_hop} ; lower Z + {% if not printer.extruder.can_extrude %} + {action_respond_info("Extruder Temp to low heat to %3.1f°C" % printer.configfile.settings.extruder.min_extrude_temp)} + M109 S{printer.configfile.settings.extruder.min_extrude_temp} + {% endif %} + G92 E0 ; reset Extruder + M83 ; relative extrusion + G1 E2 F500 ; purge filament + G1 E2 F800 ; purge filament + G1 E-1 F800 ; retract filament + G4 P500 + _WIPE + M109 S{printer.extruder.target} ; restore old extruder temperature + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=1 + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set it back to relative + {% if printer.gcode_move.absolute_extrude %} M82 {% endif %} ; set it back to absolute + SET_GCODE_OFFSET Z={printer.gcode_move.homing_origin.z} MOVE=1 + +[gcode_macro _WIPE] +description: Helper: Wipe nozzle at bucket +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set wipe = user.purge.wipe %} + G90 ; absolute positioning + G0 X{wipe.start.x} Y{wipe.start.y} Z{wipe.start.z} F{user.speed.wipe} + {% for moves in range(0, wipe.cnt) %} ; move head diagonal to brush + {% for coordinate in [wipe.start.x, wipe.end.x] %} + G0 X{coordinate} Y{wipe.start.y + wipe.offset * moves} + {% endfor %} + {% endfor %} + G0 X{wipe.end.x} Y{wipe.end.y} Z{wipe.end.z} + +[gcode_macro PRIME_LINE] +description: Purge nozzle at defined position +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set prime = user.prime %} + {% set prime_height = params.PRIME_HEIGHT|default(prime.pos.z) %} ; get parameter or set default + {% set move_z = [user.z_hop,printer.toolhead.position.z]|max %} ; calc movement high + {% if prime.dir|string == 'X+' %} + {% set first_line = 'X%s E%s F%s' % (prime.length_per_seg, prime.extrude_per_seg, user.speed.prime) %} + {% set second_line = 'X-%s E%s F%s' % (prime.length_per_seg, prime.extrude_per_seg, user.speed.prime) %} + {% set move_to_side = 'Y%s' % prime.spacing %} + {% elif prime.dir|string == 'X-' %} + {% set first_line = 'X-%s E%s F%s' % (prime.length_per_seg, prime.extrude_per_seg, user.speed.prime) %} + {% set second_line = 'X%s E%s F%s' % (prime.length_per_seg, prime.extrude_per_seg, user.speed.prime) %} + {% set move_to_side = 'Y%s' % prime.spacing %} + {% elif prime.dir|string == 'Y+' %} + {% set first_line = 'Y%s E%s F%s' % (prime.length_per_seg, prime.extrude_per_seg, user.speed.prime) %} + {% set second_line = 'Y-%s E%s F%s' % (prime.length_per_seg, prime.extrude_per_seg, user.speed.prime) %} + {% set move_to_side = 'X%s' % prime.spacing %} + {% elif prime.dir|string == 'Y-' %} + {% set first_line = 'Y-%s E%s F%s' % (prime.length_per_seg, prime.extrude_per_seg, user.speed.prime) %} + {% set second_line = 'Y%s E%s F%s' % (prime.length_per_seg, prime.extrude_per_seg, user.speed.prime) %} + {% set move_to_side = 'X%s' % prime.spacing %} + {% else %} + {action_raise_error("_USER_VARIABLE.prime.dir is not spezified as X+, X-, Y+ or Y-")} + {% endif %} + _PRINT_AR T="Prime Line" SHOW_LCD=true + _CG28 ; home if not already homed + G92 E0 ; reset Extruder + G90 ; absolute positioning + G1 Z{move_z} F{user.speed.z_hop} ; move head up + G1 X{prime.pos.x} Y{prime.pos.y} F{user.speed.travel} ; move to start position + G1 Z{prime_height} F{user.speed.z_hop} ; move Z Axis down + G91 ; relative positioning + {% for segment in range(prime.seg|int) %} ; draw the first line + G1 {first_line} + {% endfor %} + G1 {move_to_side} ; move to side + {% for segment in range(prime.seg|int) %} ; draw the second line + G1 {second_line} + {% endfor %} + G92 E0 ; reset Extruder + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set it back to relative + {% if printer.gcode_move.absolute_extrude %} M82 {% endif %} ; set it back to absolute + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=1 \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg new file mode 100644 index 000000000..ce0b32b9c --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg @@ -0,0 +1,212 @@ +##################################################################### +# Preperation +##################################################################### +# copy this file in the same directory as your printer.cfg +# add +# [include flexplate.cfg] +# to your printer.cfg +# +# add +# _SET_PLATE_OFFSET +# to your print start gcode to apply the offset before you print the first line of filament +# +# A [save_variables] block is needed since a printer save variable needs to be used to have it available after power up. +# You can skip this if you already have an [save_variables] config block +# e.g: +# [save_variables] +# filename: /home/pi/klipper_config/.variables.stb +# I like to hide that file as there is nothing in that should be modified by the user. +# Do a klipper restart after adding the stuff above +# +# After klipper is back you need define your first plate e.g. +# ADD_NEW_PLATE NAME=Texture OFFSET=-0.010 +# +##################################################################### +# Macro for the print_start gcode section of your slicer +# or your print start macro +##################################################################### +# _SET_PLATE_OFFSET [MOVE=0|1] : Set the z offset +# Set the offset of the active flexplate as an Z_ADJUST offset. MOVE=0 (default) +# will add the offset with the next z move, MOVE=1 imitate change the z offset. +# +# !!! Caution: Insure that SET_GCODE_OFFSET Z=0 is set once at every +# print start. Please read also the desribtion of the gcode SET_GCODE_OFFSET +# at https://www.klipper3d.org/G-Codes.html#extended-g-code-commands !!! +# +##################################################################### +# Console ussage +##################################################################### +# LIST_PLATES: List all plates +# Use the index shown there for all other macros +# +# SET_PLATE INDEX=: Set the active flexplate +# The flexplate stored at index will be activated. +# +# ADD_PLATE [NAME=] [OFFSET=]: Add a new flexplate to the list +# If NAME or OFFSET is not defined than the defaults 'New' and 0.000 will be used. +# !!! Caution do not use special characters like äüö or anything else in the name !!! +# +# REMOVE_PLATE INDEX=: Remove a flexplate of the list +# Remove plate with INDEX from the list. Note the last or active plate can not be removed. +# +# CHANGE_PLATE_VALUE [INDEX=] [NAME=] [OFFSET=]: Change name or/and offset of an flexplate +# If INDEX is not defined the name and/or offset value of the active plate will be changed. +# !!! Caution do not use special characters like äüö or anything else in the name !!! +# +##################################################################### +# LCD menu usage +##################################################################### +# Change the active flexplate and the offset of that flexplate. +# +##################################################################### +# Get offset_z and name for own usage +##################################################################### +# {% set offset = printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].offset %} +# {% set name = printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].name %} +# +##################################################################### +[gcode_macro _SET_PLATE_OFFSET] +description: Helper: Apply the z-offset of the active flexplate +gcode: + {% if not printer.save_variables.variables.plates %} + {action_respond_info("FLEXPLATE: No Plate Array defined. ABORDED")} + {% else %} + {% set plates = printer.save_variables.variables.plates %} + SET_GCODE_OFFSET Z_ADJUST={plates.array[plates.index].offset} MOVE={params.MOVE|default(0)} + {% endif %} + +[gcode_macro LIST_PLATES] +description: List all flexplates +gcode: + {% if not printer.save_variables.variables.plates %} + {action_respond_info("FLEXPLATE: No Plate Array defined. ABORDED")} + {% else %} + {% set plates = printer.save_variables.variables.plates %} + {% set out = ["FLEXPLATE: Defined Plates"] %} + {% for elem in range(plates.array|length) %} + {% set _dummy = out.append("INDEX: %d -> %s -> offset: %.3fmm" % + (elem, plates.array[elem].name, plates.array[elem].offset)) %} + {% endfor %} + {% set _dummy = out.append("\n Active Plate: %s" % plates.array[plates.index].name) %} + {action_respond_info(out|join("\n"))} + {% endif %} + +[gcode_macro SET_PLATE] +description: Set an flexplate +gcode: + {% if not printer.save_variables.variables.plates %} + {action_respond_info("FLEXPLATE: No Plate Array defined. ABORDED")} + {% else %} + {% set plates = printer.save_variables.variables.plates %} + {% if 'INDEX' not in params|upper %} + {action_respond_info("FLEXPLATE: No INDEX defined, use SET_PLATE INDEX=index. ABORDED")} + {% elif params.INDEX|int < 0 or params.INDEX|int >= plates.array|length %} + {action_respond_info("FLEXPLATE: Index out of range [0..%d]. ABORDED" % (plates.array|length-1))} + {% else %} + {% set _dummy = plates.update({'index' : params.INDEX|int}) %} + SAVE_VARIABLE VARIABLE=plates VALUE="{plates}" + M117 Plate: {plates.array[plates.index].name} + {action_respond_info("FLEXPLATE: Set plate: %s with offset: %.3fmm" % ( + plates.array[plates.index].name,plates.array[plates.index].offset))} + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=10 + {% endif %} + {% endif %} + +[gcode_macro ADD_PLATE] +description: Add a flexplate to the list +gcode: + {% set name = params.NAME|default('New')|string %} + {% set offset = params.OFFSET|default(0.0)|float|round(3) %} + {% if not printer.save_variables.variables.plates %} + {action_respond_info("FLEXPLATE: Initialize Plate Array + Add plate: %s with offset: %.3fmm at INDEX: 0" % (name,offset))} + {% set plates = {'array': [{'name': name, 'offset': offset}], 'index' : 0} %} + {% else %} + {% set plates = printer.save_variables.variables.plates %} + {action_respond_info("FLEXPLATE: Add plate: %s with offset: %.3fmm at INDEX: %d" % (name,offset,plates.array|length))} + {% set _dummy = plates.array.append({'name': name, 'offset': offset}) %} + {% endif %} + SAVE_VARIABLE VARIABLE=plates VALUE="{plates}" + +[gcode_macro REMOVE_PLATE] +description: Remove a flexplate from the list +gcode: + {% if not printer.save_variables.variables.plates %} + {action_respond_info("FLEXPLATE: No Plate Array defined. ABORDED")} + {% else %} + {% set plates = printer.save_variables.variables.plates %} + {% if 'INDEX' not in params|upper %} + {action_respond_info("FLEXPLATE: No INDEX defined, use REMOVE_PLATE INDEX=index. ABORDED")} + {% elif plates.array|length == 1 or params.INDEX|int == plates.index %} + {action_respond_info("FLEXPLATE: Last or active plate can not be removed. ABORDED")} + {% elif params.INDEX|int < 0 or params.INDEX|int >= plates.array|length %} + {action_respond_info("FLEXPLATE: Index out of range [0..%d]. ABORDED" % (plates.array|length-1))} + {% else %} + {action_respond_info("FLEXPLATE: Remove plate with INDEX %d from list " % params.INDEX|int)} + {% set _dummy = plates.array.pop(params.INDEX|int) %} + SAVE_VARIABLE VARIABLE=plates VALUE="{plates}" + {% endif %} + {% endif %} + +[gcode_macro CHANGE_PLATE_VALUE] +description: Change name or offset of an flexplate in the list +gcode: + {% if not printer.save_variables.variables.plates %} + {action_respond_info("FLEXPLATE: No Plate Array defined. ABORDED")} + {% else %} + {% set plates = printer.save_variables.variables.plates %} + {% set index = params.INDEX|default(plates.index)|int %} + {% if index < 0 or index >= plates.array|length %} + {action_respond_info("FLEXPLATE: Index out of range [0..%d]. ABORDED" % (plates.array|length-1))} + {% else %} + {% set change_txt = [] %} + {% if 'NAME' in params|upper %} + {% set _dummy = change_txt.append("name to %s" % params.NAME|string) %} + {% set _dummy = plates.array[index].update({'name': params.NAME|string}) %} + {% endif %} + {% if 'OFFSET' in params|upper %} + {% set _dummy = change_txt.append("offset to %.3fmm" % params.OFFSET|float|round(3)) %} + {% set _dummy = plates.array[index].update({'offset': params.OFFSET|float|round(3)}) %} + {% endif %} + {% if change_txt|length > 0 %} + {action_respond_info("FLEXPLATE: Changed %s at plate with INDEX %d" % (change_txt|join(" and "),index))} + SAVE_VARIABLE VARIABLE=plates VALUE="{plates}" + {% else %} + {action_respond_info("FLEXPLATE: Nothing changed at plate with INDEX %d" % index)} + {% endif %} + {% endif %} + {% endif %} + +# Display Menu +# !!! Caution: I use my own menu root __voron_main !!! +# If you use a stock menu un comment this here +#[menu __main __flexplate] +#type: list +#name: Flexplate: {printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].name} +#enable: {'plates' in printer.save_variables.variables} +#index: 1 + +#[menu __main __flexplate __set] +#type: input +#name: Set: {printer.save_variables.variables.plates.array[menu.input|int].name} +#enable: {printer.print_stats.state != "printing" and printer.print_stats.state != "paused"} +#input: {printer.save_variables.variables.plates.index} +#input_min: 0 +#input_max: {printer.save_variables.variables.plates.array|length - 1} +#gcode: +# {%- if menu.event == 'long_click' -%} +# SET_PLATE INDEX={menu.input|int} +# {%- endif -%} + +#[menu __main __flexplate __offset] +#type: input +#name: Offset:{'%01.3f' % menu.input} +#enable: {printer.print_stats.state != "printing" and printer.print_stats.state != "paused"} +#input: {printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].offset} +#input_min: -1.0 +#input_max: 1.0 +#input_step: 0.001 +#gcode: +# {%- if menu.event == 'long_click' -%} +# CHANGE_PLATE_VALUE OFFSET={menu.input|float} +# {%- endif -%} \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg new file mode 100644 index 000000000..8fded41d1 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg @@ -0,0 +1,32 @@ +## This is an emergency fix if the gantry is at the max Z position what makes homing imposible +## 1) set enable_force_move: True +## 2) do an klipper restart +## 3) use a SET_KINEMATIC_POSITION e.g SET_KINEMATIC_POSITION X=50 Y=50 Z=100 +## that position does not need to be accurate as we only use it to get the head down +## 4) get the head down by at least the amount you have specified as z lift for homing e.g. 25 mm +## 5) set enable_force_move: False +## 6) do an klipper restart +## 7) now you can home normal again + +## Reference: +## Force move enabled will allow the following 2 debug commands. !!! Use them carefully !!! +## +## SET_KINEMATIC_POSITION [X=] [Y=] [Z=]: Force the low-level kinematic code to believe +## the toolhead is at the given cartesian position. This is a diagnostic and debugging command; use +## SET_GCODE_OFFSET and/or G92 for regular axis transformations. If an axis is not specified then it will +## default to the position that the head was last commanded to. Setting an incorrect or invalid position +## may lead to internal software errors. This command may invalidate future boundary checks; issue a G28 +## afterwards to reset the kinematics. +## +## FORCE_MOVE STEPPER= DISTANCE= VELOCITY= [ACCEL=]: This command will +## forcibly move the given stepper the given distance (in mm) at the given constant velocity (in mm/s). +## If ACCEL is specified and is greater than zero, then the given acceleration (in mm/s^2) will be used; +## otherwise no acceleration is performed. If acceleration is not performed then it can lead to the +## micro-controller reporting “No next step” errors (avoid these errors by specifying an ACCEL value or +## use a very low VELOCITY). No boundary checks are performed; no kinematic updates are made; other +## parallel steppers on an axis will not be moved. Use caution as an incorrect command could cause +## damage! Using this command will almost certainly place the low-level kinematics in an incorrect state; +## issue a G28 afterwards to reset the kinematics. This command is intended for low-level diagnostics and debugging. + +[force_move] +enable_force_move: False diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg new file mode 100644 index 000000000..4b02cd60f --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg @@ -0,0 +1,90 @@ +##################################################################### +# Extruder +##################################################################### +## XYE board, E0 Connector +## XYE board, TH0 Connector +[extruder] +##################### Standard Values ##################### +## BMG spec of extruder pully +## rotation_distence: 22.68 BMG 5mm axis +## rotation_distence: 33.00 BMG 8 mm axis +## gear ratios of different Extruders +## gear_ratio: 50:10 Voron V0.1 DD +## gear_ratio: 50:17 Voron Afterburner Clockworks +## gear_ratio: 80:20 Voron M4 +## gear_ratio: 7.5:1 Voron Afterburner Galileo +############### Different Clockworks Setups ############### +## Afterburner: Stepper Motor 0.9 step distance 0.00120 calibrated 0.001196 +## dir_pin: P0.11 +## full_steps_per_rotation: 400 +## microsteps: 16 +## rotation_distance: 7.6544 +############################################################ +## Galileo: Stepper Motor 1.8 step distance 0.00138 calibrated 0,001375 +## dir_pin: !P0.11 +## full_steps_per_rotation: 200 +## microsteps: 16 +## rotation_distance: 4.401 +############### Different Clockworks Setups ############### +## Update value below when you perform extruder calibration +## Higher value means less filament extruded +## If you ask for 100mm of filament, but in reality it is 98mm: +## step_distance = 98 / 100 * step_distance_old +############################################################ +step_pin: P2.13 +dir_pin: !P0.11 +enable_pin: !P2.12 +full_steps_per_rotation: 200 +microsteps: 16 +rotation_distance: 4.401 +nozzle_diameter: 0.4 +filament_diameter: 1.75 +heater_pin: P2.7 +sensor_type: SliceEngineering 450 +sensor_pin: P0.24 +min_temp: 10 +max_temp: 300 +max_power: 1.0 +# The minimum temperature (in Celsius) at which extruder move +# commands may be issued. The default is 170 Celsius. +min_extrude_temp: 210 +## Maximum length (in mm of raw filament) that a retraction or +## extrude-only move may have. If a retraction or extrude-only move +## requests a distance greater than this value it will cause an error +## to be returned. The default is 50mm. +max_extrude_only_distance: 100.0 +#control = pid +#pid_kp = 26.213 +#pid_ki = 1.304 +#pid_kd = 131.721 +## Try to keep pressure_advance below 1.0 +pressure_advance: 0.05 +## Default is 0.040, leave stock +pressure_advance_smooth_time: 0.040 + +##################################################################### +# Bed Heater +##################################################################### +## SSR - Z board, Fan0 Connector +## Z board, TB Connector +[heater_bed] +heater_pin: z:P2.3 +sensor_type: Generic 3950 +sensor_pin: z:P0.25 +max_power: 0.65 +min_temp: 10 +max_temp: 130 +#control: pid +#pid_kp: 58.437 +#pid_ki: 2.347 +#pid_kd: 363.769 + +## Sensor srewed in the bed +## Z board, TH0 Thermistor +## This only works as safety guard +[temperature_sensor bed] +sensor_type: Generic 3950 +sensor_pin: z:P0.24 +min_temp: 10 +max_temp: 120 +gcode_id: B1 \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg new file mode 100644 index 000000000..bffa83de4 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg @@ -0,0 +1,14 @@ +##################################################################### +# Heater Verification +##################################################################### +[verify_heater heater_bed] +max_error: 120 +check_gain_time: 60 +hysteresis: 5 +heating_gain: 2 + +[verify_heater extruder] +max_error: 120 +check_gain_time: 20 +hysteresis: 5 +heating_gain: 2 \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg new file mode 100644 index 000000000..27922be3b --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg @@ -0,0 +1,107 @@ +##################################################################### +# Homing definition +##################################################################### +[homing_override] +axes: z +set_position_z: 0 +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set home_x, home_y, home_z = False, False, False %} ; define what axes need to be homed + {% if params.X is not defined and params.Y is not defined and params.Z is not defined %} ; G28 + {% set home_x, home_y, home_z = True, True, True %} + {% else %} + {% if params.X is defined %}{% set home_x = True %}{% endif %} + {% if params.Y is defined %}{% set home_y = True %}{% endif %} + {% if params.Z is defined %} + {% if 'x' not in printer.toolhead.homed_axes %}{% set home_x = True %}{% endif %} ; check if homed + {% if 'y' not in printer.toolhead.homed_axes %}{% set home_y = True %}{% endif %} ; check if homed + {% set home_z = True %} + {% endif %} + {% endif %} + {% if user.hw.mag_probe.ena %} _MAG_PROBE ACTION=GET_STATUS RESPOND=0 {% endif %} ; generate probe state + _SET_ACC VAL=HOME ; reduce accel and accel_to_decel + G0 Z{user.homing.z_endstop.hop} F{user.speed.z_hop} ; lift nozzle + {% if home_x %} G28 X {% endif %} ; home X + {% if home_y %} G28 Y {% endif %} ; home Y + {% if home_z %} _HOME_Z {% endif %} ; home Z + _SET_ACC ; set accel and accel_to_decel back to cfg value + +[gcode_macro _HOME_Z] +description: Helper: z homing +variable_calibrate_z_next: False +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + ; use -10 as default to insure it error out in case the variable is not existing + {% set z_endstop = user.homing.z_endstop|default({'x':-10,'y':-10,'z':0, 'hop':0}) %} + {% if user.hw.mag_probe.ena %} + {% set probe = printer['gcode_macro _MAG_PROBE'].state|default('unknown')|lower %} ; get probe state + {% set error = "run \"_MAG_PROBE ACTION=GET_STATUS\"" if probe == 'unknown' + else "last dock or undock failed" if probe == 'error' + else "not valid" if probe is not in ['docked','attached'] + else "" %} + {% if error|length > 0 %} + {action_raise_error("Home&Probe: MagProbe state %s %s" % (error,probe|upper))} + {% endif %} + {% endif %} + {% if user.hw.mag_probe.ena and probe == 'attached' %} + {action_respond_info("Home&Probe: Probe docked, remove probe first")} + DETACH_PROBE ; detach probe + {% endif %} + _SET_Z_CURRENT VAL=HOME ; reduce Z current + G90 ; absolute position + G0 X{z_endstop.x} Y{z_endstop.y} F{user.speed.travel} ; move to endstop position + G28 Z ; home Z + G0 Z{z_endstop.z} F{user.speed.z_hop/3} ; lift toolhead to stop pressing on the pin + {% if calibrate_z_next %} + SET_GCODE_VARIABLE MACRO=_HOME_Z VARIABLE=calibrate_z_next VALUE=False + {% else %} + _SET_Z_CURRENT ; set Z current back to cfg value + G0 Z{user.z_hop} F{user.speed.z_hop} ; lift toolhead + {% endif %} + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set it back to relative + +##################################################################### +# Macros +##################################################################### +## conditional home +[gcode_macro _CG28] +description: Helper: Conditional homing +gcode: + {% if "xyz" not in printer.toolhead.homed_axes %} G28 {% endif %} + +[gcode_macro _SET_Z_CURRENT] +description: Helper: Set Z-drive motor current +variable_last_val: 'CONFIG' +gcode: + {% set val = params.VAL|default('CONFIG') %} + {% set z_run = printer['gcode_macro _USER_VARIABLE'].homing.z_current if val == 'HOME' + else printer.configfile.settings['tmc2209 stepper_z'].run_current if 'tmc2209 stepper_z' in printer.configfile.settings + else printer.configfile.settings['tmc5160 stepper_z'].run_current if 'tmc5160 stepper_z' in printer.configfile.settings %} + {% if val != last_val %} + SET_GCODE_VARIABLE MACRO=_SET_Z_CURRENT VARIABLE=last_val VALUE='"{val}"' + {% if params.RESPOND|default(printer['gcode_macro _USER_VARIABLE'].respond.z_current)|int == 1 %} + {action_respond_info("Home&Probe: RunCur %.2fA rms" % z_run|float)} + {% endif %} + SET_TMC_CURRENT STEPPER=stepper_z CURRENT={z_run} + SET_TMC_CURRENT STEPPER=stepper_z1 CURRENT={z_run} + SET_TMC_CURRENT STEPPER=stepper_z2 CURRENT={z_run} + SET_TMC_CURRENT STEPPER=stepper_z3 CURRENT={z_run} + M400 + {% endif %} + +[gcode_macro _SET_ACC] +description: Helper: Set accel and accel_to_decel value +variable_last_val: 'CONFIG' +gcode: + {% set val = params.VAL|default('CONFIG') %} + {% set accel = printer['gcode_macro _USER_VARIABLE'].homing.accel if val == 'HOME' + else printer.configfile.settings.printer.max_accel %} + {% set accel_to_decel = printer['gcode_macro _USER_VARIABLE'].homing.accel|int / 2 if val == 'HOME' + else printer.configfile.settings.printer.max_accel_to_decel %} + {% if val != last_val %} + SET_GCODE_VARIABLE MACRO=_SET_ACC VARIABLE=last_val VALUE='"{val}"' + {% if params.RESPOND|default(printer['gcode_macro _USER_VARIABLE'].respond.acc)|int == 1 %} + {action_respond_info("Home&Probe: ACCEL: %d ACCEL_TO_DECEL: %d" % (accel|int, accel_to_decel|int))} + {% endif %} + SET_VELOCITY_LIMIT ACCEL={accel} ACCEL_TO_DECEL={accel_to_decel} + {% endif %} diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg new file mode 100644 index 000000000..a7d1cd15e --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg @@ -0,0 +1,151 @@ +##################################################################### +# G Sensor definition +##################################################################### +[adxl345] +cs_pin: rpi:None +## The SPI speed (in hz) to use when communicating with the chip. +## The default is 5000000. +#spi_speed: 5000000 +## Output data rate for ADXL345. ADXL345 supports the following data +## rates: 3200, 1600, 800, 400, 200, 100, 50, and 25. Note that it is +## not recommended to change this rate from the default 3200, and +## rates below 800 will considerably affect the quality of resonance +## measurements. +#rate: 3200 +## The accelerometer axis for each of the printer's x, y, and z axes. +## This may be useful if the accelerometer is mounted in an +## orientation that does not match the printer orientation. For +## example, one could set this to "y,x,z" to swap the x and y axes. +## It is also possible to negate an axis if the accelerometer +## direction is reversed (eg, "x,z,-y"). The default is "x,y,z". +## receck +axes_map: x,y,z + +##################################################################### +# resonance tester definition +##################################################################### +[resonance_tester] +accel_chip: adxl345 +## A list of X,Y,Z coordinates of points (one point per line) to test +## resonances at. At least one point is required. Make sure that all +## points with some safety margin in XY plane (~a few centimeters) +## are reachable by the toolhead. +probe_points: + 175,175,20 +# 175,175,160 +# 175,175,300 +## Maximum input shaper smoothing to allow for each axis during shaper +## auto-calibration (with 'SHAPER_CALIBRATE' command). By default no +## maximum smoothing is specified. Refer to Measuring_Resonances guide +## for more details on using this feature. +#max_smoothing: +## Minimum/Maximum frequency to test for resonances. +min_freq: 5 +max_freq: 133 +## This parameter is used to determine which acceleration to use to +## test a specific frequency: accel = accel_per_hz * freq. Higher the +## value, the higher is the energy of the oscillations. Can be set to +## a lower than the default value if the resonances get too strong on +## the printer. However, lower values make measurements of +## high-frequency resonances less precise. The default value is 75 +## (mm/sec). +accel_per_hz: 75 +## Determines the speed of the test. When testing all frequencies in +## range [min_freq, max_freq], each second the frequency increases by +## hz_per_sec. Small values make the test slow, and the large values +## will decrease the precision of the test. The default value is 1.0 +## (Hz/sec == sec^-2). +hz_per_sec: 1 + +##################################################################### +# input shaper definition +##################################################################### +[input_shaper] +## A frequency (in Hz) of the input shaper for X or Y axis. +shaper_freq_x: 61.4 +shaper_freq_y: 43.4 +## A type of the intput shaper for X or Y axia. +shaper_type_x: mzv +shaper_type_y: mzv +## Damping ratios of vibrations of X and Y axes used by input shapers +## to improve vibration suppression. Default value is 0.1 which is a +## good all-round value for most printers. In most circumstances this +## parameter requires no tuning and should not be changed. +#damping_ratio_x: 0.1 +#damping_ratio_y: 0.1 + +##################################################################### +# Macros +##################################################################### +# !!! This macro only works with the use of gcode_shell_command.py !!! +# you find both needed files at /klipper_config/script +# - gcode_shell_command.py -> klipper add on file +# - plot_graph.sh -> shell script that is executed +# +# Setup: +# - symlink or copy gcode_shell_command.py to /klipper/klippy/extra +# e.g ln -s /home/pi/klipper_config/script/gcode_shell_command.py /home/pi/klipper/klippy/extras/gcode_shell_command.py +# - klipper service restart +# +# Please inspect the shell script by yourself and use it at your own risk +# Functions: +# - Generate folder if needed. Default path is IS_FOLDER=~/klipper_config/input_shaper +# - Store a defined number of results for the RESONANCES_TEST/BELT_TEST. Default is STORE_RESULTS=5 +# - generate/store following files for RESONANCES_TEST: +# - resonances_x_YYYYMMDD_HHMMSS.csv +# - resonances_y_YYYYMMDD_HHMMSS.csv +# - resonances_x_YYYYMMDD_HHMMSS.png +# - resonances_y_YYYYMMDD_HHMMSS.png +# - generate/store following files for BELT_TEST: +# - raw_data_belt_a_YYYYMMDD_HHMMSS.csv +# - raw_data_belt_b_YYYYMMDD_HHMMSS.csv +# - resonances_belts_YYYYMMDD_HHMMSS.png +# - remove files from /tmp +##################################################################### +[gcode_macro RESONANCES_TEST] +description: Run input shaper test +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + _CG28 ; home if needed + TURN_OFF_HEATERS ; turn off heaters + M107 ; turn off fan + {% if user.hw.chamber.fan %} M141 {% endif %} ; exhaust fan off + {% if user.hw.filter.ena %} _SET_FILTER {% endif %} ; filter off + _PRINT_AR T="INPUT SHAPER: Noise values, check if sensor is installed" + MEASURE_AXES_NOISE ; get noise value in log + _PRINT_AR T="INPUT SHAPER: Resonance Tests starting" + _PRINT_AR T="INPUT SHAPER: Mesasure X axis" + TEST_RESONANCES AXIS=X ; measure X + _PRINT_AR T="INPUT SHAPER: Mesasure Y axis" + TEST_RESONANCES AXIS=Y ; measure Y + _PRINT_AR T="INPUT SHAPER: Resonance Tests done" + _PRINT_AR T="INPUT SHAPER: Generate graph in backround" + RUN_SHELL_COMMAND CMD=plot_graph PARAMS=SHAPER + +[gcode_macro BELT_TEST] +description: Run resonance test to analyze belts +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + _CG28 ; home if needed + TURN_OFF_HEATERS ; turn off heaters + M107 ; turn off fan + {% if user.hw.chamber.fan %} M141 {% endif %} ; exhaust fan off + {% if user.hw.filter.ena %} _SET_FILTER {% endif %} ; filter off + _PRINT_AR T="BELT TEST: Noise values, check if sensor is installed" + MEASURE_AXES_NOISE ; get noise value in log + _PRINT_AR T="BELT TEST: Resonance Tests starting ..." + _PRINT_AR T="BELT TEST: Mesasure B belt" + TEST_RESONANCES AXIS=1,1 OUTPUT=raw_data NAME=b + _PRINT_AR T="BELT TEST: Mesasure A belt" + TEST_RESONANCES AXIS=1,-1 OUTPUT=raw_data NAME=a + _PRINT_AR T="BELT TEST: Resonance Tests done" + _PRINT_AR T="BELT TEST: Generate graph in backround" + RUN_SHELL_COMMAND CMD=plot_graph PARAMS=BELT + +# Shell Comand is not supported by a default klipper installation +[gcode_shell_command plot_graph] +command: bash /home/pi/klipper_config/script/plot_graph.sh +timeout: 60.0 +verbose: True + + diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg new file mode 100644 index 000000000..7374570c2 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg @@ -0,0 +1,303 @@ +# Displays mini12864 LCD (Fystec) +[display] +lcd_type: uc1701 +cs_pin: z:P1.18 +a0_pin: z:P1.19 +encoder_pins: ^z:P3.25,^z:P3.26 +click_pin: ^!z:P0.28 +contrast: 63 +display_group: __voron_display +# Use either: +# __voron_main : that is a complete menu you need to [include display_menu.cfg] here. +# __voron_empty: only activates the backlight of the display for 10 sek if you +# hit the knob with no other function. In this case you can comment out +# [include display_menu.cfg] +# remove menu_root: ... if you want to use the stock menu +menu_root: __voron_empty + +# Display menu definitions +[menu __voron_empty] +type: command +name: Main +gcode: {menu.exit()} + +#[include display_menu.cfg] + +[neopixel neo_display] +# Fystec 1 backlight 2/3 knob +# BTT 3 backlight 1/2 knob +# the macros here are written for Fystec if you use BTT you need to change the index +pin: z:P1.21 +chain_count: 3 +color_order: RGB +initial_RED: 0.8 +initial_GREEN: 0.8 +initial_BLUE: 1.0 + +[output_pin _BEEPER] +pin: z:P1.30 +pwm: TRUE +value: 0 +shutdown_value: 0 +# PWM frequency : 0.001 = 1ms will give a base tone of 1kHz +cycle_time: 0.0024 + +# this solution is purly a workaround to switch on the display +# when pressing the menu button. It has the following limitaions: +# - As it is handled as normal gcode it can take a few sec to +# execute the gcode and light up +# - At blocking gcodes e.g M190 it will executed after that finished +# - You need to add 'UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10' +# manual to each menu item you execute with the menu.exit methode +# add this to use the click pin also to switch on display +[duplicate_pin_override] +pins: z:P0.28 + +[gcode_button click_button_display] +pin: ^!z:P0.28 +press_gcode: {% if not printer.menu.running %} _DISPLAY_ON {% endif %} +release_gcode: {% if not printer.menu.running %} UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 {% endif %} + +# Glyph definition +[display_glyph chamber] +data: + 0000000000000000 + 1111111111111111 + 1000010000100001 + 1000010000100001 + 1000011111100001 + 1000000000000001 + 1000000000000001 + 1000001111000001 + 1011101001011101 + 1000001111000001 + 1000000110000001 + 1000000000000001 + 1011111111111101 + 1000100000010001 + 1111111111111111 + 0000000000000000 + +[display_glyph voron] +data: + 1111111001111111 + 1111100000011111 + 1111000000001111 + 1100000000000011 + 1000001100110001 + 1000011001100001 + 1000110011000001 + 1001100110000001 + 1000000110011001 + 1000001100110001 + 1000011001100001 + 1000110011000001 + 1110000000000111 + 1111000000001111 + 1111100000011111 + 1111111001111111 + +[display_glyph voroninv] +data: + 0000001110000000 + 0000111111100000 + 0001111111110000 + 0111111111111100 + 1111100111001110 + 1111001110011110 + 1110011100111110 + 1100111001111110 + 1111110011100110 + 1111100111001110 + 1111001110011110 + 1110011100111110 + 0111111111111100 + 0001111111110000 + 0000111111100000 + 0000001110000000 + +# Display Data definition +[display_template _vheater_temperature] +param_heater: "extruder" +text: + {% if param_heater in printer %} + # Show glyph + {% if param_heater == "heater_bed" %} + {% if printer[param_heater].target %} + {% set frame = (printer.toolhead.estimated_print_time|int % 2) + 1 %} + ~bed_heat{frame}~ + {% else %} + ~bed~ + {% endif %} + {% else %} + ~extruder~ + {% endif %} + # Show temperature + { "%3.0f" % (printer[param_heater].temperature,) } + # Optionally show target + {% if printer[param_heater].target and (printer[param_heater].temperature - printer[param_heater].target)|abs > 2 %} + ~right_arrow~ + { "%0.0f" % (printer[param_heater].target,) } + {% endif %} + ~degrees~ + {% endif %} + +[display_data __voron_display extruder] +position: 0, 0 +text: { render("_vheater_temperature", param_heater="extruder") } + +[display_data __voron_display fan] +position: 0, 10 +text: + {% if 'fan' in printer %} + {% set speed = printer.fan.speed %} + {% if speed %} + {% set frame = (printer.toolhead.estimated_print_time|int % 2) + 1 %} + ~fan{frame}~ + {% else %} + ~fan1~ + {% endif %} + { "{:>4.0%}".format(speed) } + {% endif %} + +[display_data __voron_display bed] +position: 1, 0 +text: { render("_vheater_temperature", param_heater="heater_bed") } + +[display_data __voron_display progress_text] +position: 1, 10 +text: + {% set progress = printer.virtual_sdcard.progress %} + { "{:^6.0%}".format(progress) } + +[display_data __voron_display progress_text2] +position: 1, 10 +text: + {% set progress = printer.virtual_sdcard.progress %} + { draw_progress_bar(1, 10, 6, progress) } + +[display_data __voron_display chamber] +position: 2, 0 +text: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% if 'chamber' in user.hw and user.hw.chamber.ena %} + ~chamber~ + { "%3.0f" % printer["temperature_" + user.hw.chamber.type + " chamber"].temperature } + ~degrees~ + {% endif %} + +[display_data __voron_display printing_time] +position: 2, 10 +text: + {% set ptime = printer.print_stats.total_duration %} + { "%02d:%02d" % (ptime // (60 * 60), (ptime // 60) % 60) } + +[display_data __voron_display print_status] +position: 3, 0 +text: + {% if printer.display_status.message %} + { printer.display_status.message } + {% elif printer.idle_timeout.printing_time|int != 0 %} + {% set pos = printer.motion_report.live_position %} + { "X%-4.0fY%-4.0fZ%-5.2f" % (pos.x, pos.y, pos.z) } + {% else %} + { "V2.660 " } + ~voroninv~ + {% endif %} + +# Macro definition + +# M300 [P] [S] +# P is the tone duration, S the tone frequency. +# The frequency won't be pitch perfect. +# Volume can be adjusted with VALUE. Maximum volume is VALUE=0.5 on the 12864. +[gcode_macro M300] +description: Set Beeper value +gcode: + {% set freq = params.S|default(440)|float %} + {% if freq != 0 %} SET_PIN PIN=_BEEPER VALUE=0.3 CYCLE_TIME={1/freq} {% endif %} + G4 P{params.P|default(100)|int} + SET_PIN PIN=_BEEPER VALUE=0 + +[delayed_gcode _DISPLAY_INIT] +gcode: + {% if printer['gcode_macro _USER_VARIABLE'].hw.display.ena %} + _LCD_KNOB COLOR=GREEN SYNC=1 + UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + {% endif %} + +[gcode_macro _LCD_KNOB] +description: Helper: Set LCD Knob color +variable_knob: {'act' : {'pri':{'R':0.0, 'G':0.3, 'B':0.0}, + 'sec':{'R':0.0, 'G':0.0, 'B':0.0}}, + 'restore': {'pri':{'R':0.0, 'G':0.0, 'B':0.0}, + 'sec':{'R':0.0, 'G':0.0, 'B':0.0}}, + 'time' : 0, + 'sync' : 0} +variable_select: 1 ; used to select what neopixel is active while blinking +gcode: + ##### color definition ##### + {% set color_dic = {'OFF' :{'R':0.0, 'G':0.0, 'B':0.0}, + 'GREEN':{'R':0.0, 'G':0.3, 'B':0.0}, + 'RED' :{'R':0.5, 'G':0.0, 'B':0.0}, + 'BLUE' :{'R':0.0, 'G':0.0, 'B':0.5}} %} + ##### get PARAMETERS or use defaults values ##### + {% set _dummy = knob.update({'time': params.BLINK|default(0)|float}) %} + {% set _dummy = knob.update({'sync': params.SYNC|default(0)|int}) %} + {% if 'COLOR' in params|upper %} + {% set color = params.COLOR|upper %} + {% set _dummy = knob.restore.update({'pri':knob.act.pri}) %} + {% if color in color_dic %} + {% set _dummy = knob.act.update({'pri':color_dic[color]}) %} + {% else %} + {action_respond_info("LCD KNOB COLOR %s is not defined used default: GREEN" % color)} + {% set _dummy = knob.act.update({'pri':color_dic.GREEN}) %} + {% endif %} + {% else %} + {% set _dummy = knob.act.update({'pri':knob.restore.pri}) %} + {% endif %} + ##### store new variable values ##### + SET_GCODE_VARIABLE MACRO=_LCD_KNOB VARIABLE=knob VALUE="{knob}" + ##### update to new color and start or stop blinking ##### + SET_LED LED=neo_display RED={knob.act.pri.R} GREEN={knob.act.pri.G} BLUE={knob.act.pri.B} INDEX=2 TRANSMIT=0 SYNC={knob.sync} + SET_LED LED=neo_display RED={knob.act.pri.R} GREEN={knob.act.pri.G} BLUE={knob.act.pri.B} INDEX=3 TRANSMIT=1 SYNC={knob.sync} + UPDATE_DELAYED_GCODE ID=_BLINK_DELAY DURATION={knob.time} + +[delayed_gcode _BLINK_DELAY] +gcode: + {% set knob = printer["gcode_macro _LCD_KNOB"].knob %} + {% set i = [2,3] if printer["gcode_macro _LCD_KNOB"].select|int == 1 else [3,2] %} + SET_GCODE_VARIABLE MACRO=_LCD_KNOB VARIABLE=select VALUE={(printer["gcode_macro _LCD_KNOB"].select|int * -1)} + SET_LED LED=neo_display RED={knob.act.pri.R} GREEN={knob.act.pri.G} BLUE={knob.act.pri.B} INDEX={i[0]} TRANSMIT=0 SYNC={knob.sync} + SET_LED LED=neo_display RED={knob.act.sec.R} GREEN={knob.act.sec.G} BLUE={knob.act.sec.B} INDEX={i[1]} TRANSMIT=1 SYNC={knob.sync} + UPDATE_DELAYED_GCODE ID=_BLINK_DELAY DURATION={knob.time} + +[gcode_macro DISPLAY] +description: Toggle Display backlight +variable_state: 'on' +gcode: + {% if state == 'on' %} _DISPLAY_OFF {% else %} _DISPLAY_ON {% endif %} + _DISPLAY_STATE + +[gcode_macro _DISPLAY_STATE] +description: Helper: Print display backlight state +gcode: {action_respond_info("LCD display %s" % (printer["gcode_macro DISPLAY"].state))} + +[gcode_macro _DISPLAY_OFF] +description: Helper: Display backlight off +gcode: + {% if not printer.menu.running and printer['gcode_macro _USER_VARIABLE'].hw.display.ena %} + SET_GCODE_VARIABLE MACRO=DISPLAY VARIABLE=state VALUE='"off"' + SET_LED LED=neo_display RED=0 GREEN=0 BLUE=0 INDEX=1 TRANSMIT=1 SYNC=0 + {% endif %} + +[gcode_macro _DISPLAY_ON] +description: Helper: Display backlight on +gcode: + {% if printer['gcode_macro _USER_VARIABLE'].hw.display.ena %} + SET_GCODE_VARIABLE MACRO=DISPLAY VARIABLE=state VALUE='"on"' + SET_LED LED=neo_display RED=0.8 GREEN=0.8 BLUE=1.0 INDEX=1 TRANSMIT=1 SYNC=0 + {% endif %} + +[delayed_gcode _DELAY_DISPLAY_OFF] +gcode: _DISPLAY_OFF \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg new file mode 100644 index 000000000..93fdfea96 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg @@ -0,0 +1,356 @@ +## User Paramaters +## BED_TEMP : Target temperature for the Bed. Is also used to decide +## if heatsoak is needed +## EXTRUDER_TEMP : Target temperature for the Extruder +## CHAMBER_TEMP : Target temperature for the chamber fan controll +## SOAK : Soak time in minutes +## DELTA_B : Allowed delta between actual bed temperature and target +## temperature for the decision if heat soak is needed. +## DELTA_C : Allowed delta between actual chamber temperature and target +## will wait until target reached or time is zero +## CHAMBER_SOAK : Extra Soak time if Chamber is not on target - DELTA_C +## EXTRA_SOAK : Enables Chamber Soak ('true'/'false') +## LAYER_HEIGHT : Hight of prime_line should be set to layer_hight +## Z_ADJUST : Add extra z offset via slicer +## FILTER : Activate Nevermore 1 On 0 Off default On +[gcode_macro PRINT_START] +description: All cmd needed at print start +variable_var: {'temp' : {'extruder': 245.0, 'bed': 100.0, 'chamber': 40.0, 'endstop': 0.0}, + 'delta' : {'chamber': 5.0, 'bed': 10}, + 'time' : {'soak' : 1800, 'soak_extra': 900}, + 'redo_qgl' : True, + 'prime_height': 0.0, + 'z_adjust' : 0.0, + 'filter' : True} +## Valid state +## Prepare : Store Params +## HeatBed : heat up bed and decide if soak is needed +## HeatSoak : loop the time specified with SOAK +## Chamber : decide if extra soak is needed +## ChamberSoak: loop the time specified with EXTRA_SOAK or Chamber target reached +## Final : all what needs to be done after wait time +variable_state: 'Prepare' +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set actBed = printer['temperature_sensor bed'].temperature|float|round(1) if 'temperature_sensor bed' in printer + else printer.heater_bed.temperature|float|round(1) %} ; get actual temp from extra sensor or heater sensor + ############################## Prepare phase only done at the first exection of PRINT_START ############################## + {% if state == 'Prepare' %} + ############# Store input parameters ############# + {% set var = {'temp': {'extruder': params.EXTRUDER_TEMP|default(245)|float|round(1), + 'bed' : params.BED_TEMP|default(100)|float|round(1), + 'chamber' : params.CHAMBER_TEMP|default(50)|float|round(1), + 'endstop' : 0.0}, + 'delta': {'chamber': params.DELTA_C|default(5)|float|round(1), + 'bed' : params.DELTA_B|default(10)|float|round(1)}, + 'time' : {'soak' : params.SOAK|default(30)|int * 60, + 'soak_extra': params.CHAMBER_SOAK|default(15)|int * 60 if params.EXTRA_SOAK|default('true') == 'true' and + user.hw.chamber.ena + else 0}, + 'redo_qgl' : True, + 'prime_height': params.LAYER_HEIGHT|float * user.print_start.prime_mult|float if LAYER_HEIGHT in params + else user.prime.pos.z|float, + 'z_adjust' : params.Z_ADJUST|default(0.0)|float, + 'filter' : False if params.FILTER|default(1)|int == 0 else True} %} + {% if user.hw.relay.ena %} _HEATER_ON {% endif %} + {% if user.hw.caselight.ena %} _CASELIGHT_ON {% endif %} ; switch on light + {% if user.hw.display.ena %} _LCD_KNOB COLOR=RED BLINK=1 {% endif %} + {% if user.hw.chamber.fan %} M141 S0 {% endif %} ; exhaust fan off + {% if user.hw.filter.ena and var.filter %} _FILTER_ON {% endif %} ; activate filter + _CG28 ; home if needed + G90 ; absolute position + G0 Z{user.park.bed.z} F{user.speed.z_hop} ; move nozzle to z high first + G0 X{user.park.bed.x} Y{user.park.bed.y} F{user.speed.travel} ; home to get toolhead in the middle + PAUSE_BASE + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=var VALUE="{var}" + SET_GCODE_VARIABLE MACRO=CANCEL_PRINT VARIABLE=execute VALUE=False + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"HeatBed"' + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION=0.5 + ############################## HeatBed Phase heat up the bed ############################## + {% elif state == 'HeatBed' %} + # get max allow bed temp from config. Lower it by 5C to avoid shutdown + {% set cfg_bed_max = printer.configfile.settings.heater_bed.max_temp|float|round(1) - 5.0 %} + {% set targetBed = var.temp.bed - var.delta.bed %} + {% set soakBed = [(var.temp.bed + user.print_start.bed_up), cfg_bed_max]|min %} + {% if (var.time.soak <= 0) or (actBed >= targetBed) %} ; check if soak time is 0 or if the bed is still hot + M117 Heating Extruder + {% set text = 'heat soak disabled' if var.time.soak <= 0 else 'heat soak not needed' %} + _PRINT_AR T="{"Bed temp: act %3.1f°C min %3.1f°C (target(%3.1f°C) - delta(%2.1f°C)) %s" % + (actBed,targetBed,var.temp.bed,var.delta.bed,text)}" + {% set _dummy = var.update({'redo_qgl' : False}) %} + M140 S{var.temp.bed} ; heat bed + M109 S{var.temp.extruder} ; heat extruder and wait + M190 S{var.temp.bed} ; heat bed and wait + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"Chamber"' + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION=0.5 + {% else %} + M117 Heating Bed + _PRINT_AR T="{"Bed temp: act %3.1f°C min %3.1f°C (target(%3.1f°C) - delta(%2.1f°C)) heat soak needed" % + (actBed,targetBed,var.temp.bed,var.delta.bed)}" + _PRINT_AR T="{"Set Bed temp to %3.1f°C instead of %3.1f°C for faster heat soak" % (soakBed,var.temp.bed)}" + M106 S90 ; switch part cooling ~35% to move air in chamber + M140 S{soakBed} ; heat bed + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"HeatSoak"' + {% set next_duration = user.print_start.ival if var.time.soak > user.print_start.ival else var.time.soak %} + {% set _dummy = var.time.update({'soak': var.time.soak - user.print_start.ival}) if var.time.soak > user.print_start.ival + else var.time.update({'soak': 0}) %} + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION={next_duration} + {% endif%} + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=var VALUE="{var}" + _RUNOUT_INFO + ############################## Heatsoak Phase call the delay macro until time is over ############################## + {% elif state == 'HeatSoak' %} + ############# Get filament runout info ############# + {% if user.hw.runout.sensor %} + {% if printer["filament_" + user.hw.runout.type + "_sensor runout"].enabled|lower == 'true' %} + {% set filament_detected = printer["filament_" + user.hw.runout.type + "_sensor runout"].filament_detected %} + {% elif 'filament_loaded' in printer.save_variables.variables %} + {% set filament_detected = printer.save_variables.variables.filament_loaded %} + {% else %} + {% set filament_detected = True %} + {% endif %} + {% elif user.hw.runout.type == 'file' %} + {% set filament_detected = printer.save_variables.variables.filament_loaded %} + {% else %} + {% set filament_detected = True %} + {% endif %} + {% if filament_detected %} + {% if var.time.soak <= (user.print_start.time.extruder + var.temp.extruder - 240) and + var.temp.extruder != printer.extruder.target %} ; check time to start heating extruder + M104 S{var.temp.extruder} ; heat extruder + {% endif %} + {% if var.time.soak <= user.print_start.time.bed and bed != printer.heater_bed.target|int %} ; check time to reduce bed temp + M140 S{var.temp.bed} ; heat bed + {% endif %} + {% if var.time.soak > 0 %} ; check remaining time + {% set next_duration = var.time.soak if user.print_start.ival >= var.time.soak else user.print_start.ival %} + {% set _dummy = var.time.update({'soak': 0}) if user.print_start.ival >= var.time.soak + else var.time.update({'soak': var.time.soak - user.print_start.ival}) %}} + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION={next_duration} + {% else %} + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"Chamber"' + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION=0.5 + _PRINT_AR T="{"Bed act temp=%3.1fC heat soak done" % (actBed)}" + {% endif%} + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=var VALUE="{var}" + {% else %} + _PRINT_AR T="No Filament loaded, print aborded!" + CANCEL_PRINT PARK=1 ERROR=1 + {% endif %} + ############################## Decide if extended soaking is needed ############################## + {% elif state == 'Chamber' %} + {% set targetChamber = var.temp.chamber - var.delta.chamber %} + {% set actChamber = printer["temperature_" + user.hw.chamber.type + " chamber"].temperature|round(1) if user.hw.chamber.ena + else 0 %} + {% if var.time.soak_extra > 0 and actChamber < targetChamber %} + _PRINT_AR T="{"Chamber temp: act %2.1f°C min %2.1f°C (target(%2.1f°C) - delta(%2.1f°C)) extra heat soak needed" % + (actChamber,targetChamber,var.temp.chamber,var.delta.chamber)}" + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"ChamberSoak"' + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION=0.5 + {% else %} + {% set text = 'extra heat soak disabled' if var.time.soak_extra <= 0 else 'extra heat soak not needed' %} + _PRINT_AR T="{"Chamber temp: act %2.1f°C min %2.1f°C (target(%2.1f°C) - delta(%2.1f°C)) %s" % + (actChamber,targetChamber,var.temp.chamber,var.delta.chamber,text)}" + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"Final"' + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION=0.5 + {% endif %} + ############################## extra Heat Soak terminated by chamber temp ############################## + {% elif state == 'ChamberSoak' %} + {% set targetChamber = var.temp.chamber - var.delta.chamber %} + {% set actChamber = printer["temperature_" + user.hw.chamber.type + " chamber"].temperature|round(1) if user.hw.chamber.ena + else 0 %} + {% if var.time.soak_extra > 0 and actChamber < targetChamber %} ; check remaining time and temp difference + {% set next_duration = var.time.soak_extra if user.print_start.ival >= var.time.soak_extra else user.print_start.ival %} + {% set _dummy = var.time.update({'soak_extra': 0}) if user.print_start.ival >= var.time.soak_extra + else var.time.update({'soak_extra': var.time.soak_extra - user.print_start.ival}) %}} + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION={next_duration} + {% else %} + {% set text = 'extra heat soak timed out' if var.time.soak_extra == 0 else 'chamber temp reached' %} + _PRINT_AR T="{"Chamber temp: act %2.1f°C min %2.1f°C (target(%2.1f°C) - delta(%2.1f°C)) %s" % + (actChamber,targetChamber,var.temp.chamber,var.delta.chamber,text)}" + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"Final"' + UPDATE_DELAYED_GCODE ID=_START_PRINT_WAIT DURATION=0.5 + {% endif %} + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=var VALUE="{var}" + ############################## all whats need to run at the end ############################## + {% elif state == 'Final' %} + RESUME_BASE + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"Prepare"' ; set state for next print + {% if user.hw.display.ena %} _LCD_KNOB COLOR=RED {% endif %} + M106 S0 ; turn off part cooling fan + G34 ; home & QGL + {% if user.hw.chamber.fan %} M141 S{var.temp.chamber} {% endif %} ; set target temp for exhaust fan + NOZZLECLEAN + SET_GCODE_VARIABLE MACRO=_HOME_Z VARIABLE=calibrate_z_next VALUE={user.hw.auto_z_offset.auto} + G28 Z + {% if user.hw.auto_z_offset.auto %} CALIBRATE_Z {% endif %} + {% if user.hw.auto_z_offset.manu %} _SET_PLATE_OFFSET {% endif %} + SET_GCODE_OFFSET Z_ADJUST={var.z_adjust} MOVE=1 + _PRINT_OFFSET + PRIME_LINE PRIME_HEIGHT={var.prime_height} + {% if user.hw.endstop_temp.ena %} + {% set _dummy = var.temp.update({'endstop': printer['temperature_sensor endstop'].temperature}) %} + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=var VALUE="{var}" + {% endif %} + G21 ; set units to millimeters + G90 ; use absolute coordinates + M83 ; use relative distances for extrusion + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=1 + {% endif %} + +[delayed_gcode _START_PRINT_WAIT] +gcode: + {% macro print_time(text, time) %} ; print remaining time + M117 {'%s' % text} {(time|int // 60)}:{'%02d' % (time|int % 60)} + {% endmacro %} + {% if printer['gcode_macro PRINT_START'].state == 'HeatSoak'%} + { print_time("HEAT SOAK", printer['gcode_macro PRINT_START'].var.time.soak) } + {% elif printer['gcode_macro PRINT_START'].state == 'ChamberSoak' %} + { print_time("SOAK", printer['gcode_macro PRINT_START'].var.time.soak_extra) } + {% endif %} + # Check CANCLE_PRINT was executed + {% if printer['gcode_macro CANCEL_PRINT'].execute|lower == 'false' %} + PRINT_START ; Junp back to PRINT_START + {% else %} ; break loop and insure state is correct for the next print start + SET_GCODE_VARIABLE MACRO=CANCEL_PRINT VARIABLE=execute VALUE=False + SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=state VALUE='"Prepare"' + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=1 + {% endif %} + +[gcode_macro PRINT_END] +description: All commands after the print +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set filter_off = user.peripheral.filter.run_after_print %} + {% set vent_on = user.peripheral.vent.on_val %} + {% set vent_off = user.peripheral.vent.run_after_print %} + # calculate save move + {% set max = printer.toolhead.axis_maximum %} + {% set act = printer.toolhead.position %} + {% set safe = {'x': 20.0 if act.x|float < (max.x|float - 20.0) else -20.0, + 'y': 20.0 if act.y|float < (max.y|float - 20.0) else -20.0, + 'z': 2.0 if act.z|float < (max.z|float - 2.0) else (max.z|float - act.z|float)} %} + M400 ; wait for buffer to clear + SAVE_GCODE_STATE NAME=STATE_PRINT_END + G92 E0 ; zero the extruder + M83 ; relative extrusion + G1 E-{user.filament.retract.end} F{user.speed.retract} ; retract filament + G91 ; relative positioning + G0 X{safe.x} Y{safe.y} Z{safe.z} F{user.speed.travel} ; move nozzle to remove stringing + TURN_OFF_HEATERS ; turn off heaters + M107 ; turn off fan + {% if user.hw.chamber.fan %} M141 S{vent_on} {% endif %} ; vent chamber (setting fan to below ambient) + G90 ; absolute positioning + G0 X{user.park.pause.x} Y{user.park.pause.y} F{user.speed.travel} ; park nozzle at brush bin + _ADD_PRINT_TIME + _SD_PRINT_STATS R='done' + _SD_PRINTER_STATS + {% if user.hw.display.ena %} _LCD_KNOB COLOR=GREEN {% endif %} + {% if user.hw.caselight.ena %} _CASELIGHT_OFF {% endif %} + {% if user.hw.chamber.fan %} UPDATE_DELAYED_GCODE ID=_DELAY_VENT_OFF DURATION={vent_off} {% endif %} + {% if user.hw.filter.ena %} UPDATE_DELAYED_GCODE ID=_DELAY_FILTER_OFF DURATION={filter_off} {% endif %} + {% if user.hw.endstop_temp.ena %} + {action_respond_info("PRINT_END + BED temp: act %3.1f°C + Endstop temp: start %3.1f°C end %3.1f°C" % (printer['temperature_sensor bed'].temperature if 'temperature_sensor bed' in printer + else printer.heater_bed.temperature, + printer['gcode_macro PRINT_START'].var.temp.endstop, + printer['temperature_sensor endstop'].temperature))} + {% endif %} + {% if user.unload_sd|lower == 'true' %} UPDATE_DELAYED_GCODE ID=_DELAY_SDCARD_RESET_FILE DURATION=10 {% endif %} + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=10 + RESTORE_GCODE_STATE NAME=STATE_PRINT_END + M220 S100 ; set feedrate percentage back to default + M221 S100 ; set speed percentage back to default + +[gcode_macro G34] +description: Reset bed mesh, offset and execute QGL +gcode: + _PRINT_AR T="Home & QGL" SHOW_LCD=true + BED_MESH_CLEAR + SET_GCODE_OFFSET Z=0 MOVE=1 + {% if printer['gcode_macro PRINT_START'].var.redo_qgl|lower == 'true' %} + _PRINT_AR T="QGL forced by PRINT_START" + QUAD_GANTRY_LEVEL PARK=false HOME=false + {% elif printer.quad_gantry_level.applied|lower == 'false' %} + _PRINT_AR T="QGL not executed yet" + QUAD_GANTRY_LEVEL PARK=false HOME=false + {% endif %} + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=1 + +[gcode_macro M204] +description: Set and limit acceleration to cfg value +rename_existing: M204.1 +gcode: + {% set accel = params.S|float if 'S' in params and params.S|float > 0 + else [params.P|float,params.T|float]|min if 'P' in params and 'T' in params and + params.P|float > 0 and params.T|float > 0 %} + {% if accel is defined %} + {% set lim_accel = [accel, printer.configfile.settings.printer.max_accel ]|min %} + {% set lim_accel_to_decel = [accel / 2, printer.configfile.settings.printer.max_accel_to_decel]|min %} + SET_VELOCITY_LIMIT ACCEL={lim_accel} ACCEL_TO_DECEL={lim_accel_to_decel} + {% else %} + {action_respond_info("Invalid M204 command \"M204 %s\"" % rawparams)} + {% endif %} + +[gcode_macro M900] +description: Set pressure advance +gcode: + SET_PRESSURE_ADVANCE ADVANCE={params.K|default(0)} + +[gcode_macro _PRINT_OFFSET] +description: Helper: Print gcode offsets defined by script or user in PRINT_START +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set text = ["GCODE OFFSET for Z applied from:"] %} + {% if user.hw.auto_z_offset.manu %} + {% set _dummy = text.append("Plate %s %.3fmm" % + (printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].name, + printer.save_variables.variables.plates.array[printer.save_variables.variables.plates.index].offset)) %} + {% endif %} + {% if user.hw.auto_z_offset.auto %} + {% set _dummy = text.append("Z_CALIBRATE %.3fmm" % printer.z_calibration.last_z_offset) %} + {% endif %} + {% set _dummy = text.append("User %.3fmm" % printer['gcode_macro PRINT_START'].var.z_adjust) %} + {% set _dummy = text.append("Total %.3fmm" % printer.gcode_move.homing_origin.z) %} + {action_respond_info(text|join("\n"))} + +[gcode_macro _RUNOUT_INFO] +description: Helper: Print runout sensor status +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set out = ['RUNOUT: ' + user.hw.runout.type|capitalize + ' Sensor'] if user.hw.runout.sensor + else ['RUNOUT: Stored in file'] if user.hw.runout.type == 'file' + else ['RUNOUT: Not monitored'] %} + + {% set enable = printer["filament_" + user.hw.runout.type + "_sensor runout"].enabled if user.hw.runout.sensor + else False %} + {% set _dummy = out.append('Enabled: ' + enable|lower) if user.hw.runout.sensor %} + {% set detected = printer["filament_" + user.hw.runout.type + "_sensor runout"].filament_detected if enable + else printer.save_variables.variables.filament_loaded if user.hw.runout.type == 'file' %} + {% set _dummy = out.append('Detect Filament: ' + detected|lower) if detected is defined %} + {action_respond_info(out|join("\n"))} + +## PrusaSlicer/SuperSlicer: +## Add at the start gcode section +## _LAYER TOTAL=[total_layer_count] RESPOND=0 +## +## Add at the layer change gcode section +## _LAYER CURRENT={layer_num+1} +[gcode_macro _LAYER] +description: Pass the current layer and the total amount of layers by your Slicer. +variable_layer: {'current': 0, 'total':0} +gcode: + {% set _dummy = layer.update({'total':params.TOTAL|int}) if ('TOTAL' in params and params.TOTAL|int > 0) %} + {% set _dummy = layer.update({'current':params.CURRENT|default(0)|int}) %} + SET_GCODE_VARIABLE MACRO=_LAYER VARIABLE=layer VALUE="{layer}" + {% if params.RESPOND|default(printer['gcode_macro _USER_VARIABLE'].respond.layer)|int == 1 %} + {action_respond_info("Layer %s of %s" % (layer.current, layer.total))} + {% endif %} + +[gcode_macro TOGGLE_LAYER_OUTPUT] +description: Enable/Disable Console output of _LAYER +gcode: + {% set respond = printer['gcode_macro _USER_VARIABLE'].respond %} + {% set _dummy = respond.update({'layer':1}) if respond.layer|int == 0 else respond.update({'layer':0}) %} + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=respond VALUE="{respond}" diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg new file mode 100644 index 000000000..4de56e67b --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg @@ -0,0 +1,286 @@ +##################################################################### +# User Macros +##################################################################### +## Used the same names as in +## to make the switch easier after the PR is merged +[gcode_macro ATTACH_PROBE] +description: Attaching the MagProbe if not already attached +gcode: + _MAG_PROBE ACTION=ATTACH + _MAG_PROBE ACTION=CHECK_ATTACH + +[gcode_macro DETACH_PROBE] +description: Dock the MagProbe if not already docked +gcode: + _MAG_PROBE ACTION=DOCK + _MAG_PROBE ACTION=CHECK_DOCK + +[gcode_macro GET_PROBE_STATUS] +description: Prints the current MagProbe state, valid probe states are UNKNOWN, ATTACHED and DOCKED +gcode: + _MAG_PROBE ACTION=GET_STATUS RESPOND=1 + +[gcode_macro SET_PROBE_STATUS] +description: Manually specify MagProbe status, valid probe states are UNKNOWN, ATTACHED and DOCKED +gcode: + {% if not params.STATE or params.STATE|lower is not in ['unknown','attached','docked'] %} + {action_raise_error("Invalid probe state: %s. Valid probe states are [UNKNOWN, ATTACHED, DOCKED]" % params.STATE|default('none')|upper)} + {% endif %} + SET_GCODE_VARIABLE MACRO=_PROBE_ACTION VARIABLE=man_state VALUE='"{params.STATE|lower}"' + SET_GCODE_VARIABLE MACRO=_MAG_PROBE VARIABLE=state VALUE='"{params.STATE|lower}"' + +##################################################################### +# Helper Macros +##################################################################### +# QUERY_PROBE must run direct before _PROBE_ACTION +# that relation is insured by the caller id +[gcode_macro _MAG_PROBE] +description: Helper: Query MagProbe state and request action +variable_state: 'unknown' +variable_dock_state: 'unknown' +variable_id: 0 +gcode: + {% set id = 1 if id == 0 else id + 1 %} ; generate an id not equal to 0 + QUERY_PROBE ID={id} + _PROBE_ACTION ACTION={params.ACTION} ID={id} {"RESPOND=" + params.RESPOND if params.RESPOND is defined else ""} + SET_GCODE_VARIABLE MACRO=_MAG_PROBE VARIABLE=id VALUE={id} + +[gcode_macro _PROBE_ACTION] +description: Helper: Perform MagProbe action +variable_man_state: 'unknown' +gcode: + {% set action = params.ACTION|default('undefined')|lower %} + {% set id = params.ID|default(0)|int %} + {% set probe_id = printer['gcode_macro QUERY_PROBE'].id|default(0)|int %} + {% set probe = 'attached' if printer.probe.last_query|int == 0 + else 'docked' if printer.probe.last_query|int == 1 %} + {% set error_id = 1 if printer.probe.last_query|lower == 'false' + else 2 if id == 0 or id != probe_id + else 3 if action is not in ['attach','dock','check_attach','check_dock','get_status'] + else 4 if action == 'check_dock' and probe != 'docked' + else 5 if action == 'check_attach' and probe != 'attached' + else 0 %} + {% set state = 'error' if error_id != 0 + else man_state if man_state != 'unknown' + else probe %} + {% if params.RESPOND|default(printer['gcode_macro _USER_VARIABLE'].respond.probe_action)|int == 1 %} + {% set txt = [] %} + {% if man_state != 'unknown' %}{% set _dummy = txt.append("State was set to %s by SET_PROBE_STATUS" % man_state)%}{% endif %} + {% if action == 'attach' and state == 'docked' %}{% set _dummy = txt.append("Attach Probe")%}{% endif %} + {% if action == 'attach' and state == 'attached' %}{% set _dummy = txt.append("Already attached")%}{% endif %} + {% if action == 'dock' and state == 'attached' %}{% set _dummy = txt.append("Dock Probe")%}{% endif %} + {% if action == 'dock' and state == 'docked' %}{% set _dummy = txt.append("Already docked")%}{% endif %} + {% if action == 'get_status' %}{% set _dummy = txt.append("Status: %s" % state)%}{% endif %} + {% if txt|length > 0 %} {action_respond_info("MagProbe: %s" % txt|join("\n"))} {% endif %} + {% endif %} + {% if action == 'attach' and state == 'docked' %} _ATTACH_PROBE {% endif %} + {% if action == 'dock' and state == 'attached' %} _DOCK_PROBE {% endif %} + SET_GCODE_VARIABLE MACRO=_PROBE_ACTION VARIABLE=man_state VALUE='"unknown"' + SET_GCODE_VARIABLE MACRO=_MAG_PROBE VARIABLE=state VALUE='"{state}"' + SET_GCODE_VARIABLE MACRO=_CHECK_STATE VARIABLE=error_id VALUE={error_id} + _CHECK_STATE + +[gcode_macro _CHECK_STATE] +description: Helper: Perform MagProbe error check +variable_error_id: 0 +gcode: + {% set txt = "Please execute QUERY_PROBE first" if error_id == 1 + else "Call ID invalid or does not match QUERY_PROBE call ID" if error_id == 2 + else "action not defined" if error_id == 3 + else "docking failed" if error_id == 4 + else "attaching failed" if error_id == 5 %} + {% if error_id != 0 %} {action_raise_error("MagProbe: ERROR, %s" % txt)} {% endif %} + +## used probe: klicky probe +## the probe is fixed to the Gantry +## +## Gantry +## ======= +## | dock| x position: probe.store +## | arm| +## +## x position: probe.dock +## +## Attach: +## 1) Prepare : move toolhead next to of dock arm (left or right depending on mouting position) +## 2) Dock Probe : move toolhead in X direction on the dock +## 3) Finisch : slide toolhead from holder (Y direction) +## +## Detach: +## 1) Prepare : move toolhead infront of the dock arm +## 2) UnDock Probe : slide toolhead on holder (Y direction) +## 3) Finisch Dock : move toolhead from dock arm (left or right depending on mouting position) +[gcode_macro _ATTACH_PROBE] +description: Helper: Attach MagProbe +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set move_z = [user.z_hop, printer.toolhead.position.z]|max %} ; calc movement high + G90 ; absolute positioning + G0 Z{move_z} F{user.speed.z_hop} ; move head up + G0 X{user.probe.store.x} Y{user.probe.store.y} F{user.speed.travel} ; step 1 + G0 X{user.probe.dock.x} F{user.speed.dock} ; step 2 + G0 Y{user.probe.dock.y} F{user.speed.dock} ; step 3 + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + +[gcode_macro _DOCK_PROBE] +description: Helper: Dock MagProbe +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set move_z = [user.z_hop, printer.toolhead.position.z]|max %} ; calc movement high + G90 ; absolute positioning + G0 Z{move_z} F{user.speed.z_hop} ; move head up + G0 X{user.probe.dock.x} Y{user.probe.dock.y} F{user.speed.travel} ; step 1 + G0 Y{user.probe.store.y} F{user.speed.dock} ; step 2 + G0 X{user.probe.store.x} F{user.speed.dock} ; step 3 + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + +##################################################################### +# Customized standard macros +##################################################################### +# QUAD_GANTRY_LEVEL can be found in probe_qgl.cfg +# BED_MESH_CALIBRATE can be found in bed_mesh.cfg +##################################################################### +# +# !!! Caution !!! +# +# PROBE_CALIBRATE will attach the probe run the probe sequence and +# than detach the probe. After that use the normal paper test to find +# the right height. Use ACCEPT or ABOURT as usual. +# +##################################################################### +# +# If your probe needs a Z move for attach/detach use either +# G0 .... FORCE +# G1 .... FORCE +# +##################################################################### +[gcode_macro G0] +description: Move gcode that prevents moves lower than the limit when probe attached +rename_existing: G0.1 +gcode: + {% if params.FORCE is defined or printer['gcode_macro _MAG_PROBE'].state == 'docked' %} + G0.1 {rawparams} + {% else %} + {% set param = [] %} + {% for key in params %} ; get gcode input parameters + {% set _dummy = param.append(key + "=" + params[key]) if key is not in ['G', 'FORCE'] %} + {% endfor %} + _Z_MOVE_CHECK CALLER=G0 {param|join(" ")} + {% endif %} + +[gcode_macro G1] +description: Move gcode that prevents moves lower than the limit when probe attached +rename_existing: G1.1 +gcode: + {% if params.FORCE is defined or printer['gcode_macro _MAG_PROBE'].state == 'docked' %} + G1.1 {rawparams} + {% else %} + {% set param = [] %} + {% for key in params %} ; get gcode input parameters + {% set _dummy = param.append(key + "=" + params[key]) if key is not in ['G', 'FORCE'] %} + {% endfor %} + _Z_MOVE_CHECK CALLER=G1 {param|join(" ")} + {% endif %} + +[gcode_macro _Z_MOVE_CHECK] +description: Helper: Check limit and perform move +gcode: + {% set param = [] %} + {% for key in params %} ; generate base macro call + {% if key == 'Z' %} + {% set z_target = params.Z|float if printer.gcode_move.absolute_coordinates + else params.Z|float + printer.gcode_move.gcode_position.z %} + {% set z_move_ok = True if z_target >= printer['gcode_macro _USER_VARIABLE'].z_hop or + z_target >= printer.gcode_move.gcode_position.z + else False %} + {% if z_move_ok %} + {% set _dummy = param.append(key + params[key]) %} + {% else %} + {action_respond_info("%s: Z Move (%.3f mm -> %.3f mm) not allowed" % + (params.CALLER, printer.gcode_move.gcode_position.z, z_target))} + {% endif %} + {% elif key != 'CALLER' %} + {% set _dummy = param.append(key + params[key]) %} + {% endif %} + {% endfor %} + {params.CALLER}.1 {param|join(" ")} ; call G0 or G1 base macro with all parameters + +[gcode_macro QUERY_PROBE] +description: Return the status of the z-probe and store ID +rename_existing: QUERY_PROBE_BASE +variable_id: 0 +gcode: + QUERY_PROBE_BASE + SET_GCODE_VARIABLE MACRO=QUERY_PROBE VARIABLE=id VALUE={params.ID|default(0)} ; call id 0 means invalid + +[gcode_macro PROBE_ACCURACY] +description: Probe Z-height accuracy at current XY position and dock/undock MagProbe +rename_existing: PROBE_ACCURACY_BASE +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + # as we need to return to the position with the probe we need to be at least at z_hop + {% if user.hw.mag_probe.ena and printer.gcode_move.gcode_position.z < user.z_hop %} + {action_respond_info("PROBE_ACCURACY: High must be above %.2f" % user.z_hop)} + G90 ; absolute positioning + G0 Z{user.z_hop} F{user.speed.z_hop} ; move head up + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + {% endif %} + {% if user.hw.mag_probe.ena == 'true' %} + SAVE_GCODE_STATE NAME=STATE_PROBE_ACCURACY + ATTACH_PROBE + RESTORE_GCODE_STATE NAME=STATE_PROBE_ACCURACY MOVE=1 MOVE_SPEED={(user.speed.travel|float / 60)} + {% endif %} + PROBE_ACCURACY_BASE {rawparams} + {% if user.hw.mag_probe.ena == 'true' and params.DOCK|default(1)|int == 1 %} ; use DOCK=0 to omit the probe docking + DETACH_PROBE + RESTORE_GCODE_STATE NAME=STATE_PROBE_ACCURACY MOVE=1 MOVE_SPEED={(user.speed.travel|float / 60)} + {% endif %} + +[gcode_macro PROBE] +description: Probe Z-height at current XY position and dock/undock MagProbe +rename_existing: PROBE_BASE +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + # as we need to return to the position with the probe we need to be at least at z_hop + {% if user.hw.mag_probe.ena == 'true' and printer.gcode_move.gcode_position.z < user.z_hop %} + {action_respond_info("PROBE_ACCURACY: High must be above %.2f" % user.z_hop)} + G90 ; absolute positioning + G0 Z{user.z_hop} F{user.speed.z_hop} ; move head up + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + {% endif %} + {% if user.hw.mag_probe.ena == 'true' %} + SAVE_GCODE_STATE NAME=STATE_PROBE + ATTACH_PROBE + RESTORE_GCODE_STATE NAME=STATE_PROBE MOVE=1 MOVE_SPEED={(user.speed.travel|float / 60)} + {% endif %} + PROBE_BASE {rawparams} + G1 Z{user.z_hop} F{user.speed.z_hop} ; move head up to remove trigger + {% if user.hw.mag_probe.ena == 'true' and params.DOCK|default(1)|int == 1 %} ; use DOCK=0 to omit the probe docking + DETACH_PROBE + RESTORE_GCODE_STATE NAME=STATE_PROBE MOVE=1 MOVE_SPEED={(user.speed.travel|float / 60)} + {% endif %} + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + +[gcode_macro PROBE_CALIBRATE] +description: Calibrate the probe's z_offset and undock MagProbe +rename_existing: PROBE_CALIBRATE_BASE +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + # as we need to return to the position with the probe we need to be at least at z_hop + {% if user.hw.mag_probe.ena == 'true' and printer.gcode_move.gcode_position.z < user.z_hop %} + {action_respond_info("PROBE_ACCURACY: High must be above %.2f" % user.z_hop)} + G90 ; absolute positioning + G0 Z{user.z_hop} F{user.speed.z_hop} ; move head up + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + {% endif %} + {% if user.hw.mag_probe.ena == 'true' %} + SAVE_GCODE_STATE NAME=STATE_PROBE_CALIBRATE_ATTACH + ATTACH_PROBE + RESTORE_GCODE_STATE NAME=STATE_PROBE_CALIBRATE_ATTACH MOVE=1 MOVE_SPEED={(user.speed.travel|float / 60)} + {% endif %} + PROBE_CALIBRATE_BASE {rawparams} + {% if user.hw.mag_probe.ena == 'true' %} + SAVE_GCODE_STATE NAME=STATE_PROBE_CALIBRATE_DETACH + DETACH_PROBE + RESTORE_GCODE_STATE NAME=STATE_PROBE_CALIBRATE_DETACH MOVE=1 MOVE_SPEED={(user.speed.travel|float / 60)} + {% endif %} \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf new file mode 100644 index 000000000..6d59bdd25 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf @@ -0,0 +1,187 @@ +[server] +host: 0.0.0.0 +port: 7125 +klippy_uds_address: /tmp/klippy_uds +enable_debug_logging: False +# The maximum size allowed for a file upload. Default is 1024 MiB. +max_upload_size: 1024 +# The port to listen on for SSL (HTTPS) connections. Note that the HTTPS +# server will only be started of the certificate and key options outlined +# below are provied. The default is 7130. +ssl_port: 7130 +# The path to a self signed ssl certificate. The default is no path, which +# disables HTTPS. +#ssl_certificate_path: +# The path to the private key used to signed the certificate. The default +# is no path, which disables HTTPS. +#ssl_key_path: + +[file_manager] +config_path: ~/klipper_config +log_path: ~/klipper_logs +# When set to True the file manager will add uploads to the job_queue when +# the `start_print` flag has been set. The default if False. +queue_gcode_uploads: False +# When set to True gcode files will be run through a "preprocessor" +# during metdata extraction if object tags are detected. This preprocessor +# replaces object tags with G-Code commands compatible with Klipper's +# "cancel object" functionality. Note that this process is file I/O intensive, +# it is not recommended for usage on low resource SBCs such as a Pi Zero. +# The default is False. +enable_object_processing: True + +[database] +database_path: ~/.moonraker_database +enable_database_debug: False + +[data_store] +# The maximum number of temperature values to store for each sensor. Note +# that this value also applies to the "target", "power", and "fan_speed" +# if the sensor reports them. The default is 1200, which is enough to +# store approximately 20 minutes of data at one value per second. +temperature_store_size: 1200 +# The maximum number "gcode lines" to store. The default is 1000. +gcode_store_size: 1000 + +[job_queue] +# When set to true the job queue will attempt to load the next +# pending job when Klipper reports as "Ready". If the queue has +# been paused it will automatically resume. Note that neither +# the job_transition_delay nor the job_transition_gcode are +# applied in this case. The default is False. +load_on_startup: False +# When set to True the queue will automatically transition to +# the next job in the queue after the current job is complete. +# This is useful for belt printers and other machines with the +# ability to automate clearing of the build area. When False +# the queue will be paused after each job is loaded, requiring +# that users manually resume to load the next print. The default +# is False. +automatic_transition: False +# The amount of time to delay after completion of a job before +# loading the next job on the queue. The default is no delay. +#job_transition_delay: +# A gcode to execute after the completion of a job before the next +# job is loaded. If a "job_transition_delay" has been configured +# this gcode will run after the delay. The default is no gcode. +#job_transition_gcode: + +[authorization] +# When set to True a user login is required for authorization if at least +# one user has been created, overriding the "trusted_clients" configuration. +# If no users have been created then trusted client checks will apply. +# The default is False. +force_logins: False +# The time, in days, after which a user is forced to re-enter their +# credentials to log in. This period begins when a logged out user +# first logs in. Successive logins without logging out will not +# renew the timeout. The default is 90 days. +#login_timeout: +cors_domains: + *.local + *://my.mainsail.xyz + *://app.fluidd.xyz + *://voron350 +trusted_clients: + 192.168.178.0/24 + 2a02:810d:9340:33f6::/64 + 172.29.199.0/25 + 127.0.0.1 + +[secrets] +secrets_path: ~/.moonraker_secret.json + +[octoprint_compat] + +[history] + +[timelapse] + +[update_manager] +channel: dev +enable_repo_debug: True +enable_auto_refresh: True +enable_system_updates: True +refresh_interval: 24 + +[update_manager mainsail] +type: web_beta +repo: mainsail-crew/mainsail +path: ~/mainsail + +[update_manager KlipperScreen] +type: git_repo +path: ~/KlipperScreen +env: /home/pi/.KlipperScreen-env/bin/python +origin: https://github.com/jordanruthe/KlipperScreen.git +requirements: scripts/KlipperScreen-requirements.txt +venv_args: -p python3 +install_script: scripts/KlipperScreen-install.sh + +[update_manager kiauh] +type: git_repo +path: ~/kiauh +origin: https://github.com/th33xitus/kiauh.git +is_system_service: False + +[update_manager z_calibration] +type: git_repo +path: ~/klipper_z_calibration +origin: https://github.com/protoloft/klipper_z_calibration.git + +[update_manager webcamd] +type: git_repo +path: ~/crowsnest +origin: https://github.com/mainsail-crew/crowsnest.git +primary_branch: nightly + +[update_manager timelapse] +type: git_repo +primary_branch: main +path: ~/moonraker-timelapse +origin: https://github.com/mainsail-crew/moonraker-timelapse.git + +[mqtt] +address: 192.168.178.200 +port: 1883 +username: {secrets.mqtt_credentials.username} +password: {secrets.mqtt_credentials.password} +# The protocol to use when connecting to the Broker. May be v3.1, +# v3.1.1, and v5. The default is v3.1.1 +mqtt_protocol: v3.1.1 +# If set to true the MQTT client will subscribe to API topic, ie: +# {instance_name}/moonraker/api/request +# This can be set to False if the user does not wish to allow API +# requests over MQTT. The default is True. +enable_moonraker_api: True +instance_name: printer/V2.660 +default_qos: 0 +# The QOS level to use for the API topics. If not provided, the +# value specified by "default_qos" will be used. +#api_qos: + +[power psu] +type: gpio +pin: !gpio14 +initial_state: on +bound_service: klipper +locked_while_printing: True + +[power bed] +type: gpio +pin: !gpio15 +initial_state: on +off_when_shutdown: True +locked_while_printing: True + +[power dryer] +type: mqtt +qos: 1 +command_topic: shellies/Schalten/OG/Arbeit/3dTrockner/relay/0/command +command_payload: {command} +retain_command_state: True +query_topic: shellies/Schalten/OG/Arbeit/3dTrockner/relay/0 +state_topic: shellies/Schalten/OG/Arbeit/3dTrockner/relay/0 +state_response_template: {payload} +query_after_command: False + diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg new file mode 100644 index 000000000..494e4d39f --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg @@ -0,0 +1,20 @@ +# You can specify the park_pos variable manually if you do not want +# to use a _USER_VARIABLE macro, The set statement would look like: +# {% set park_pos = {'x': val, 'y': val, 'z': val} %} +# e.g. +# {% set park_pos = {'x': 175.0, 'y': 25.0, 'z': 30.0 } %} + +[gcode_macro PARK] +description: Park head depending on parameter P +gcode: + {% if params.P and params.P|lower is not in ['bed','center','front','frontlow','rear'] %} + {action_respond_info("\"PARK P=%s\" not valid use P=[BED,CENTER,FRONT,FRONTLOW,REAR] + Default position BED will be used" % params.P|upper)} + {% else %} + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set pos = params.P|default('bed')|lower %} + _CG28 ; home if not already homed + G90 ; absolute positioning + G0 X{user.park[pos].x} Y{user.park[pos].y} Z{user.park[pos].z} F{user.speed.travel} + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + {% endif %} \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg new file mode 100644 index 000000000..1fc8c35dc --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg @@ -0,0 +1,90 @@ +##################################################################### +# Idle Timeout +##################################################################### +[idle_timeout] +gcode: + {% if printer.webhooks.state|lower == 'ready' %} + {% if printer.pause_resume.is_paused|lower == 'false' %} + {action_respond_info("POWER: Execute Idle Timeout")} + TURN_OFF_HEATERS + {% if printer['gcode_macro _USER_VARIABLE'].hw.relay.ena %} + UPDATE_DELAYED_GCODE ID=_DELAY_HEATER_OFF DURATION=10 + {% endif %} + UPDATE_DELAYED_GCODE ID=_DELAY_PSU_OFF DURATION=20 + {% endif %} + {% endif %} +# 2h timeout +timeout: 7200 + +##################################################################### +# Safety Relay extruder +##################################################################### +## Use a pin to switch on a relay for the Extruder heater if klipper is active +## XYE board, UPWR_DET_PIN Connector +[output_pin extruder_relay] +## negativ logic +pin: !P1.0 +pwm: false +shutdown_value: 0 +value: 1 + +##################################################################### +# Safety Relay heater_bed +##################################################################### +## Use a pin to switch on a relay for the heater_bed if klipper is active +## Z board, UPWR_DET_PIN Connector +[output_pin heater_bed_relay] +## negativ logic +pin: !z:P1.0 +pwm: false +shutdown_value: 0 +value: 1 + +##################################################################### +# Macro +##################################################################### +[delayed_gcode _DELAY_PSU_OFF] +gcode: + {action_respond_info("POWER: 24V PS power off")} + {action_call_remote_method("set_device_power", device="psu", state="off")} + +[gcode_macro _HEATER_ON] +description: Helper: Power on BED and Extruder power +gcode: + {%if printer['output_pin heater_bed_relay'].value == 0 %} + {action_respond_info("POWER: heater_bed power on")} + SET_PIN PIN=heater_bed_relay VALUE=1 + {% endif %} + {action_call_remote_method("set_device_power", device="bed", state="on")} + {%if printer['output_pin extruder_relay'].value == 0 %} + {action_respond_info("POWER: extruder power on")} + SET_PIN PIN=extruder_relay VALUE=1 + {% endif %} + +[delayed_gcode _DELAY_HEATER_OFF] +gcode: + {%if printer['output_pin heater_bed_relay'].value == 1 %} + {action_respond_info("POWER: heater_bed power off")} + SET_PIN PIN=heater_bed_relay VALUE=0 + {% endif %} + {action_call_remote_method("set_device_power", device="bed", state="off")} + {%if printer['output_pin extruder_relay'].value == 1 %} + {action_respond_info("POWER: extruder power off")} + SET_PIN PIN=extruder_relay VALUE=0 + {% endif %} + +[gcode_macro _SHUTDOWN_PI] +description: Helper: Power down the rPi +gcode: {action_call_remote_method("shutdown_machine")} + +[gcode_macro PRINTER_OFF] +description: Park head and Power down the rPi +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + _CG28 ; home if not already homed + G90 ; absolute positioning + G0 X{user.park.bed.x} Y{user.park.bed.y} Z{user.park.bed.z} F{user.speed.travel} + M117 PI Off in 5 sec + G4 P5000 + M400 + _SHUTDOWN_PI \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg new file mode 100644 index 000000000..d01420ad6 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg @@ -0,0 +1,185 @@ +##################################################################### +# Preperation +##################################################################### +# copy this file in the same directory as your printer.cfg +# add +# [include pressure_advance.cfg] +# to your printer.cfg +# +# A [save_variables] block is needed since a printer save variable needs to be used to have it available after power up. +# You can skip this if you already have an [save_variables] config block +# e.g: +# [save_variables] +# filename: /home/pi/klipper_config/.variables.stb +# I like to hide that file as there is nothing in that should be modified by the user. +# Do a klipper restart after adding the stuff above +# +# After klipper is back you need define your first filament id e.g. +# PRESSURE_ADVANCE_ADD FILAMENT=ABS +# +##################################################################### +# Macro for the print start or filament gcode section of your slicer +##################################################################### +# PRESSURE_ADVANCE_SELECT [FILAMENT=] [NOZZLE=] : Set pressure advanve and smooth +# time for the different filaments and nozzles combinations. If no combo is found +# the cfg values are used. +# +# For SuperSlicer/PrusaSlicer this could look like +# PRESSURE_ADVANCE_SELECT NOZZLE=[nozzle_diameter] FILAMENT=[filament_settings_id] +# +##################################################################### +# Console ussage +##################################################################### +# PRESSURE_ADVANCE_LIST: List all pressure advanve and smooth +# time for the different filaments and nozzles +# +# PRESSURE_ADVANCE_ADD FILAMENT= [NOZZLE=] [PRESSURE_ADVANCE=] [SMOOTH_TIME=]: +# Add new filaments, or nozzle to an existing filament or change pa settings for +# for an existing filament nozzle combination. +# Nozzle is defaulted to 0.4 and preasure advance/smoth time to the cfg values if not defined at the call +# !!! Caution do not use special characters like äüö or anything else in the name !!! +# +# PRESSURE_ADVANCE_REMOVE FILAMENT= [NOZZLE=]: Remove a definition +# If FILAMENT/NOZZLE is defined then only the coresponding nozzle setup will removed otherwise the complete +# filament. +# +##################################################################### +[gcode_macro PRESSURE_ADVANCE_LIST] +description: List all filament pressure advance settings +gcode: + {% if not printer.save_variables.variables.pressure_advance %} + {action_respond_info("PRESSURE ADVANCE: No filament defined ABORDED")} + {% else %} + {% set pa_dic = printer.save_variables.variables.pressure_advance %} + {% set out = ["PRESSURE ADVANCE: Defined filaments"] %} + {% for filament in pa_dic|sort(attribute='id') %} + {% set _dummy = out.append("%s" % filament.id) %} + {% for setup in filament.val|sort(attribute='nozzle') %} + {% set _dummy = out.append("Nozzle: %1.02f | Pressure Advance: %1.03f | Smooth Time: %1.03f" % + (setup.nozzle, setup.pa, setup.st)) %} + {% endfor %} + {% endfor %} + {action_respond_info(out|join("\n"))} + {% endif %} + +[gcode_macro PRESSURE_ADVANCE_ADD] +description: Add or change pressure advance settings +gcode: + {% if 'FILAMENT' not in params|upper %} + {action_respond_info("PRESSURE ADVANCE: FILAMENT must be defined use \"PRESSURE_ADVANCE_ADD FILAMENT=id\" as a minimum")} + {% else %} + {% set cfg = printer.configfile.settings.extruder %} + {% set id = params.FILAMENT|string %} + {% set nozzle = params.NOZZLE|default(0.40)|float|round(2) %} + {% if not printer.save_variables.variables.pressure_advance %} # add first entry + {action_respond_info("PRESSURE ADVANCE: Initialize with Filament %s" % (id))} + {% set pa_dic = [{'id' : id, + 'val': [{'nozzle': nozzle, + 'pa' : params.PRESSURE_ADVANCE|default(cfg.pressure_advance)|float|round(3), + 'st' : params.SMOOTH_TIME|default(cfg.pressure_advance_smooth_time)|float|round(3)}]}] %} + {% else %} + {% set pa_dic = printer.save_variables.variables.pressure_advance %} + {% for filament in pa_dic %} + {% if id == filament.id %} + {% set id_index = loop.index0 %} + {% for setup in filament.val %} + {% if nozzle == setup.nozzle %} # change value of an existing nozzle st an existing filament + {% set change_txt = [] %} + {% if 'PRESSURE_ADVANCE' in params|upper %} + {% set _dummy = change_txt.append("PRESSURE ADVANCE") %} + {% set _dummy = pa_dic[id_index].val[loop.index0].update({'pa': params.PRESSURE_ADVANCE|float|round(3)}) %} + {% endif %} + {% if 'SMOOTH_TIME' in params|upper %} + {% set _dummy = change_txt.append("SMOOTH TIME") %} + {% set _dummy = pa_dic[id_index].val[loop.index0].update({'st': params.SMOOTH_TIME|float|round(3)}) %} + {% endif %} + {% if change_txt|length > 0 %} + {action_respond_info("PRESSURE ADVANCE: Changed %s at Filament %s Nozzle %s" % (change_txt|join(" and "),id,nozzle))} + {% else %} + {action_respond_info("PRESSURE ADVANCE: Nothing changed at Filament %s Nozzle %s" % (id,nozzle))} + {% endif %} + {% elif loop.last %} # add a new nozzle to an existing filament + {action_respond_info("PRESSURE ADVANCE: Add setup for Nozzle %s at Filament %s" % (nozzle,id))} + {% set _dummy = pa_dic[id_index].val.append({'nozzle': nozzle, + 'pa' : params.PRESSURE_ADVANCE|default(cfg.pressure_advance)|float|round(3), + 'st' : params.SMOOTH_TIME|default(cfg.pressure_advance_smooth_time)|float|round(3)}) %} + {% endif%} + {% endfor %} + {% elif loop.last %} # add a new filament + {action_respond_info("PRESSURE ADVANCE: Add setup for Filament %s" % (id))} + {% set _dummy = pa_dic.append({'id' : id, + 'val': [{'nozzle': nozzle, + 'pa' : params.PRESSURE_ADVANCE|default(cfg.pressure_advance)|float|round(3), + 'st' : params.SMOOTH_TIME|default(cfg.pressure_advance_smooth_time)|float|round(3)}]}) %} + {% endif %} + {% endfor %} + {% endif %} + SAVE_VARIABLE VARIABLE=pressure_advance VALUE="{pa_dic}" + {% endif %} + +[gcode_macro PRESSURE_ADVANCE_REMOVE] +description: Remove a filament or a nezzle setup +gcode: + {% if 'FILAMENT' not in params|upper %} + {action_respond_info("PRESSURE ADVANCE: FILAMENT must be defined use \"PRESSURE_ADVANCE_REMOVE FILAMENT=id\" as a minimum")} + {% else %} + {% if not printer.save_variables.variables.pressure_advance %} # nothing setup'ed yet + {action_respond_info("PRESSURE ADVANCE: Nothing to remove, no save_variable defined yet")} + {% else %} + {% set id = params.FILAMENT|string %} + {% set pa_dic = printer.save_variables.variables.pressure_advance %} + {% for filament in pa_dic %} + {% if id == filament.id %} + {% if 'NOZZLE' in params|upper %} + {% set nozzle = params.NOZZLE|float|round(2) %} + {% set id_index = loop.index0 %} + {% for setup in filament.val %} + {% if nozzle == setup.nozzle %} # remove nozzle + {action_respond_info("PRESSURE ADVANCE: Remove Nozzle %s at Filament %s" % (nozzle,id))} + {% set _dummy = pa_dic[id_index].val.pop(loop.index0) %} + {% elif loop.last %} # nozzle not found + {action_respond_info("PRESSURE ADVANCE: Nothing to remove, Nozzle %s at Filament %s not defined" % (nozzle,id))} + {% endif%} + {% endfor %} + {% else %} # remove filament + {action_respond_info("PRESSURE ADVANCE: Remove Filament %s" % id)} + {% set _dummy = pa_dic.pop(loop.index0) %} + {% endif %} + {% elif loop.last %} # filament not found + {action_respond_info("PRESSURE ADVANCE: Nothing to remove, Filament %s not defined" % id)} + {% endif %} + {% endfor %} + {% endif %} + SAVE_VARIABLE VARIABLE=pressure_advance VALUE="{pa_dic}" + {% endif %} + +[gcode_macro PRESSURE_ADVANCE_SELECT] +description: Set PA depending on nozzle and filament +gcode: + {% if not printer.save_variables.variables.pressure_advance %} + {action_respond_info("PRESSURE ADVANCE: No filament defined ABORDED")} + {% else %} + {% set nozzle = params.NOZZLE|default(0.4)|float %} + {% set id = params.FILAMENT|default('None')|string %} + {% set pa_dic = printer.save_variables.variables.pressure_advance %} + {% set found = {'id' : 'default', + 'nozzle': 0.4, + 'pa' : printer.configfile.settings.extruder.pressure_advance, + 'st' : printer.configfile.settings.extruder.pressure_advance_smooth_time} %} + {% for filament in pa_dic %} + {% if id == filament.id %} + {% for setup in filament.val %} + {% if nozzle == setup.nozzle %} + {% set _dummy = found.update({'id': filament.id}) %} + {% set _dummy = found.update({'nozzle': setup.nozzle}) %} + {% set _dummy = found.update({'pa': setup.pa}) %} + {% set _dummy = found.update({'st': setup.st}) %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + SET_PRESSURE_ADVANCE ADVANCE={found.pa} SMOOTH_TIME={found.st} + {action_respond_info("PRESSURE ADVANCE: + Filament: %s Nozzle: %1.02f + Pressure Advance: %1.03f Smooth Time: %1.03f" % (found.id, found.nozzle, found.pa, found.st))} + {% endif %} diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg new file mode 100644 index 000000000..086b5586e --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg @@ -0,0 +1,465 @@ +##===================== SKR 1.4 Pin Definitions =================== +# +--------------+------+------+------+------+------+ +----+------+------+------+ +# | | X | Y | Z | E0 | E1 | | | 0 | 1 | BED | +# +--------------+------+------+------+------+------+ +----+------+------+------+ +# | STEP | 2.2 | 0.19 | 0.22 | 2.13 | 1.15 | | HE | 2.7 | 2.4 | 2.5 | +# +--------------+------+------+------+------+------+ +----+------+------+------+ +# | DIR | 2.6 | 0.20 | 2.11 | 0.11 | 1.14 | | TH | 0.24 | 0.23 | 0.25 | +# +--------------+------+------+------+------+------+ +----+------+------+------+ +# | ENABLE | 2.1 | 2.8 | 0.21 | 2.12 | 1.16 | +# +--------------+------+------+------+------+------+ +------+-------+-------+---------+ +# | DIAG/ENDSTOP | 1.29 | 1.28 | 1.27 | 1.26 | 1.25 | | FAN0 | SERVO | PROBE | PWR_DET | +# +--------------+------+------+------+------+------+ +------+-------+-------+---------+ +# | UART | 1.10 | 1.9 | 1.8 | 1.4 | 1.1 | | 2.3 | 2.0 | 0.10 | 1.0 | +# +--------------+------+------+------+------+------+ +------+-------+-------+---------+ + +# MCU definition +## MCU for X/Y/E steppers main MCU +## [X in X] - B Motor +## [Y in Y] - A Motor +## [E in E0] - Extruder +[mcu] +serial: /dev/serial/by-id/usb-Klipper_lpc1769_1840010F871C4AAF863E7C5DC32000F5-if00 +restart_method: command + +## MCU for Z steppers +## [Z in X] - Front Left +## [Z1 in Y] - Rear Left +## [Z2 in Z] - Rear Right +## [Z3 in E0] - Front Right +[mcu z] +serial: /dev/serial/by-id/usb-Klipper_lpc1769_07300110871C4AAFBF427C5DC72000F5-if00 +restart_method: command + +## MCU for adxl345 acelometer +[mcu rpi] +serial: /tmp/klipper_host_mcu + +# General Printer definition +[printer] +kinematics: corexy +max_velocity: 450 +max_accel: 7000 +max_accel_to_decel: 4000 +max_z_velocity: 30 +max_z_accel: 700 +square_corner_velocity: 5.0 + +# Stepper Settings +[include stepper.cfg] +[include tmc.cfg] + +# Extruder & Bed; Heater Verification (default values) +[include heater.cfg] +#[include heater_verify.cfg] + +# Probe and Gantry Adjustment Routines +[include probe_qgl.cfg] + +# Fan Control & Extra Thermistor +[include fan.cfg] + +# Caselight Control +[include caselight.cfg] + +# Homing Routines +[include homing.cfg] + +# Bed Mesh +[include bed_mesh.cfg] + +# Resonance compensation +[include input_shaper.cfg] + +# Display & Custom Menu +[include lcd.cfg] + +# Macros +[include basic_macro.cfg] +[include macro.cfg] +[include park_macro.cfg] +[include debug_macro.cfg] + +# moonraker/mainsail +[include webclient.cfg] + +# Power relays +[include power.cfg] + +# print and service time storage +[include printtime.cfg] + +# probe accuracy test +#[include test_probe_accuracy.cfg] + +# flexplate select menu +[include flexplate.cfg] + +# filament and pressure advance +[include filament.cfg] +[include pressure_advance.cfg] + +# filament runout sensor +[include runout.cfg] + +# force move used only if gantry is at z max +[include force_move.cfg] + +# MagProbe instead of Sensor +[include magprobe.cfg] + +# Z_calibration needs +[include z_calibration.cfg] + +# timelaps needs +[include timelapse.cfg] + +# Enable Execute Object (beta) use https://github.com/troy-jacobson/klipper/tree/exclude-object-pr +[exclude_object] + +# File location of stored varibales +[save_variables] +filename: /home/pi/klipper_config/.variables.stb + +# Virtual SD Card +[virtual_sdcard] +path: /home/pi/sdcard + +# macro that run at klipper start +[delayed_gcode _INIT] +initial_duration: 1 +gcode: + _USER_VARIABLE + _CHECK_CONSITENT + _EXECUTE_AT_INIT + +[gcode_macro _EXECUTE_AT_INIT] +description: Helper: Everything that should run at klipper start +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% if 'gcode_macro _MENU_LIMITS' is in printer %} _MENU_LIMITS INDEX=4 {% endif %} + {% if printer.save_variables.variables.filament_sensor %} _RESTORE_FILAMENT_SENSOR {% endif %} + {% if user.hw.filter.ena %} _CHECK_FILTER {% endif %} + {% if user.hw.relay.ena %} _HEATER_ON {% endif %} + {% if user.hw.display.ena %} UPDATE_DELAYED_GCODE ID=_DISPLAY_INIT DURATION=2 {% endif %} + _PRINT_AR T="Klipper INIT done" + +[gcode_macro _CHECK_CONSITENT] +description: Helper: Check that some criterias are meet in the printer.cfg +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set text = ["CONFIG: ERROR"] %} + {% if user.run is not defined %} + {% set _dummy = text.append("_USER_VARIABLE macro missing") %} + {% elif not user.run %} + {% set _dummy = text.append("_USER_VARIABLE macro not executed") %} + {% endif %} + {% if user.hw.auto_z_offset.auto and not user.hw.mag_probe.ena %} + {% set _dummy = text.append("[z_calibration] defined but no MagProbe\n") %} + {% endif %} + {% if 'save_variables' not in printer %} + {% set _dummy = text.append("[save_variables] missing") %} + {% endif %} + {% if 'virtual_sdcard' not in printer %} + {% set _dummy = text.append("[virtual_sdcard] missing") %} + {% endif %} + {% if text|length > 1 %} + {action_respond_info(text|join("\n"))} + {% endif %} + +[gcode_macro _USER_VARIABLE] +description: Helper: Contains User defined printer variables +##### see the readme for the variable definition ##### +variable_hw: {} +variable_homing: {} +variable_z_hop: 0 +variable_speed: {} +variable_probe: {} +variable_park: {} +variable_filament: {} +variable_purge: {} +variable_print_start: {} +variable_unload_sd: False +variable_prime: {} +variable_respond: {} +variable_peripheral: {} +variable_run: False +gcode: + ################################################################### + ## start of user defines ## + ## this needs to be changed for your printer ## + ################################################################### + #{% set user_z_endstop_xy = [232.0,355.0] %} ; z Endstop position insight right profil + {% set user_z_endstop_xy = [123.0,355.0] %} ; z Endstop position insight left profil + {% set user_z_endstop_hop = 7.5 %} ; z hop for moves e.g homimg + {% set user_z_home_current = 0.3 %} ; reduced homing curent for z + {% set user_home_accel = 1200 %} ; reduced ACCEL for homing + {% set user_bed_y_offset = 5 %} ; Endstop offset to bed max y + ##### all user defined speeds [mm/sec] ##### + {% set user_z_hop_speed = 15 %} ; default z_hop speed + {% set user_retract_speed = 30 %} ; default retract/extrude speed + {% set user_travel_speed = 300 %} ; travel speed e.g park, dock ... + {% set user_probe_dock_speed = 50 %} ; dock speed for attach/dock + {% set user_filament_load_speed = 50 %} ; load/unload speed + {% set user_wipe_speed = 60 %} ; wipe move speed + {% set user_prime_speed = 25 %} ; prime line speed + ##### Mag Probe ##### + {% set user_probe_dock_pos = [0,355] %} ; position of the dock + {% set user_probe_delta_x = 30 %} ; x offset for position before dock + {% set user_probe_delta_y = -30 %} ; y offset to move probe out of dock + {% set user_z_probe_hop = 15.5 %} ; z minimum heigh to avoid crash + ##### Park Position ##### + {% set user_park_xy_delta = 25 %} ; distance for x or y from the edge + {% set user_park_z_max_delta = 40 %} ; insure to do not hit cam in front + {% set user_park_z_min = 30 %} ; minimal z from bed + {% set user_park_pause_z_delta = 2.0 %} ; distance to increase head while PAUSE/CANCEL_PRINT + {% set user_park_at_cancel = False %} ; park head at CANCEL_PRINT if not paused [False/True] + ##### Filament ##### + {% set user_extruder_min_add = 30 %} ; Temperature add to min Extruder temp + {% set user_load_distance = 90 %} ; load distance while load filament + {% set user_load_extrude = 50 %} ; extrude distance while load filament + {% set user_unload_distance = 75 %} ; unload distance while unload filament + {% set user_retract_end = 2 %} ; retract distance at PRINT_END or CANCEL_PRINT + {% set user_retract_pause = 1 %} ; retract/extrude distance while PAUSE or RESUME + ##### Purge & Brush ##### + {% set user_brush_pos = 'right' %} ; left/right profile used + #{% set user_brush_x_middle = 100 %} ; mid point of brush at left profile + {% set user_brush_x_middle = 250 %} ; mid point of brush at right profil + {% set user_brush_x_width = 40 %} ; width of brush + {% set user_brush_y_start = 351 %} ; start point at y + {% set user_wipe_z = 1.0 %} ; z for wipe moves + {% set user_wipe_cnt = 5 %} ; number of full wipes + {% set user_z_purge = 2.5 %} ; z above purge bucket + ##### PRINT_START/STOP ##### + {% set user_print_start_bed_up = 10 %} ; bed temp raise for faster heat soak + {% set user_print_start_ival = 1 %} ; wait time per call in sec + {% set user_print_start_extruder_time = 3 %} ; time in minutes before soak end to start extruder heating + {% set user_print_start_bed_time = 3 %} ; time in minutes before soak end to set bed target temp + {% set user_print_start_prime_mult = 2 %} ; multiplier for prime line hight + {% set user_unload_sd = True %} ; unload sd file at PRINT_END or CANCEL_PRINT [True,False] + ##### Prime Line ##### + {% set user_prime_start_xy = [5.0,30.0] %} ; x&y start coordinates of prime line + {% set user_prime_z = 0.34 %} ; default prime layer hight + {% set user_prime_dir = 'Y+' %} ; direction of prime line (X+, X-, Y+, Y-) + {% set user_prime_spacing = 0.4 %} ; distance between line, move will allways positive + {% set user_prime_lenght = 220 %} ; length of prime line + {% set user_prime_seg = 11 %} ; segments in that the prime line is splitted + {% set user_prime_extrude_per_seg = 2 %} ; amount of filament extruded per segment + ##### Respond defaults ##### + # Default behaivior for output messages of the macro 0: no output 1: console output + {% set user_respond_set_z_current = 0 %} ; Macro: _SET_Z_CURRENT + {% set user_respond_set_acc = 0 %} ; Macro: _SET_ACC + {% set user_respond_probe_action = 1 %} ; Macro: _PROBE_ACTION + {% set user_respond_layer = 0 %} ; Macro: _LAYER + ##### Peripheral ##### + {% set user_filter_on = 0.5 %} ; filter on value + {% set user_filter_use_time = 80 %} ; Nevermore change warning limit + {% set user_vent_on = 15 %} ; chamber fan on temperature + {% set user_caselight_on = 0.4 %} ; caselight on value + {% set user_fan_run_after_print = 30 %} ; time in min to run filter and chamber exhaust after print finsih + ################################################################### + ## end of user defines ## + ################################################################### + # get printer limits & cfg value + {% set min = printer.toolhead.axis_minimum %} + {% set max = printer.toolhead.axis_maximum %} + {% set cfg_endstop_z_offset = printer.configfile.settings.stepper_z.position_endstop|default(0.0)|float %} + # detect additional hardware + {% set hw_dic = {'display' : {'ena' : True if 'neopixel neo_display' in printer.configfile.settings + else False}, + 'chamber' : {'type': 'sensor' if 'temperature_sensor chamber' in printer.configfile.settings + else 'fan' if 'temperature_fan chamber' in printer.configfile.settings + else 'none'}, + 'caselight' : {'ena' : True if 'output_pin caselight' in printer.configfile.settings + else False}, + 'filter' : {'ena' : True if 'fan_generic filter' in printer.configfile.settings + else False}, + 'runout' : {'type': 'switch' if 'filament_switch_sensor runout' in printer.configfile.settings + else 'motion' if 'filament_motion_sensor runout' in printer.configfile.settings + else 'file' if 'save_variables' in printer and filament_loaded in printer.save_variables.variables + else 'none'}, + 'relay' : {'ena' : True if 'output_pin extruder_relay' in printer.configfile.settings and + 'output_pin heater_bed_relay' in printer.configfile.settings + else False}, + 'auto_z_offset' : {'type': 'z_calib+flexplate' if 'z_calibration' in printer and 'save_variables' in printer and 'plates' in printer.save_variables.variables + else 'z_calib' if 'z_calibration' in printer + else 'flexplate' if 'save_variables' in printer and 'plates' in printer.save_variables.variables + else 'none'}, + 'mag_probe' : {'ena' : True if printer['gcode_macro _MAG_PROBE'] is defined or 'dockable_probe' in printer + else False}, + 'endstop_temp' : {'ena' : True if 'temperature_sensor endstop' in printer.configfile.settings + else False}}%} + {% set _dummy = hw_dic.chamber.update({'ena': True if hw_dic.chamber.type != 'none' else False}) %} + {% set _dummy = hw_dic.chamber.update({'fan': True if hw_dic.chamber.type == 'fan' else False}) %} + {% set _dummy = hw_dic.runout.update({'ena': True if hw_dic.runout.type != 'none' else False}) %} + {% set _dummy = hw_dic.runout.update({'sensor': True if hw_dic.runout.type == 'switch' or hw_dic.runout.type == 'motion' + else False}) %} + {% set _dummy = hw_dic.auto_z_offset.update({'ena': True if hw_dic.auto_z_offset.type != 'none' else False}) %} + {% set _dummy = hw_dic.auto_z_offset.update({'auto': True if hw_dic.auto_z_offset.type == 'z_calib+flexplate' or + hw_dic.auto_z_offset.type == 'z_calib' + else False}) %} + {% set _dummy = hw_dic.auto_z_offset.update({'manu': True if hw_dic.auto_z_offset.type == 'z_calib+flexplate' or + hw_dic.auto_z_offset.type == 'flexplate' + else False}) %} + # calc needed values + {% set bed = {'min': {'x': min.x, 'y': min.y , 'z': 0 }, + 'max': {'x': max.x, 'y': max.y - user_bed_y_offset, 'z': max.z}} %} + {% set calc_center = {'x': (bed.max.x - bed.min.x) / 2, + 'y': (bed.max.y - bed.min.y) / 2, + 'z': (bed.max.z - bed.min.z) / 2} %} + {% set calc_park = {'min': {'x': bed.min.x + user_park_xy_delta, + 'y': bed.min.y + user_park_xy_delta, + 'z': bed.min.z + user_park_z_min}, + 'max': {'x': bed.max.x - user_park_xy_delta, + 'y': bed.max.y - user_park_xy_delta, + 'z': bed.max.z - user_park_z_max_delta}} %} + {% set calc_z_endstop_z = cfg_endstop_z_offset|round(0, 'ceil') + 1.0 if cfg_endstop_z_offset > 0 else 1.0 %} + {% set calc_z_hop = user_z_probe_hop if hw_dic.mag_probe.ena and user_z_probe_hop > user_z_endstop_hop + else user_z_endstop_hop %} + {% set calc_brush = {'start': user_brush_x_middle - user_brush_x_width / 2, + 'end' : user_brush_x_middle + user_brush_x_width / 2} %} + {% set calc_purge = {'x': (min.x + calc_brush.start) / 2 if user_brush_pos|lower == 'left' + else max.x - (max.x - calc_brush.end) / 2, + 'y': max.y} %} + {% set calc_wipe = {'start': {'x': calc_brush.start if user_brush_pos|lower == 'left' + else calc_brush.end, + 'y': user_brush_y_start}, + 'end' : {'x': calc_brush.end if user_brush_pos|lower == 'left' + else calc_brush.start, + 'y': max.y}} %} + # prepare dictonaries + {% set homing_dic = {'z_endstop': {'x':user_z_endstop_xy[0], 'y':user_z_endstop_xy[1], 'z':calc_z_endstop_z, 'hop':user_z_endstop_hop}, + 'z_current': user_z_home_current, + 'accel' : user_home_accel} %} + {% set purge_dic = {'purge' : {'x':calc_purge.x, 'y':calc_purge.y, 'z':user_z_purge}, + 'wipe' : {'start' : {'x': calc_wipe.start.x, 'y': calc_wipe.start.y, 'z':user_wipe_z}, + 'end' : {'x': calc_wipe.end.x, 'y': calc_wipe.end.y, 'z':user_wipe_z}, + 'offset' : (calc_wipe.end.y - calc_wipe.start.y) / user_wipe_cnt, + 'cnt' : user_wipe_cnt}} %} + {% set probe_dic = {'dock' : {'x' : user_probe_dock_pos[0], + 'y' : user_probe_dock_pos[1] + user_probe_delta_y}, + 'store' : {'x' : user_probe_dock_pos[0] + user_probe_delta_x, + 'y' : user_probe_dock_pos[1]}} %} + {% set speed_dic = {'z_hop' : (user_z_hop_speed * 60), + 'retract' : (user_retract_speed * 60), + 'travel' : (user_travel_speed * 60), + 'dock' : (user_probe_dock_speed * 60), + 'load' : (user_filament_load_speed * 60), + 'wipe' : (user_wipe_speed * 60), + 'prime' : (user_prime_speed * 60)} %} + {% set park_dic = {'bed' : {'x': calc_center.x, 'y': calc_center.y, 'z': calc_park.min.z}, + 'center' : {'x': calc_center.x, 'y': calc_center.y, 'z': calc_center.z}, + 'front' : {'x': calc_center.x, 'y': calc_park.min.y, 'z': calc_park.max.z}, + 'frontlow' : {'x': calc_center.x, 'y': calc_park.min.y, 'z': calc_park.min.z}, + 'rear' : {'x': calc_park.min.x, 'y': calc_park.max.y, 'z': calc_park.max.z}, + 'pause' : {'x': calc_purge.x, 'y': calc_purge.y, 'dz': user_park_pause_z_delta}, + 'park_at_cancel': user_park_at_cancel} %} + {% set filament_dic = {'load_distance' : user_load_distance, + 'load_extrude' : user_load_extrude, + 'unload_distance' : user_unload_distance, + 'retract' : {'end' : user_retract_end, + 'pause' : user_retract_pause, + 'cancel': user_retract_end - user_retract_pause}} %} + {% set prime_dic = {'pos' : {'x':user_prime_start_xy[0], 'y':user_prime_start_xy[1], 'z':user_prime_z}, + 'dir' : user_prime_dir, + 'spacing' : user_prime_spacing, + 'length_per_seg' : user_prime_lenght / user_prime_seg, + 'seg' : user_prime_seg, + 'extrude_per_seg' : user_prime_extrude_per_seg} %} + {% set print_start_dic = {'bed_up' : user_print_start_bed_up|float|round(1), + 'ival' : user_print_start_ival|int, + 'time' : {'extruder' : (user_print_start_extruder_time * 60)|int, + 'bed' : (user_print_start_bed_time * 60)|int}, + 'prime_mult' : user_print_start_prime_mult|float} %} + {% set respond_dic = {'z_current' : user_respond_set_z_current, + 'acc' : user_respond_set_acc, + 'probe_action' : user_respond_probe_action, + 'layer' : user_respond_layer} %} + {% set peripheral_dic = {'filter' : {'on_val' : user_filter_on, + 'warning' : user_filter_use_time, + 'run_after_print' : (user_fan_run_after_print * 60)}, + 'vent' : {'on_val' : user_vent_on, + 'run_after_print' : ((user_fan_run_after_print * 60) + 5)}, + 'caselight' : {'on_val' : user_caselight_on}} %} + # store results in variable + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=hw VALUE="{hw_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=homing VALUE="{homing_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=z_hop VALUE={calc_z_hop} + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=speed VALUE="{speed_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=probe VALUE="{probe_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=park VALUE="{park_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=filament VALUE="{filament_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=purge VALUE="{purge_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=print_start VALUE="{print_start_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=unload_sd VALUE={user_unload_sd} + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=prime VALUE="{prime_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=respond VALUE="{respond_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=peripheral VALUE="{peripheral_dic}" + SET_GCODE_VARIABLE MACRO=_USER_VARIABLE VARIABLE=run VALUE=True + +#*# <---------------------- SAVE_CONFIG ----------------------> +#*# DO NOT EDIT THIS BLOCK OR BELOW. The contents are auto-generated. +#*# +#*# [extruder] +#*# control = pid +#*# pid_kp = 23.886 +#*# pid_ki = 1.254 +#*# pid_kd = 113.757 +#*# +#*# [heater_bed] +#*# control = pid +#*# pid_kp = 42.778 +#*# pid_ki = 1.501 +#*# pid_kd = 304.788 +#*# +#*# [stepper_z] +#*# position_endstop = 2.177 +#*# +#*# [probe] +#*# z_offset = 0 +#*# +#*# [bed_mesh En_Thick-Bed_Temp-0C] +#*# version = 1 +#*# points = +#*# -0.055625, -0.001562, 0.030000, 0.019375, 0.009063, 0.029375, 0.026875, 0.062500, 0.096875 +#*# -0.040625, 0.008125, 0.039375, 0.035313, 0.021250, 0.048125, 0.048750, 0.079375, 0.122813 +#*# -0.043437, -0.005625, 0.017500, 0.014063, 0.004063, 0.023438, 0.040938, 0.070313, 0.101250 +#*# -0.036250, -0.004062, 0.016563, 0.014688, 0.007188, 0.025625, 0.032813, 0.065000, 0.093750 +#*# -0.025312, -0.003750, 0.013438, 0.008438, 0.000000, 0.017500, 0.029375, 0.065000, 0.090312 +#*# -0.005313, 0.007812, 0.026250, 0.021875, 0.011875, 0.029375, 0.035625, 0.069062, 0.090000 +#*# 0.001562, 0.014375, 0.028125, 0.013125, 0.003750, 0.018125, 0.024687, 0.050000, 0.073125 +#*# 0.020625, 0.029375, 0.033125, 0.014062, 0.007187, 0.027187, 0.028125, 0.049375, 0.056250 +#*# 0.050937, 0.044375, 0.040000, 0.021875, 0.011875, 0.030937, 0.037812, 0.047500, 0.050625 +#*# tension = 0.2 +#*# min_x = 30.0 +#*# algo = bicubic +#*# y_count = 9 +#*# mesh_y_pps = 2 +#*# min_y = 30.0 +#*# x_count = 9 +#*# max_y = 320.0 +#*# mesh_x_pps = 2 +#*# max_x = 320.0 +#*# +#*# [bed_mesh Mueller-Bed_Temp-0C] +#*# version = 1 +#*# points = +#*# -0.015000, 0.021875, 0.030000, 0.021250, 0.016875, 0.028125, 0.031250, 0.030625, 0.032500 +#*# -0.017500, 0.021875, 0.036250, 0.031875, 0.026250, 0.046875, 0.048750, 0.034375, 0.045625 +#*# -0.016875, 0.011875, 0.015000, 0.003750, 0.006250, 0.025625, 0.030625, 0.026250, 0.022500 +#*# -0.008750, 0.018125, 0.029375, 0.005000, 0.010625, 0.021250, 0.030625, 0.030625, 0.026875 +#*# -0.003125, 0.005000, 0.013125, 0.000000, 0.000000, 0.015000, 0.028750, 0.036875, 0.032500 +#*# -0.001875, 0.008750, 0.015000, 0.001875, 0.005625, 0.018125, 0.030000, 0.031250, 0.037500 +#*# 0.003750, 0.016875, 0.028750, 0.006875, 0.006250, 0.026250, 0.030000, 0.035000, 0.028750 +#*# 0.023125, 0.036250, 0.036250, 0.013125, 0.018750, 0.032500, 0.041875, 0.036875, 0.034375 +#*# 0.062500, 0.062500, 0.061875, 0.031875, 0.031875, 0.054375, 0.070625, 0.061250, 0.044375 +#*# x_count = 9 +#*# y_count = 9 +#*# mesh_x_pps = 2 +#*# mesh_y_pps = 2 +#*# algo = bicubic +#*# tension = 0.2 +#*# min_x = 30.0 +#*# max_x = 320.0 +#*# min_y = 30.0 +#*# max_y = 320.0 diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg new file mode 100644 index 000000000..19599b2b2 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg @@ -0,0 +1,167 @@ +##################################################################### +# Macro +##################################################################### +## This macro stores the variables +## must be added to PRINT_END - CANCEL_PRINT Macro +## works only with the use of virtual sd card! +[gcode_macro _ADD_PRINT_TIME] +description: Helper: Store print time values in variables +gcode: + {% set time = printer.print_stats.total_duration %} + {% set filament = printer.print_stats.filament_used|float %} + {% set filtertime = time if printer['gcode_macro PRINT_START'].var.filter else 0 %} + # update saved dictornary or initiate if not exist + {% if not printer.save_variables.variables.print_stats %} + {% set print_stats = {'time': {'total': time, 'service': time, 'filter': filtertime}, 'filament': filament}%} + {% else %} + {% set print_stats = printer.save_variables.variables.print_stats %} + {% set _dummy = print_stats.time.update({'total':(print_stats.time.total + time)|int}) %} + {% set _dummy = print_stats.time.update({'service':(print_stats.time.service + time)|int}) %} + {% set _dummy = print_stats.time.update({'filter':(print_stats.time.filter + filtertime)|int}) %} + {% set _dummy = print_stats.update({'filament':(print_stats.filament + filament)|float}) %} + {% endif %} + SAVE_VARIABLE VARIABLE=print_stats VALUE="{print_stats}" + +[gcode_macro _DISPLAY_PRINT_TIME] +description: Helper: Print actual stored print time +gcode: + {% set totaltime = params.SECONDS|int if 'SECONDS' in params|upper + else printer.save_variables.variables.print_stats.time.total %} + {% set prefix = params.PREFIX|default('Total') %} + {% set h,m,s = (totaltime / 3600)|int, ((totaltime / 60) % 60)|int, (totaltime % 60)|int %} + {action_respond_info("Print time %s %d:%02d:%02d" % (prefix,h,m,s))} + M117 {prefix} {h}:{'%02d' % m}:{'%02d' % s} + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=10 + +## used at PRINT_END and CANCEL_PRINT +[gcode_macro _SD_PRINT_STATS] +description: Helper: Print statistic of last print +gcode: + {% set PT = printer.print_stats.print_duration %} + {% set Ph,Pm,Ps = (PT / 3600)|int, ((PT / 60) % 60)|int, (PT % 60)|int %} + {% set TT = printer.print_stats.total_duration %} + {% set Th,Tm,Ts = (TT / 3600)|int, ((TT / 60) % 60)|int, (TT % 60)|int %} + {% set Fil = printer.print_stats.filament_used|float / 1000.0 %} + {action_respond_info("Statistic of last Print (%s): + Name: %s + Filament: %.4fm + Print Time: %d:%02d:%02d + Total Time: %d:%02d:%02d" % + (params.R, printer.print_stats.filename, Fil, Ph, Pm, Ps, Th, Tm, Ts))} + + ## used at PRINT_END and CANCEL_PRINT +[gcode_macro _SD_PRINTER_STATS] +description: Helper: Print statistic of printer +gcode: + {% set ST = printer.save_variables.variables.print_stats.time.service %} + {% set Sh,Sm,Ss = (ST / 3600)|int, ((ST / 60) % 60)|int, (ST % 60)|int %} + {% set TT = printer.save_variables.variables.print_stats.time.total %} + {% set Th,Tm,Ts = (TT / 3600)|int, ((TT / 60) % 60)|int, (TT % 60)|int %} + {% set FT = printer.save_variables.variables.print_stats.time.filter %} + {% set Fh,Fm,Fs = (FT / 3600)|int, ((FT / 60) % 60)|int, (FT % 60)|int %} + {% set Fil = printer.save_variables.variables.print_stats.filament|float / 1000.0 %} + {action_respond_info("Printer Statistics: + Total Print Time: %d:%02d:%02d + Total Filament used: %.4fm + Filter use time: %d:%02d:%02d + Time since last Service: %d:%02d:%02d" % + (Th, Tm, Ts, Fil, Fh, Fm, Fs, Sh, Sm, Ss))} + _CHECK_FILTER + +[gcode_macro _CHECK_FILTER] +description: Helper: Print filter exchange warning +gcode: + {% if printer['gcode_macro _USER_VARIABLE'].hw.filter.ena and + printer.save_variables.variables.print_stats %} + {% set Fh = (printer.save_variables.variables.print_stats.time.filter / 3600)|int %} + {% if Fh >= printer['gcode_macro _USER_VARIABLE'].peripheral.filter.warning %} + M117 Change Filter! + {action_respond_info("Change Filter material at Micro!")} + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=10 + {% endif %} + {% endif %} + +[gcode_macro RST_FILTER] +description: Reset Nevermore interval time +gcode: + {% if printer.save_variables.variables.print_stats %} + {% set print_stats = printer.save_variables.variables.print_stats %} + {% set _dummy = print_stats.time.update({'filter': 0}) %} + SAVE_VARIABLE VARIABLE=print_stats VALUE="{print_stats}" + {action_respond_info("Flter used time reseted to zero")} + {% endif %} + +[gcode_macro RST_SERVICE] +description: Reset Service interval time +gcode: + {% if printer.save_variables.variables.print_stats %} + {% set print_stats = printer.save_variables.variables.print_stats %} + {% set _dummy = print_stats.time.update({'service': 0}) %} + SAVE_VARIABLE VARIABLE=print_stats VALUE="{print_stats}" + {action_respond_info("Time since last service reseted to zero")} + {% endif %} + +# Display Menu +# !!! Caution: I use my own menu root __voron_main !!! +# If you use a stock menu un comment this here +#[menu __main __statistic] +#type: list +#enable: {'print_stats' in printer.save_variables.variables} +#name: Satistic + +#[menu __main __statistic __totaltime] +#type: command + +#name: Time of Operation +#gcode: +# {menu.exit()} +# _DISPLAY_PRINT_TIME PREFIX=Total SECONDS={printer.save_variables.variables.print_stats.time.total} +# UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + +#[menu __main __statistic __filament] +#type: command + +#name: Total Filament used +#gcode: +# {menu.exit()} +# M117 Filerment {'%.4f' % (printer.save_variables.variables.print_stats.filament|float / 1000.0)}m +# {action_respond_info("Total Filament printed: %.4fm" % (printer.save_variables.variables.print_stats.filament|float / 1000.0))} +# UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=10 +# UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + +#[menu __main __statistic __filtertime] +#type: command + +#name: Time since Filter change +#gcode: +# {menu.exit()} +# _DISPLAY_PRINT_TIME PREFIX=Filter SECONDS={printer.save_variables.variables.print_stats.time.filter} +# UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + +#[menu __main __statistic __servicetime] +#type: command + +#name: Time since Service +#gcode: +# {menu.exit()} +# _DISPLAY_PRINT_TIME PREFIX=Service SECONDS={printer.save_variables.variables.print_stats.time.service} +# UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + + +#[menu __main __statistic __rst_filter] +#type: command +#enable: {not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused")} +#name: Reset Filter time +#gcode: +# {menu.exit()} +# RST_FILTER +# UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 + +#[menu __main __statistic __rst_service] +#type: command +#enable: {not (printer.print_stats.state == "printing" or printer.print_stats.state == "paused")} +#name: Reset Service time +#gcode: +# {menu.exit()} +# RST_SERVICE +# UPDATE_DELAYED_GCODE ID=_DELAY_DISPLAY_OFF DURATION=10 \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg new file mode 100644 index 000000000..ac0435dc8 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg @@ -0,0 +1,121 @@ +##################################################################### +# Probe +##################################################################### +############### Different Probe Settings ############### +## Omron: +## speed: 10.0 +## lift_speed: 30.0 +## samples: 9 +## samples_result: median +## sample_retract_dist: 0.5 +## samples_tolerance: 0.006 +## samples_tolerance_retries: 10 +## y_offset: 25.00 +######################################################## +## Super Pinda: +## speed: 7.5 +## lift_speed: 30.0 +## samples: 6 +## samples_result: median +## sample_retract_dist: 0.8 +## samples_tolerance: 0.005 +## samples_tolerance_retries: 10 +## y_offset: 25.00 +######################################################## +## MagProbe Klicky +## speed: 7.5 +## lift_speed: 30.0 +## sample: 5 +## samples_result: median +## sample_retract_dist: 0.8 +## samples_tolerance: 0.005 +## samples_tolerance_retries: 10 +## y_offset: 19.75 +## z_offset: 6.42 ;not needed since a Endstop is used +############### Different Probe Settings ############## +[probe] +## Inductive Probe / Mag Probe +## This probe is not used for Z height +pin: ^z:P0.10 +x_offset: 0 +y_offset: 19.75 +#z_offset: 0 +speed: 7.5 +lift_speed: 30.0 +samples: 5 +samples_result: median +sample_retract_dist: 0.8 +samples_tolerance: 0.005 +samples_tolerance_retries: 10 + +##################################################################### +# Disable Heater while probing +##################################################################### +#[homing_heaters] +#steppers: stepper_z, stepper_z1, stepper_z2, stepper_z3 +#heaters: extruder + +##################################################################### +# Gantry Adjustment Routines +##################################################################### +[quad_gantry_level] +## Min & Max gantry corners - measure from nozzle to respective belt positions +gantry_corners: + -56,-1 + 406,420 +## Probe points; this are nozzel positions we need to substract the probe offset +points: + 100,50 + 100,250 + 250,250 + 250,50 +speed: 200 +horizontal_move_z: 20 ; MagProbe 20, Vinda or Omron 5 +retries: 10 +retry_tolerance: 0.005 +max_adjust: 15 + +##################################################################### +# Macros +##################################################################### +[gcode_macro QUAD_GANTRY_LEVEL] +description: Conform a moving, twistable gantry to the shape of a stationary bed +rename_existing: QUAD_GANTRY_LEVEL_BASE +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set move_z = [user.z_hop, printer.toolhead.position.z]|max %} ; calc movement high + _SET_Z_CURRENT VAL=HOME + {% if "xyz" not in printer.toolhead.homed_axes %} G28 {% endif %} + {% if user.hw.mag_probe.ena %} + G90 + G0 Z{move_z} F{user.speed.z_hop} ; move head up to insure Probe is not triggered in error case + ATTACH_PROBE + {% endif %} + QUAD_GANTRY_LEVEL_BASE {rawparams} + {% if user.hw.mag_probe.ena %} DETACH_PROBE {% endif %} + {% if params.HOME|default('true')|lower == 'true' %} G28 Z {% endif %} + _SET_Z_CURRENT + {% if params.PARK|default('true')|lower == 'true' %} + G90 + G0 X{user.park.bed.x} Y{user.park.bed.y} Z{user.park.bed.z} F{user.speed.travel} + {% endif %} + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + +[gcode_macro CHECK_QGL] +description: Run after QUAD_GANTRY_LEVEL to insure it passes +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set probe_state = printer['gcode_macro _MAG_PROBE'].state|default('unknown')|lower %} ; get probe state + {% set probe_ok = False if user.hw.mag_probe.ena and (probe_state == 'error' or probe_state == 'unknown') + else True %} + {% if not printer.quad_gantry_level.applied or not probe_ok %} ; check QGL and probe status + {action_respond_info("QGL CHECK: Fail therefore cancel the print")} + PAUSE_BASE + G90 + G0 Z{user.z_hop} F{user.speed.z_hop} ; move nozzle to z high first + {% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %} ; set back to relative + {% if user.hw.mag_probe.ena %} DETACH_PROBE {% endif %} + CANCEL_PRINT PARK=1 ERROR=1 + {% else %} + {action_respond_info("QGL CHECK: Pass")} + {% endif %} diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg new file mode 100644 index 000000000..b7c50dc1a --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg @@ -0,0 +1,94 @@ +#[filament_switch_sensor runout] +## When set to True, a PAUSE will execute immediately after a runout +## is detected. Note that if pause_on_runout is False and the +## runout_gcode is omitted then runout detection is disabled. Default +## is True. +#pause_on_runout: FALSE +#runout_gcode: +# {action_respond_info("RUNOUT: Filament runout")} +# PAUSE +#insert_gcode: {action_respond_info("RUNOUT: Filament inserted")} +## The minimum amount of time in seconds to delay between events. +## Events triggered during this time period will be silently +## ignored. The default is 3 seconds. +##event_delay: 3.0 +## The amount of time to delay, in seconds, between the pause command +## dispatch and execution of the runout_gcode. It may be useful to +## increase this delay if OctoPrint exhibits strange pause behavior. +## Default is 0.5 seconds. +##pause_delay: 0.5 +## XYE mcu E0DET +#switch_pin: ^!P1.26 + +[filament_motion_sensor runout] +# The minimum length of filament pulled through the sensor to trigger +# a state change on the switch_pin +# Default is 7 mm. +detection_length: 14.0 +extruder: extruder +pause_on_runout: FALSE +runout_gcode: + {action_respond_info("RUNOUT: Filament runout")} + PAUSE +insert_gcode: {action_respond_info("RUNOUT: Filament inserted")} +# The minimum amount of time in seconds to delay between events. +# Events triggered during this time period will be silently +# ignored. The default is 3 seconds. +#event_delay: 3.0 +# The amount of time to delay, in seconds, between the pause command +# dispatch and execution of the runout_gcode. It may be useful to +# increase this delay if OctoPrint exhibits strange pause behavior. +# Default is 0.5 seconds. +#pause_delay: 0.5 +## XYE mcu E0DET +switch_pin: ^!P1.26 + +[filament_switch_sensor toolhead_runout] +## When set to True, a PAUSE will execute immediately after a runout +## is detected. Note that if pause_on_runout is False and the +## runout_gcode is omitted then runout detection is disabled. Default +## is True. +pause_on_runout: FALSE +runout_gcode: {action_respond_info("RUNOUT: Toolhead Filament runout")} +# PAUSE +insert_gcode: {action_respond_info("RUNOUT: Toolhead Filament inserted")} +## The minimum amount of time in seconds to delay between events. +## Events triggered during this time period will be silently +## ignored. The default is 3 seconds. +##event_delay: 3.0 +## The amount of time to delay, in seconds, between the pause command +## dispatch and execution of the runout_gcode. It may be useful to +## increase this delay if OctoPrint exhibits strange pause behavior. +## Default is 0.5 seconds. +##pause_delay: 0.5 +## XYE mcu E1DET +switch_pin: ^!P1.25 + +##################################################################### +# Macro +##################################################################### +[gcode_macro SET_FILAMENT_SENSOR] +description: Sets the filament sensor on/off and save value to file +rename_existing: SET_FILAMENT_SENSOR_BASE +gcode: + {% if printer.save_variables.variables.filament_sensor is not defined %} + {% set filament_sensor = {params.SENSOR|string: params.ENABLE|int} %} + {% else %} + {% set filament_sensor = printer.save_variables.variables.filament_sensor %} + {% set _dummy = filament_sensor.update({params.SENSOR|string: params.ENABLE|int}) %} + {% endif %} + SET_FILAMENT_SENSOR_BASE SENSOR={params.SENSOR} ENABLE={params.ENABLE} + SAVE_VARIABLE VARIABLE=filament_sensor VALUE="{filament_sensor}" + +[gcode_macro _RESTORE_FILAMENT_SENSOR] +description: Restore the filament sensor on/off state at klipper start +gcode: + {% if printer.save_variables.variables.filament_sensor is defined %} + {% for sensor in printer.save_variables.variables.filament_sensor %} + SET_FILAMENT_SENSOR_BASE SENSOR={sensor} ENABLE={printer.save_variables.variables.filament_sensor[sensor]} + {% endfor %} + {% endif %} + +[gcode_macro M600] +description: Filament change +gcode: PAUSE Y=10 ; everything needed is defined there \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg new file mode 100644 index 000000000..e8e27ef0d --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg @@ -0,0 +1,86 @@ +# MCU - X -> B Stepper - Left +[stepper_x] +step_pin: P2.2 +# TMC2209 dir_pin: !P2.6 +dir_pin: P2.6 +enable_pin: !P2.1 +full_steps_per_rotation: 400 +microsteps: 32 +rotation_distance: 40 +endstop_pin: ^!P1.29 +position_endstop: 350 +position_max: 350 +homing_speed: 100 +homing_retract_dist: 2 +second_homing_speed: 5 + +# MCU - Y -> A Stepper - Right +[stepper_y] +step_pin: P0.19 +# TMC2209 dir_pin: P0.20 +dir_pin: !P0.20 +enable_pin: !P2.8 +full_steps_per_rotation: 400 +microsteps: 32 +rotation_distance: 40 +endstop_pin: ^!P1.28 +position_endstop: 355 +position_max: 355 +homing_speed: 100 +homing_retract_dist: 2 +second_homing_speed: 5 + +# Z MCU - X -> Z0 Stepper - Front Left +[stepper_z] +step_pin: z:P2.2 +# TMC2209 dir_pin: !z:P2.6 +dir_pin: z:P2.6 +enable_pin: !z:P2.1 +full_steps_per_rotation: 400 +microsteps: 32 +gear_ratio: 80:16 +rotation_distance: 40 +endstop_pin: z:P1.27 +# Z-position of nozzle (in mm) to z-endstop trigger point relative to print surface (Z0) +# (+) value = endstop above Z0, (-) value = endstop below +# Increasing position_endstop brings nozzle closer to the bed +# After you run Z_ENDSTOP_CALIBRATE, position_endstop will be stored at the very end of your config +#position_endstop: -0.5 +position_max: 320 +position_min: -1 +homing_speed: 15.0 +second_homing_speed: 3.0 +homing_retract_dist: 2.0 + +# Z MCU - Y -> Z1 Stepper - Rear Left +[stepper_z1] +step_pin: z:P0.19 +# TMC2209 dir_pin: z:P0.20 +dir_pin: !z:P0.20 +enable_pin: !z:P2.8 +full_steps_per_rotation: 400 +microsteps: 32 +gear_ratio: 80:16 +rotation_distance: 40 + +# Z MCU - Z -> Z2 Stepper - Rear Right +[stepper_z2] +step_pin: z:P0.22 +# TMC2209 dir_pin: !z:P2.11 +dir_pin: z:P2.11 +enable_pin: !z:P0.21 +full_steps_per_rotation: 400 +microsteps: 32 +gear_ratio: 80:16 +rotation_distance: 40 + +# Z MCU - E0 -> Z3 Stepper - Front Right +[stepper_z3] +step_pin: z:P2.13 +# TMC2209 dir_pin: z:P0.11 +dir_pin: !z:P0.11 +enable_pin: !z:P2.12 +full_steps_per_rotation: 400 +microsteps: 32 +gear_ratio: 80:16 +rotation_distance: 40 \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg new file mode 100644 index 000000000..958c1bf87 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg @@ -0,0 +1,163 @@ +##################################################################### +# TMC Definitions of all steppers +##################################################################### +[tmc5160 stepper_x] +cs_pin: P1.10 +spi_software_miso_pin: P0.5 +spi_software_mosi_pin: P1.17 +spi_software_sclk_pin: P0.4 +interpolate: true +run_current: 0.875 +sense_resistor: 0.075 +stealthchop_threshold: 0 + +[tmc5160 stepper_y] +cs_pin: P1.9 +spi_software_miso_pin: P0.5 +spi_software_mosi_pin: P1.17 +spi_software_sclk_pin: P0.4 +interpolate: true +run_current: 0.875 +sense_resistor: 0.075 +stealthchop_threshold: 0 + +[tmc5160 stepper_z] +cs_pin: z:P1.10 +spi_software_miso_pin: z:P0.5 +spi_software_mosi_pin: z:P1.17 +spi_software_sclk_pin: z:P0.4 +interpolate: true +run_current: 1.1 +sense_resistor: 0.075 +stealthchop_threshold: 0 + +[tmc5160 stepper_z1] +cs_pin: z:P1.9 +spi_software_miso_pin: z:P0.5 +spi_software_mosi_pin: z:P1.17 +spi_software_sclk_pin: z:P0.4 +interpolate: true +run_current: 1.1 +sense_resistor: 0.075 +stealthchop_threshold: 0 + +[tmc5160 stepper_z2] +cs_pin: z:P1.8 +spi_software_miso_pin: z:P0.5 +spi_software_mosi_pin: z:P1.17 +spi_software_sclk_pin: z:P0.4 +interpolate: true +run_current: 1.1 +sense_resistor: 0.075 +stealthchop_threshold: 0 + +[tmc5160 stepper_z3] +cs_pin: z:P1.4 +spi_software_miso_pin: z:P0.5 +spi_software_mosi_pin: z:P1.17 +spi_software_sclk_pin: z:P0.4 +interpolate: true +run_current: 1.1 +sense_resistor: 0.075 +stealthchop_threshold: 0 + +#[tmc2209 stepper_x] +#uart_pin: P1.10 +#interpolate: true +#run_current: 0.875 +#hold_current: 0.7 +#sense_resistor: 0.110 +#stealthchop_threshold: 1 +#driver_TBL: 2 +#driver_TOFF: 3 +#driver_HEND: 3 +#driver_HSTRT: 0 +#driver_PWM_GRAD: 8 +#driver_PWM_LIM: 9 + +#[tmc2209 stepper_y] +#uart_pin: P1.9 +#interpolate: true +#run_current: 0.875 +#hold_current: 0.7 +#sense_resistor: 0.110 +#stealthchop_threshold: 1 +#driver_TBL: 2 +#driver_TOFF: 3 +#driver_HEND: 3 +#driver_HSTRT: 0 +#driver_PWM_GRAD: 8 +#driver_PWM_LIM: 9 + +#[tmc2209 stepper_z] +#uart_pin: z:P1.10 +#interpolate: true +#run_current: 1.1 +#hold_current: 1.1 +#sense_resistor: 0.110 +#stealthchop_threshold: 1 +#driver_TBL: 0 +#driver_TOFF: 7 +#driver_HEND: 2 +#driver_HSTRT: 0 +#driver_PWM_GRAD: 8 +#driver_PWM_LIM: 10 + +#[tmc2209 stepper_z1] +#uart_pin: z:P1.9 +#interpolate: true +#run_current: 1.1 +#hold_current: 1.1 +#sense_resistor: 0.110 +#stealthchop_threshold: 1 +#driver_TBL: 0 +#driver_TOFF: 7 +#driver_HEND: 3 +#driver_HSTRT: 0 +#driver_PWM_GRAD: 8 +#driver_PWM_LIM: 10 + +#[tmc2209 stepper_z2] +#uart_pin: z:P1.8 +#interpolate: False +#interpolate: true +#run_current: 1.1 +#hold_current: 1.1 +#sense_resistor: 0.110 +#stealthchop_threshold: 1 +#driver_TBL: 0 +#driver_TOFF: 7 +#driver_HEND: 2 +#driver_HSTRT: 0 +#driver_PWM_GRAD: 8 +#driver_PWM_LIM: 10 + +#[tmc2209 stepper_z3] +#uart_pin: z:P1.4 +#interpolate: true +#run_current: 1.1 +#hold_current: 1.1 +#sense_resistor: 0.110 +#stealthchop_threshold: 1 +#driver_TBL: 0 +#driver_TOFF: 7 +#driver_HEND: 2 +#driver_HSTRT: 0 +#driver_PWM_GRAD: 8 +#driver_PWM_LIM: 10 + + +[tmc2209 extruder] +############### Different Clockworks Setups ############### +## Afterburner: Stepper Motor 0.9 step distance 0.00120 calibrated 0.001196 +## run_current: 0.6 +############################################################ +## Galileo: Stepper Motor 1.8 step distance 0.00132 calibrated 0,001320975 +## run_current: 0.25 +############### Different Clockworks Setups ############### +uart_pin: P1.4 +interpolate: false +run_current: 0.25 +hold_current: 0.1 +sense_resistor: 0.110 +stealthchop_threshold: 0 \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg new file mode 100644 index 000000000..44216d3ed --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg @@ -0,0 +1,109 @@ +[pause_resume] + +[display_status] + +[respond] +default_type: echo +# Sets the default prefix of the "M118" and "RESPOND" output to one +# of the following: +# echo: "echo: " (This is the default) +# command: "// " +# error: "!! " +#default_prefix: echo: +# Directly sets the default prefix. If present, this value will +# override the "default_type". + +##################################################################### +# Macros +##################################################################### +[gcode_macro CANCEL_PRINT] +description: Cancel the actual running print +rename_existing: CANCEL_PRINT_BASE +variable_execute: False +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set filter_off = user.peripheral.filter.run_after_print %} + {% set vent_on = user.peripheral.vent.on_val %} + {% set vent_off = user.peripheral.vent.run_after_print %} + {% set retract = user.filament.retract.end if not printer.pause_resume.is_paused + else user.filament.retract.cancel %} + SET_GCODE_VARIABLE MACRO=CANCEL_PRINT VARIABLE=execute VALUE=True + M117 Cancel + CANCEL_PRINT_BASE + {% if printer['gcode_macro PRINT_START'].state == 'Prepare' %} + {% if not printer.extruder.can_extrude %} + {action_respond_info("Extruder Temp to low heat to %3.1f°C" % printer.configfile.settings.extruder.min_extrude_temp)} + M109 S{printer.configfile.settings.extruder.min_extrude_temp} + {% endif %} + M83 + G1 E-{retract} F{user.speed.retract} + {% endif %} + TURN_OFF_HEATERS + {% if params.PARK|default(0)|int == 1 or (not printer.pause_resume.is_paused and user.park.park_at_cancel) %} + _TOOLHEAD_PARK P={params.PARK|default(0)} X={user.park.pause.x} Y={user.park.pause.y} + {% endif %} + M107 ; turn off fan + {% if user.hw.chamber.fan %} M141 S{vent_on} {% endif %} ; vent chamber (setting fan to below ambient) + _ADD_PRINT_TIME + {% if params.ERROR|default(0)|int == 1 %} + {% if user.hw.display.ena %} _LCD_KNOB COLOR=RED BLINK=0.2 {% endif %} + _SD_PRINT_STATS R='abort' + {% else %} + {% if user.hw.display.ena %} _LCD_KNOB COLOR=BLUE {% endif %} + _SD_PRINT_STATS R='canceled' + {% endif %} + _SD_PRINTER_STATS + {% if user.hw.caselight.ena %} _CASELIGHT_OFF {% endif %} + {% if user.hw.chamber.fan %} UPDATE_DELAYED_GCODE ID=_DELAY_VENT_OFF DURATION={vent_off} {% endif %} + {% if user.hw.filter.ena %} UPDATE_DELAYED_GCODE ID=_DELAY_FILTER_OFF DURATION={filter_off} {% endif %} + {% if user.unload_sd %} UPDATE_DELAYED_GCODE ID=_DELAY_SDCARD_RESET_FILE DURATION=10 {% endif %} + UPDATE_DELAYED_GCODE ID=_CLEAR_DISPLAY DURATION=10 + +[gcode_macro PAUSE] +description: Pause the actual running print +rename_existing: PAUSE_BASE +variable_restore: {'absolute': {'coordinates': True, 'extrude': True}, 'speed': 1500} +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + ##### store coordinates to restore them at resume ##### + {% set restore = {'absolute': {'coordinates': printer.gcode_move.absolute_coordinates, + 'extrude' : printer.gcode_move.absolute_extrude}, + 'speed' : printer.gcode_move.speed} %} + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=restore VALUE="{restore}" + {% if user.hw.display.ena %} _LCD_KNOB COLOR=BLUE BLINK=1 {% endif %} + {% if not printer.extruder.can_extrude %} + {action_respond_info("Extruder Temp to low heat to %3.1f°C" % printer.configfile.settings.extruder.min_extrude_temp)} + M109 S{printer.configfile.settings.extruder.min_extrude_temp} + {% endif %} + M83 + G0 E-{user.filament.retract.pause} F{user.speed.retract} + PAUSE_BASE + _TOOLHEAD_PARK P=0 X={params.X|default(user.park.pause.x)} Y={params.Y|default(user.park.pause.y)} + M104 S{printer.extruder.target} + +[gcode_macro _TOOLHEAD_PARK] +description: Helper: Park toolhead used in PAUSE and CANCEL_PRINT +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set pos = {'x': user.park.bed.x if params.P|int == 1 + else params.X, + 'y': user.park.bed.y if params.P|int == 1 + else params.Y, + 'z': user.park.bed.z if params.P|int == 1 + else [(printer.toolhead.position.z + user.park.pause.dz), printer.toolhead.axis_maximum.z]|min} %} + G90 + G0 Z{pos.z} F{user.speed.z_hop} + G0 X{pos.x} Y{pos.y} F{user.speed.travel} + +[gcode_macro RESUME] +description: Resume the actual running print +rename_existing: RESUME_BASE +gcode: + {% set user = printer['gcode_macro _USER_VARIABLE'] %} + {% set restore = printer["gcode_macro PAUSE"].restore %} + {% if user.hw.display.ena %} _LCD_KNOB COLOR=RED {% endif %} + RESUME_BASE VELOCITY={params.VELOCITY|default(user.speed.travel/60)} + G0 E{user.filament.retract.pause} F{user.speed.retract} + G0 F{restore.speed} + {% if restore.absolute.extrude %} M82 {% endif %} ; set back to absolute + {% if not restore.absolute.coordinates %} G91 {% endif %} ; set back to relative \ No newline at end of file diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg new file mode 100644 index 000000000..a58aeceed --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg @@ -0,0 +1,77 @@ +##################################################################### +# Z Calibration +##################################################################### +[z_calibration] +# The X and Y coordinates (in mm) for clicking the nozzle on the +# Z endstop. +nozzle_xy_position: 123,355 +# The X and Y coordinates (in mm) for clicking the probe's switch +# on the Z endstop. +switch_xy_position: 123,350 +# The X and Y coordinates (in mm) for probing on the print surface +# (e.g. the center point) These coordinates will be adapted by the +# probe's X and Y offsets. The default is the relative_reference_index +# of the configured bed_mesh. It will raise an error if there is no +# probe_bed site and no bed_mesh with a relative_reference_index +# configured. +bed_xy_position: 175,175 +# The trigger point offset of the used mag-probe switch. +# This needs to be fined out manually. +# A smaller value is more away from bed +switch_offset: 0.475 +# The maximum allowed deviation of the calculated offset. +# If the offset exceeds this value, it will stop! +# The default is 1.0 mm. +max_deviation: 2.0 +# The number of times to probe each point. The probed z-values +# will be averaged. The default is from the probe's configuration. +#samples: default from "probe:samples" section +# The maximum Z distance (in mm) that a sample may differ from other +# samples. The default is from the probe's configuration. +#samples_tolerance: default from "probe:samples_tolerance" section +# The number of times to retry if a sample is found that exceeds +# samples_tolerance. The default is from the probe's configuration. +#samples_tolerance_retries: default from "probe:samples_tolerance_retries" section +# The calculation method when sampling more than once - either +# "median" or "average". The default is from the probe's configuration. +#samples_result: default from "probe:samples_result" section +# The distance in mm to move up before moving to the next +# position. The default is two times the z_offset from the probe's +# configuration. +clearance: 2 +#position_min: default from "stepper_z:position_min" section. +# The moving speed in X and Y. The default is 50 mm/s. +speed: 300 +# Speed (in mm/s) of the Z axis when lifting the probe between +# samples and clearance moves. The default is from the probe's +# configuration. +#lift_speed: default from "probe:lift_speed" section +# The fast probing speed (in mm/s) used, when probing_first_fast +# is activated. The default is from the Z rail configuration. +#probing_speed: default from "stepper_z:homing_speed" section. +# The slower speed (in mm/s) for probing the recorded samples. +# The default is second_homing_speed of the Z rail configuration. +#probing_second_speed: default from "stepper_z:second_homing_speed" section. +# Distance to backoff (in mm) before probing the next sample. +# The default is homing_retract_dist from the Z rail configuration. +#probing_retract_dist: default from "stepper_z:homing_retract_dist" section. +# If true, the first probing is done faster by the probing speed. +# This is to get faster down and the result is not recorded as a +# probing sample. The default is false. +probing_first_fast: true +# A list of G-Code commands to execute prior to each calibration command. +# See docs/Command_Templates.md for G-Code format. This can be used to +# attach the probe. +start_gcode: _SET_Z_CURRENT VAL=HOME + DETACH_PROBE +# A list of G-Code commands to execute prior to each probing on the +# mag-probe. See docs/Command_Templates.md for G-Code format. This can be +# used to attach the probe after probing on the nozzle and before probing +# on the mag-probe. +before_switch_gcode: ATTACH_PROBE + G0 Z20 +# A list of G-Code commands to execute after each calibration command. +# See docs/Command_Templates.md for G-Code format. This can be used to +# detach the probe afterwards. +end_gcode: _SET_Z_CURRENT + DETACH_PROBE \ No newline at end of file diff --git a/src/plugins/Codemirror/mochaFileTests.ts b/src/plugins/Codemirror/mochaFileTests.ts new file mode 100644 index 000000000..63ca93d52 --- /dev/null +++ b/src/plugins/Codemirror/mochaFileTests.ts @@ -0,0 +1,107 @@ +import { NodeType, Parser } from '@lezer/common' +import { testTree } from '@lezer/generator/dist/test' + +function toLineContext(file: string, index: number) { + const endEol = file.indexOf('\n', index + 80) + + const endIndex = endEol === -1 ? file.length : endEol + + return file + .substring(index, endIndex) + .split(/\n/) + .map((str) => ' | ' + str) + .join('\n') +} + +function defaultIgnore(type: NodeType) { + return /\W/.test(type.name) +} + +function getLineNumber(text: string, index: number) { + const substring = text.substring(0, index) + const newLineRegex = /\n/g + const lineCount = (substring.match(newLineRegex) || []).length + 1 + return lineCount +} + +export function fileTests(file: string, fileName: string, onlyNoError = false, mayIgnore = defaultIgnore) { + const caseExpr = /\s*#[ \t]*(.*)(?:\r\n|\r|\n)([^]*?)==+>([^]*?)(?:$|(?:\r\n|\r|\n)+(?=#))/gy + const tests: { + name: string + text: string + expected: string + strict: boolean + run(parser: Parser): void + }[] = [] + let lastIndex = 0 + if (onlyNoError) { + tests.push({ + name: fileName, + text: file, + expected: 'no parsing errors', + strict: true, + run(parser: Parser) { + parser + .parse(file) + .cursor() + .iterate((node) => { + if (node.type.isError) { + let msg = 'Parse error at line ' + getLineNumber(file, node.from) + ': ' + const parseError = '"' + file.slice(node.from, node.to) + '" ' + if (parseError.length > 100) msg += parseError.slice(0, 100) + '...' + else msg += parseError + const context = + '\n\t(context: ' + JSON.stringify(file.slice(node.from - 10, node.to + 10)) + ')' + msg += context.length > 100 ? context.slice(0, 100) + '...' : context + throw new Error(msg) + } + }) + }, + }) + } else { + for (;;) { + const m = caseExpr.exec(file) + if (!m) throw new Error(`Unexpected file format in ${fileName} around\n\n${toLineContext(file, lastIndex)}`) + + const text = m[2] + const expected = m[3].trim() + const [, name, configStr] = /(.*?)(\{.*?\})?$/.exec(m[1])! + + if (expected == 'error') { + tests.push({ + name, + text, + expected: 'error while parsing', + strict: false, + run(parser: Parser) { + let parsingError = false + parser + .parse(text) + .cursor() + .iterate((node) => { + if (node.type.isError) parsingError = true + }) + if (!parsingError) throw new Error('Parsed without error, but error was expected!') + }, + }) + } else { + const config = configStr ? JSON.parse(configStr) : null + const strict = !/⚠|\.\.\./.test(expected) + tests.push({ + name, + text, + expected, + strict, + run(parser: Parser) { + if ((parser as any).configure && (strict || config)) + parser = (parser as any).configure({ strict, ...config }) + testTree(parser.parse(text), expected, mayIgnore) + }, + }) + } + lastIndex = m.index + m[0].length + if (lastIndex == file.length) break + } + } + return tests +} diff --git a/src/plugins/Codemirror/package.json b/src/plugins/Codemirror/package.json new file mode 100644 index 000000000..94a2534f1 --- /dev/null +++ b/src/plugins/Codemirror/package.json @@ -0,0 +1,11 @@ +{ + "name": "@lezer/klippercfg", + "version": "1.0", + "description": "Lezer-based grammar for Klipper Configuration", + "main": "dist/klipperCfgParser.cjs", + "type": "module", + "exports": { + "import": "./dist/klipperCfgParser.es.js", + "require": "./dist/klipperCfgParser.cjs" + } +} diff --git a/src/plugins/Codemirror/printLezerTree.ts b/src/plugins/Codemirror/printLezerTree.ts new file mode 100644 index 000000000..dd486e9de --- /dev/null +++ b/src/plugins/Codemirror/printLezerTree.ts @@ -0,0 +1,231 @@ +// MIT License +// +// Copyright (c) 2021 Matthijs Steen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import { Text } from '@codemirror/state' +import { Input, NodeType, SyntaxNode, Tree, TreeCursor } from '@lezer/common' + +class StringInput implements Input { + constructor(private readonly input: string) {} + + get length() { + return this.input.length + } + + chunk(from: number): string { + return this.input.slice(from) + } + + lineChunks = false + + read(from: number, to: number): string { + return this.input.slice(from, to) + } +} + +export function sliceType(cursor: TreeCursor, input: Input, type: number): string | null { + if (cursor.type.id === type) { + const s = input.read(cursor.from, cursor.to) + cursor.nextSibling() + return s + } + return null +} + +export function isType(cursor: TreeCursor, type: number): boolean { + const cond = cursor.type.id === type + if (cond) cursor.nextSibling() + return cond +} + +export type CursorNode = { type: NodeType; from: number; to: number; isLeaf: boolean } + +function cursorNode({ type, from, to }: TreeCursor, isLeaf = false): CursorNode { + return { type, from, to, isLeaf } +} + +export type TreeTraversal = { + beforeEnter?: (cursor: TreeCursor) => void + onEnter: (node: CursorNode) => false | void + onLeave?: (node: CursorNode) => false | void +} + +type TreeTraversalOptions = { + from?: number + to?: number + includeParents?: boolean +} & TreeTraversal + +export function traverseTree( + cursor: TreeCursor | Tree | SyntaxNode, + { from = -Infinity, to = Infinity, includeParents = false, beforeEnter, onEnter, onLeave }: TreeTraversalOptions +): void { + if (!(cursor instanceof TreeCursor)) cursor = cursor instanceof Tree ? cursor.cursor() : cursor.cursor + if (!(cursor instanceof TreeCursor)) return + for (;;) { + let node = cursorNode(cursor) + let leave = false + if (node.from <= to && node.to >= from) { + const enter = !node.type.isAnonymous && (includeParents || (node.from >= from && node.to <= to)) + if (enter && beforeEnter) beforeEnter(cursor) + node.isLeaf = !cursor.firstChild() + if (enter) { + leave = true + if (onEnter(node) === false) return + } + if (!node.isLeaf) continue + } + for (;;) { + node = cursorNode(cursor, node.isLeaf) + if (leave && onLeave) if (onLeave(node) === false) return + leave = cursor.type.isAnonymous + node.isLeaf = false + if (cursor.nextSibling()) break + if (!cursor.parent()) return + leave = true + } + } +} + +function isChildOf(child: CursorNode, parent: CursorNode): boolean { + return child.from >= parent.from && child.from <= parent.to && child.to <= parent.to && child.to >= parent.from +} + +export function validatorTraversal(input: Input | string, { fullMatch = true }: { fullMatch?: boolean } = {}) { + if (typeof input === 'string') input = new StringInput(input) + const state = { + valid: true, + parentNodes: [] as CursorNode[], + lastLeafTo: 0, + } + return { + state, + traversal: { + onEnter(node) { + state.valid = true + if (!node.isLeaf) state.parentNodes.unshift(node) + if (node.from > node.to || node.from < state.lastLeafTo) { + state.valid = false + } else if (node.isLeaf) { + if (state.parentNodes.length && !isChildOf(node, state.parentNodes[0])) state.valid = false + state.lastLeafTo = node.to + } else { + if (state.parentNodes.length) { + if (!isChildOf(node, state.parentNodes[0])) state.valid = false + } else if (fullMatch && (node.from !== 0 || node.to !== input.length)) { + state.valid = false + } + } + }, + onLeave(node) { + if (!node.isLeaf) state.parentNodes.shift() + }, + } as TreeTraversal, + } +} + +export function validateTree( + tree: TreeCursor | Tree | SyntaxNode, + input: Input | string, + options?: { fullMatch?: boolean } +): boolean { + const { state, traversal } = validatorTraversal(input, options) + traverseTree(tree, traversal) + return state.valid +} + +enum Color { + Red = 31, + Green = 32, + Yellow = 33, +} + +function colorize(value: any, color: number): string { + return /* "\u001b[" + color + "m" + */ String(value) /* + "\u001b[39m" */ +} + +type PrintTreeOptions = { from?: number; to?: number; start?: number; includeParents?: boolean } + +export function printTree( + cursor: TreeCursor | Tree | SyntaxNode, + input: Input | string, + { from, to, start = 0, includeParents }: PrintTreeOptions = {} +): string { + const inp = typeof input === 'string' ? new StringInput(input) : input + const text = Text.of(inp.read(0, inp.length).split('\n')) + const state = { + output: '', + prefixes: [] as string[], + hasNextSibling: false, + } + const validator = validatorTraversal(inp) + traverseTree(cursor, { + from, + to, + includeParents, + beforeEnter(cursor) { + state.hasNextSibling = cursor.nextSibling() && cursor.prevSibling() + }, + onEnter(node) { + validator.traversal.onEnter(node) + const isTop = state.output === '' + const hasPrefix = !isTop || node.from > 0 + if (hasPrefix) { + state.output += (!isTop ? '\n' : '') + state.prefixes.join('') + if (state.hasNextSibling) { + state.output += ' ├─ ' + state.prefixes.push(' │ ') + } else { + state.output += ' └─ ' + state.prefixes.push(' ') + } + } + const hasRange = node.from !== node.to + state.output += + (node.type.isError || !validator.state.valid ? colorize(node.type.name, Color.Red) : node.type.name) + + ' ' + + (hasRange + ? '[' + + colorize(locAt(text, start + node.from), Color.Yellow) + + '..' + + colorize(locAt(text, start + node.to), Color.Yellow) + + ']' + : colorize(locAt(text, start + node.from), Color.Yellow)) + if (hasRange && node.isLeaf) { + state.output += ': ' + colorize(JSON.stringify(inp.read(node.from, node.to)), Color.Green) + } + }, + onLeave(node) { + validator.traversal.onLeave!(node) + state.prefixes.pop() + }, + }) + return state.output +} + +function locAt(text: Text, pos: number): string { + const line = text.lineAt(pos) + return line.number + ':' + (pos - line.from) +} + +export function logTree(tree: TreeCursor | Tree | SyntaxNode, input: string, options?: PrintTreeOptions): void { + console.log(printTree(tree, input, options)) +} From 441e456fa2cb7b098f695ece0bcd39472f64c8a4 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sun, 2 Jul 2023 00:44:18 +0200 Subject: [PATCH 13/16] npm install in the case of merge conflicts with rebase, only the version from develop was used --- package-lock.json | 448 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 404 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd60311c3..743866b39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10128,21 +10128,6 @@ "node": ">= 8" } }, - "node_modules/vite/node_modules/rollup": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/vscode-jsonrpc": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", @@ -12694,6 +12679,27 @@ "dev": true, "optional": true }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@cypress/request": { "version": "2.88.10", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", @@ -13023,9 +13029,9 @@ } }, "@lezer/common": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.1.tgz", - "integrity": "sha512-8TR5++Q/F//tpDsLd5zkrvEX5xxeemafEaek7mUp7Y+bI8cKQXdSqhzTOBaOogETcMOVr0pT3BBPXp13477ciw==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.3.tgz", + "integrity": "sha512-JH4wAXCgUOcCGNekQPLhVeUtIqjH0yPBs7vvUdSjyQama9618IOKFJwkv2kcqdhF0my8hQEgCTEJU0GIgnahvA==" }, "@lezer/css": { "version": "1.0.0", @@ -13036,6 +13042,16 @@ "@lezer/lr": "^1.0.0" } }, + "@lezer/generator": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-1.3.0.tgz", + "integrity": "sha512-7HfulDoOMOkskb97fnwgpC6StwPVSob4ptc0iuOH72rapNQBbp6lVj05y7vc5IM0E9pjFjiLmNQeiBiSbLpCtA==", + "dev": true, + "requires": { + "@lezer/common": "^1.0.2", + "@lezer/lr": "^1.3.0" + } + }, "@lezer/highlight": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.1.tgz", @@ -13054,9 +13070,9 @@ } }, "@lezer/lr": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.3.tgz", - "integrity": "sha512-qpB7rBzH8f6Mzjv2AVZRahcm+2Cf7nbIH++uXbvVOL1yIRvVWQ3HAM/saeBLCyz/togB7LGo76qdJYL1uKQlqA==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.7.tgz", + "integrity": "sha512-ssHKb3p0MxhJXT2i7UBmgAY1BIM3Uq/D772Qutu3EVmxWIyNMU12nQ0rL3Fhu+MiFtiTzyTmd3xGwEf3ON5PSA==", "requires": { "@lezer/common": "^1.0.0" } @@ -13123,34 +13139,34 @@ } }, "@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz", + "integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==", "dev": true, "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", "is-module": "^1.0.0", - "resolve": "^1.19.0" + "resolve": "^1.22.1" }, "dependencies": { "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", "dev": true, "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" } }, - "estree-walker": { + "@types/estree": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "dev": true } } @@ -13259,6 +13275,30 @@ } } }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "@types/estree": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", @@ -13347,13 +13387,10 @@ } }, "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "requires": { - "@types/node": "*" - } + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true }, "@types/scheduler": { "version": "0.16.2", @@ -13711,6 +13748,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -13787,6 +13830,12 @@ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -13995,6 +14044,12 @@ "fill-range": "^7.0.1" } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "browserslist": { "version": "4.21.9", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", @@ -14181,6 +14236,17 @@ "string-width": "^4.2.0" } }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "codemirror": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", @@ -14288,6 +14354,12 @@ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "crelt": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", @@ -14679,6 +14751,12 @@ "ms": "2.1.2" } }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -14713,6 +14791,12 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -15481,6 +15565,12 @@ "path-exists": "^4.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -15593,6 +15683,12 @@ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "get-intrinsic": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", @@ -15947,6 +16043,15 @@ "has-tostringtag": "^1.0.0" } }, + "is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" + } + }, "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -16050,6 +16155,12 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -16536,6 +16647,12 @@ "sourcemap-codec": "^1.4.8" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", @@ -16612,6 +16729,109 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -17055,6 +17275,12 @@ "throttleit": "^1.0.0" } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -17637,6 +17863,35 @@ "punycode": "^2.1.0" } }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, "tslib": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", @@ -17931,6 +18186,12 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -18551,6 +18812,40 @@ "leven": "^3.1.0" } }, + "@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -18563,6 +18858,12 @@ "uri-js": "^4.2.2" } }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -18704,6 +19005,12 @@ "workbox-core": "7.0.0" } }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -18726,6 +19033,12 @@ "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -18756,6 +19069,47 @@ } } }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", @@ -18766,6 +19120,12 @@ "fd-slicer": "~1.1.0" } }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", From 4ccc164f2da66e2ffa5963643ff9fa101ff80308 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sun, 2 Jul 2023 01:16:47 +0200 Subject: [PATCH 14/16] also run build language if npm run build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e0e0d218..cb80e04bb 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "scripts": { "serve": "vite serve", - "build": "vite build && npm run build.zip", + "build": "vite build && npm run build:lang && npm run build.zip", "build:lang": "npm run build:parser:klipperCfg && npm run build:lang:klipperCfg", "build:lang:klipperCfg": "rollup --config src/plugins/Codemirror/KlipperCfgLang/rollup.config.js", "build:parser:klipperCfg": "lezer-generator src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar -o src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js", From 3f69ab6452a8be2987afa4b130dedd597f12664d Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sun, 2 Jul 2023 01:19:33 +0200 Subject: [PATCH 15/16] fix build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb80e04bb..30f7d6f08 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "scripts": { "serve": "vite serve", - "build": "vite build && npm run build:lang && npm run build.zip", + "build": "npm run build:lang && vite build && npm run build.zip", "build:lang": "npm run build:parser:klipperCfg && npm run build:lang:klipperCfg", "build:lang:klipperCfg": "rollup --config src/plugins/Codemirror/KlipperCfgLang/rollup.config.js", "build:parser:klipperCfg": "lezer-generator src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar -o src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfgParser.js", From 81997528607debb604fec5f5f60042abdd469767 Mon Sep 17 00:00:00 2001 From: forgodtosave Date: Sun, 23 Jul 2023 23:06:14 +0200 Subject: [PATCH 16/16] added references to AlexZ in the test configs --- .../KlipperCfgLang/test/testConfigs/KlipperScreen.conf | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg | 2 ++ src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg | 2 ++ .../KlipperCfgLang/test/testConfigs/heater_verify.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg | 2 ++ src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/power.cfg | 2 ++ .../KlipperCfgLang/test/testConfigs/pressure_advance.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg | 2 ++ src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg | 2 ++ .../Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg | 2 ++ .../KlipperCfgLang/test/testConfigs/z_calibration.cfg | 2 ++ src/plugins/Codemirror/mochaFileTests.ts | 2 ++ 31 files changed, 62 insertions(+) diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf index 9f150dc5c..0f75d76d7 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + [main] # Invert axis in move panel. Default is False. Change to true to invert invert_x: False diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg index 484d2b15e..13b8fab80 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Macro ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg index a30d7e44e..45f56c363 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Bed Mesh Definition ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg index 2faeda0b0..1f5b5fa08 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Caselight pin Definition ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf index f233bf84d..6a0d381e8 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + #### crowsnest.conf #### This is mainsail / MainsailOS default config. #### See: diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg index f9df81228..7e69e3d00 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + # Use: # - DUMP_PARAMETER print all parameter expect configfile # - DUMP_PARAMETER P='gcode_macro _TEST' print the defined parameter group diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg index 292f177ef..965404a38 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + # Main # + Power Off # + Flexplate diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg index 80c837a9a..946213ff0 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Fan Control ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg index 2c2dd27f3..3743cbc43 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + [firmware_retraction] retract_length: 0.75 ; length of filament (in mm) at G10/G11 unretract_extra_length: 0 ; length of additional filament (in mm) at G11 diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg index ce0b32b9c..8f8c79d1b 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Preperation ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg index 8fded41d1..3721095ff 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ## This is an emergency fix if the gantry is at the max Z position what makes homing imposible ## 1) set enable_force_move: True ## 2) do an klipper restart diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg index 4b02cd60f..3d7041588 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Extruder ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg index bffa83de4..fa16482a2 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Heater Verification ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg index 27922be3b..e4cf9a70f 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Homing definition ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg index a7d1cd15e..446b39192 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # G Sensor definition ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg index 7374570c2..1d819864a 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + # Displays mini12864 LCD (Fystec) [display] lcd_type: uc1701 diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg index 93fdfea96..e2fa0a094 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ## User Paramaters ## BED_TEMP : Target temperature for the Bed. Is also used to decide ## if heatsoak is needed diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg index 4de56e67b..5e2f01010 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # User Macros ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf index 6d59bdd25..9f62727eb 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + [server] host: 0.0.0.0 port: 7125 diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg index 494e4d39f..b0bb7163e 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + # You can specify the park_pos variable manually if you do not want # to use a _USER_VARIABLE macro, The set statement would look like: # {% set park_pos = {'x': val, 'y': val, 'z': val} %} diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg index 1fc8c35dc..32f9d32c4 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Idle Timeout ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg index d01420ad6..0271ebf41 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Preperation ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg index 086b5586e..3e61b79d7 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##===================== SKR 1.4 Pin Definitions =================== # +--------------+------+------+------+------+------+ +----+------+------+------+ # | | X | Y | Z | E0 | E1 | | | 0 | 1 | BED | diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg index 19599b2b2..ca4ddadc0 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Macro ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg index ac0435dc8..ace37ffd4 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Probe ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg index b7c50dc1a..392135ffe 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + #[filament_switch_sensor runout] ## When set to True, a PAUSE will execute immediately after a runout ## is detected. Note that if pause_on_runout is False and the diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg index e8e27ef0d..9c49fa1fc 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + # MCU - X -> B Stepper - Left [stepper_x] step_pin: P2.2 diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg index 958c1bf87..3ce2cb992 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # TMC Definitions of all steppers ##################################################################### diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg index 44216d3ed..f868ea17d 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + [pause_resume] [display_status] diff --git a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg index a58aeceed..b351aa3dd 100644 --- a/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg @@ -1,3 +1,5 @@ +# from https://github.com/zellneralex/klipper_config + ##################################################################### # Z Calibration ##################################################################### diff --git a/src/plugins/Codemirror/mochaFileTests.ts b/src/plugins/Codemirror/mochaFileTests.ts index 63ca93d52..1833679d7 100644 --- a/src/plugins/Codemirror/mochaFileTests.ts +++ b/src/plugins/Codemirror/mochaFileTests.ts @@ -1,3 +1,5 @@ +// based on https://github.com/lezer-parser/generator/blob/main/src/test.ts + import { NodeType, Parser } from '@lezer/common' import { testTree } from '@lezer/generator/dist/test'