diff --git a/.gitignore b/.gitignore index acffdf238..5c169384c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ package-lock.json cypress/screenshots/ cypress/videos/ components.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/package-lock.json b/package-lock.json index 83dc5cb1d..743866b39 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", @@ -55,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", @@ -71,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", @@ -2280,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", @@ -2702,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", @@ -2715,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", @@ -2733,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" } @@ -2828,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": { @@ -2982,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", @@ -3070,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", @@ -3589,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", @@ -3711,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", @@ -3992,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", @@ -4289,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", @@ -4418,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", @@ -4945,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", @@ -4991,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", @@ -6109,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", @@ -6273,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", @@ -6776,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", @@ -6933,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", @@ -7374,6 +7547,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", @@ -7566,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", @@ -7666,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", @@ -8296,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", @@ -8409,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", @@ -9094,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", @@ -9511,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", @@ -10345,7 +10734,53 @@ "ajv": ">=8" } }, - "node_modules/workbox-build/node_modules/ajv": { + "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", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", @@ -10361,6 +10796,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", @@ -10503,6 +10944,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", @@ -10534,6 +10981,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", @@ -10568,6 +11024,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", @@ -10578,6 +11088,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", @@ -12160,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", @@ -12489,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", @@ -12502,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", @@ -12520,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" } @@ -12589,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 } } @@ -12725,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", @@ -12813,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", @@ -13177,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", @@ -13253,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", @@ -13461,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", @@ -13647,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", @@ -13754,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", @@ -14145,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", @@ -14179,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", @@ -14947,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", @@ -15059,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", @@ -15413,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", @@ -15516,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", @@ -15845,6 +16490,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", @@ -15989,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", @@ -16065,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", @@ -16508,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", @@ -17090,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", @@ -17384,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", @@ -18004,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", @@ -18016,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", @@ -18157,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", @@ -18179,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", @@ -18209,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", @@ -18219,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", diff --git a/package.json b/package.json index 181eb4ea7..30f7d6f08 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,10 @@ }, "scripts": { "serve": "vite serve", - "build": "vite build && 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", "format": "npm run format:base -- --write", "format:base": "prettier .", "format:check": "npm run format:base -- --check", @@ -20,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": { @@ -45,6 +49,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", @@ -70,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", @@ -86,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 9c54459ec..3c1d2599d 100644 --- a/src/components/inputs/Codemirror.vue +++ b/src/components/inputs/Codemirror.vue @@ -14,13 +14,19 @@ 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 { klipperCfg } from '../../plugins/Codemirror/KlipperCfgLang/lang/klipperCfg' +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 = '' @@ -49,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 { @@ -86,6 +97,7 @@ export default class Codemirror extends Mixins(BaseMixin) { basicSetup, vscodeDark, indentUnit.of(' '.repeat(this.tabSize)), + parseErrorLint, keymap.of([indentWithTab]), EditorView.updateListener.of((update) => { this.content = update.state?.doc.toString() @@ -95,7 +107,7 @@ 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(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/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 new file mode 100644 index 000000000..a6aa5c5e7 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/lang/klipperCfg.ts @@ -0,0 +1,41 @@ +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' + +const jinja2Parser = StreamLanguage.define(klipper_config).parser + +export const klipperCfgLang = LRLanguage.define({ + parser: parser.configure({ + props: [ + foldNodeProp.add({ + ConfigBlock(tree) { + const body = tree.lastChild + if (body == null) return null + let lastOption = body.lastChild + if (lastOption == null) return null + while (lastOption.name == 'Comment') { + lastOption = lastOption.prevSibling + if (lastOption == null) return null + } + return { from: body.from - 1, to: lastOption.to - 1 } + }, + }), + ], + wrap: parseMixed((node) => { + return node.name == 'Jinja2' ? { parser: jinja2Parser } : null + }), + }), + languageData: { + commentTokens: { line: '#' }, + }, +}) + +export function klipperCfg() { + return new LanguageSupport(klipperCfgLang) +} + +/* +to generate the parser run: +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 new file mode 100644 index 000000000..5920fff37 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/parser/highlight.js @@ -0,0 +1,27 @@ +import { styleTags, tags as t } from '@lezer/highlight' + +export const klipperConfigHighlighting = styleTags({ + Import: t.keyword, + ImportKeyword: t.keyword, + Parameter: t.variableName, + ConfigBlock: t.keyword, + BlockType: t.keyword, + Identifier: t.regexp, + + String: t.string, + 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 new file mode 100644 index 000000000..719233e82 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/parser/klipperCfg.grammar @@ -0,0 +1,73 @@ +@top Program { (Import | ConfigBlock )+ } + +@skip { AutoGenerated (newline | eof) | space | blankLine | Comment newline? } + +valueBlock { indent (content (newline | eof) | valueBlock)+ (dedent | eof) } +sep { content (seperator content)+ } + + +Import { "[" ImportKeyword FilePath "]" (newline | eof) } +ConfigBlock {"[" BlockType Identifier* "]" ( newline Body? | newline? eof ) } + +Body { Option+ eof? } +Option { Parameter ":" Value | GcodeKeyword Jinja2 } + +Value { value (newline | eof) | value? newline valueBlock } +Jinja2 { jinja2 (newline | eof) | jinja2? newline valueBlock } + +value { Pin | pins | VirtualPin | Cords | Number | String | Boolean | Path | FilePath | Resolution | Ratio | Ipv4 | Ipv6 } +pins { sep<(Pin | VirtualPin), ","> } +Cords { sep } +Number { number } + + +@context trackIndent from "./tokens.js" +@external tokens indentation from "./tokens.js" { indent, dedent } +@external tokens newlines from "./tokens.js" { newline, blankLine, eof } + +@tokens { + extAscii { $[a-zA-Z0-9_\-.] } + unixPath { ![/<>|:&{}\t\f #;\[\]\n\r] } + + ImportKeyword{ "include" } + 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" | "true" | "false" } + Pin { ("^" | "~")? "!"? "P" $[A-Z]? $[0-9.]+ } + VirtualPin { ("^" | "~")? "!"? extAscii+ ":" extAscii+ } + + AutoGenerated { "#*#" ![\n\r]* } + Comment { ("#"|";") ![\n\r]* } + + space { $[ \t\f]+ } + + @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" + +@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/Codemirror/KlipperCfgLang/parser/tokens.js b/src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js new file mode 100644 index 000000000..d343a0468 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/parser/tokens.js @@ -0,0 +1,82 @@ +/* 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/klipperCfgParser.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)) { + while (input.next == space || input.next == tab) { + input.advance() + } + if (isLineBreak(input.next)) input.acceptToken(blankLine, 1) + } 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 && !isLineBreak(input.next)) { + 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)) >= 1 ? 1 : 0) + if (term == dedent) return context.parent + return context + }, + hash(context) { + return context.hash + }, +}) 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..0f75d76d7 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/KlipperScreen.conf @@ -0,0 +1,103 @@ +# from https://github.com/zellneralex/klipper_config + +[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..13b8fab80 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/basic_macro.cfg @@ -0,0 +1,56 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..45f56c363 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/bed_mesh.cfg @@ -0,0 +1,135 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..1f5b5fa08 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/caselight.cfg @@ -0,0 +1,31 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..6a0d381e8 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/crowsnest.conf @@ -0,0 +1,43 @@ +# from https://github.com/zellneralex/klipper_config + +#### 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..7e69e3d00 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/debug_macro.cfg @@ -0,0 +1,69 @@ +# 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 +# - 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..965404a38 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/display_menu.cfg @@ -0,0 +1,529 @@ +# from https://github.com/zellneralex/klipper_config + +# 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..946213ff0 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/fan.cfg @@ -0,0 +1,169 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..3743cbc43 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/filament.cfg @@ -0,0 +1,178 @@ +# 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 +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..8f8c79d1b --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/flexplate.cfg @@ -0,0 +1,214 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..3721095ff --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/force_move.cfg @@ -0,0 +1,34 @@ +# 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 +## 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..3d7041588 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater.cfg @@ -0,0 +1,92 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..fa16482a2 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/heater_verify.cfg @@ -0,0 +1,16 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..e4cf9a70f --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/homing.cfg @@ -0,0 +1,109 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..446b39192 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/input_shaper.cfg @@ -0,0 +1,153 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..1d819864a --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/lcd.cfg @@ -0,0 +1,305 @@ +# from https://github.com/zellneralex/klipper_config + +# 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..e2fa0a094 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/macro.cfg @@ -0,0 +1,358 @@ +# 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 +## 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..5e2f01010 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/magprobe.cfg @@ -0,0 +1,288 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..9f62727eb --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/moonraker.conf @@ -0,0 +1,189 @@ +# from https://github.com/zellneralex/klipper_config + +[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..b0bb7163e --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/park_macro.cfg @@ -0,0 +1,22 @@ +# 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} %} +# 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..32f9d32c4 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/power.cfg @@ -0,0 +1,92 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..0271ebf41 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/pressure_advance.cfg @@ -0,0 +1,187 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..3e61b79d7 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printer.cfg @@ -0,0 +1,467 @@ +# from https://github.com/zellneralex/klipper_config + +##===================== 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..ca4ddadc0 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/printtime.cfg @@ -0,0 +1,169 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..ace37ffd4 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/probe_qgl.cfg @@ -0,0 +1,123 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..392135ffe --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/runout.cfg @@ -0,0 +1,96 @@ +# 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 +## 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..9c49fa1fc --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/stepper.cfg @@ -0,0 +1,88 @@ +# from https://github.com/zellneralex/klipper_config + +# 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..3ce2cb992 --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/tmc.cfg @@ -0,0 +1,165 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..f868ea17d --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/webclient.cfg @@ -0,0 +1,111 @@ +# from https://github.com/zellneralex/klipper_config + +[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..b351aa3dd --- /dev/null +++ b/src/plugins/Codemirror/KlipperCfgLang/test/testConfigs/z_calibration.cfg @@ -0,0 +1,79 @@ +# from https://github.com/zellneralex/klipper_config + +##################################################################### +# 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..1833679d7 --- /dev/null +++ b/src/plugins/Codemirror/mochaFileTests.ts @@ -0,0 +1,109 @@ +// 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' + +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/parseErrorLint.ts b/src/plugins/Codemirror/parseErrorLint.ts new file mode 100644 index 000000000..ae717f6f5 --- /dev/null +++ b/src/plugins/Codemirror/parseErrorLint.ts @@ -0,0 +1,19 @@ +import { syntaxTree } from '@codemirror/language' +import { linter, Diagnostic } from '@codemirror/lint' + +export const parseErrorLint = linter((view) => { + const diagnostics: Diagnostic[] = [] + syntaxTree(view.state) + .cursor() + .iterate((node) => { + 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/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)) +}