Skip to content

Commit 68e6a21

Browse files
authored
feat: improved config file handling in monaco (#1827)
Signed-off-by: Pedro Lamas <pedrolamas@gmail.com>
1 parent 2471413 commit 68e6a21

19 files changed

Lines changed: 317 additions & 2115 deletions

CLAUDE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ src/
135135
### Monaco Editor
136136

137137
- Setup in `src/components/widgets/filesystem/setupMonaco.ts` (includes worker environment setup)
138-
- Monarch tokenizers for `gcode`, `klipper-config`, `log` languages (in `src/monaco/language/*.monarch.ts`)
139-
- Custom CodeLens providers (links to Klipper docs from config sections)
140-
- Document symbol provider for `klipper-config`; folding range provider for `klipper-config` and `gcode`
138+
- Monarch tokenizers for `gcode`, `klipper-config`, `moonraker-config`, `log` languages (in `src/monaco/language/*.monarch.ts`)
139+
- Custom CodeLens providers (links to Klipper/Moonraker docs from config sections)
140+
- CodeLens and document symbol providers for `klipper-config` and `moonraker-config`; folding range provider for `klipper-config`, `moonraker-config`, and `gcode`
141141
- Language providers run in dedicated Web Workers (`monacoCodeLensWorker`, `monacoDocumentSymbolsWorker`, `monacoFoldingRangesWorker`)
142142

143143
## Integration Points

docs/docs/features/file-editor.md

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,23 @@ directly from your browser.
1717

1818
## Syntax highlighting
1919

20-
Rich, TextMate grammar-based syntax highlighting is provided for the following
21-
file types:
22-
23-
| File Type | Highlighted Elements |
24-
|-----------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
25-
| **Klipper config** (`.cfg`, `.conf`) | Section headers, keys and values, pin references, sensor and thermistor types, driver types, serial paths, booleans, numbers, and embedded G-code within macros including Jinja2 template blocks |
26-
| **G-code** (`.gcode`, `.g`, `.gc`, `.gco`, `.ufp`, `.nc`) | G/M/T commands, coordinates, feed rates, tool and offset registers, math functions, macro variables, and control keywords |
27-
| **Log files** (`.log`) | Log-level colorization (debug, info, warning, error, critical), timestamps, URLs, UUIDs, git SHAs, exception names, and stack traces |
28-
| **JSON** | Full validation and IntelliSense via a dedicated language worker |
29-
| **CSS, SCSS, Less** | Property completion, hover, and validation via a dedicated language worker |
30-
| **Markdown** | Basic syntax highlighting |
20+
Syntax highlighting is provided for the following file types:
21+
22+
| File Type | Highlighted Elements |
23+
|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|
24+
| **Klipper config** (`.cfg`) | Section headers, key names, values, boolean constants, comments, and SAVE_CONFIG block markers |
25+
| **Moonraker config** (`.conf`) | Section headers, key names, values, boolean constants, space-prefixed escaped comment sigils (`\#`, `\;`), inline comments, and comments |
26+
| **G-code** (`.gcode`, `.g`, `.gc`, `.gco`, `.ufp`, `.nc`) | G/M/T commands, coordinates, feed rates, tool and offset registers, math functions, macro variables, and control keywords |
27+
| **Log files** (`.log`) | Log-level colorization (debug, info, warning, error, critical), timestamps, URLs, UUIDs, git SHAs, exception names, and stack traces |
28+
| **JSON** | Full validation and IntelliSense via a dedicated language worker |
29+
| **CSS, SCSS, Less** | Property completion, hover, and validation via a dedicated language worker |
30+
| **Markdown** | Basic syntax highlighting |
3131

3232
## Documentation links
3333

34-
When editing Klipper config files, clickable **CodeLens** links appear above
35-
each `[section]` header — linking directly to the relevant documentation page
36-
for:
34+
When editing Klipper or Moonraker config files, clickable **CodeLens** links
35+
appear above each `[section]` header — linking directly to the relevant
36+
documentation page for:
3737

3838
- [Klipper](https://www.klipper3d.org/Config_Reference.html)
3939
- [Kalico](https://docs.kalico.gg/Config_Reference.html)
@@ -47,7 +47,7 @@ being edited. This feature can be disabled in the editor settings.
4747

4848
## Outline and navigation
4949

50-
Klipper config files provide a two-level document outline:
50+
Klipper and Moonraker config files provide a two-level document outline:
5151

5252
- **Sections** — each `[section_name]` block
5353
- **Properties** — each `key: value` or `key = value` within a section
@@ -57,14 +57,19 @@ property, or browse the outline panel.
5757

5858
## Code folding
5959

60-
Collapsible regions are supported for both Klipper config and G-code files.
60+
Collapsible regions are supported for Klipper config, Moonraker config, and
61+
G-code files.
6162

62-
**Klipper config:**
63+
**Klipper and Moonraker config:**
6364

6465
- Section blocks — collapse an entire `[section]` and its contents
6566
- Comment blocks — consecutive comment lines fold together
6667
- Named regions — `#region` / `#endregion` markers for custom foldable areas
6768

69+
**Klipper config only:**
70+
71+
- SAVE_CONFIG blocks — the auto-generated `#*# ...` section folds as a unit
72+
6873
**G-code:**
6974

7075
- Print layers — each `SET_PRINT_STATS_INFO ... CURRENT_LAYER=N` starts a

package-lock.json

Lines changed: 0 additions & 64 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525
"test": "npm run test:unit",
2626
"test:unit": "vitest --environment jsdom --config ./vitest.config.ts",
2727
"type-check": "vue-tsc --build --noEmit",
28-
"circular-check": "skott --displayMode=file-tree --showCircularDependencies --no-trackTypeOnlyDependencies --tsconfig=./tsconfig.app.json",
29-
"theme:convert": "cd tools; node convertTheme.mjs"
28+
"circular-check": "skott --displayMode=file-tree --showCircularDependencies --no-trackTypeOnlyDependencies --tsconfig=./tsconfig.app.json"
3029
},
3130
"main": "index.js",
3231
"dependencies": {
@@ -93,7 +92,6 @@
9392
"husky": "^9.1.7",
9493
"jsdom": "^29.0.2",
9594
"mockdate": "^3.0.5",
96-
"monaco-vscode-textmate-theme-converter": "^0.1.7",
9795
"neostandard": "^0.13.0",
9896
"rollup": "^4.60.2",
9997
"sass-embedded": "^1.99.0",

src/components/widgets/filesystem/monacoProviders.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ abstract class MonacoProviderBase<T> {
9191
}
9292

9393
protected _createCacheKey (model: monaco.editor.ITextModel): string {
94-
return `${model.uri.toString()}@${model.getVersionId()}`
94+
return `${model.uri.toString()}@${model.getVersionId()}@${model.getLanguageId()}`
9595
}
9696
}
9797

@@ -100,7 +100,7 @@ export class MonacoDocumentSymbolProvider extends MonacoProviderBase<monaco.lang
100100
const cacheKey = this._createCacheKey(model)
101101

102102
if (this._lastCacheKey !== cacheKey) {
103-
const result = await this._workerWrapper<MonacoDocumentSymbolsWorkerResponseMessage>(MonacoDocumentSymbolsWorker, 'klipper-config', model.getValue(), token)
103+
const result = await this._workerWrapper<MonacoDocumentSymbolsWorkerResponseMessage>(MonacoDocumentSymbolsWorker, model.getLanguageId(), model.getValue(), token)
104104

105105
if (result == null) {
106106
return []
@@ -163,7 +163,7 @@ export class MonacoCodeLensProvider extends MonacoProviderBase<monaco.languages.
163163
? this._klippyApp.name
164164
: service
165165

166-
const result = await this._workerWrapper<MonacoCodeLensWorkerResponseMessage>(MonacoCodeLensWorker, 'klipper-config', model.getValue(), token)
166+
const result = await this._workerWrapper<MonacoCodeLensWorkerResponseMessage>(MonacoCodeLensWorker, model.getLanguageId(), model.getValue(), token)
167167

168168
if (result == null) {
169169
return []

src/components/widgets/filesystem/setupMonaco.ts

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@ import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
1818
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
1919

2020
import getVueApp from '@/util/get-vue-app'
21-
import themeDark from '@/monaco/theme/editor.dark.theme.json'
22-
import themeLight from '@/monaco/theme/editor.light.theme.json'
2321

2422
import type { KlippyApp } from '@/store/printer/types'
2523

2624
import gcodeMonarchLanguage from '@/monaco/language/gcode.monarch'
27-
import klipperConfigMonarchLanguage from '@/monaco/language/klipper-config.monarch'
25+
import * as klipperConfigMonarchLanguage from '@/monaco/language/klipper-config.monarch'
26+
import * as moonrakerConfigMonarchLanguage from '@/monaco/language/moonraker-config.monarch'
2827
import logMonarchLanguage from '@/monaco/language/log.monarch'
2928
import { type CodeLensSupportedService, MonacoCodeLensProvider, MonacoDocumentSymbolProvider, MonacoFoldingRangeProvider } from './monacoProviders'
3029

@@ -45,22 +44,21 @@ self.MonacoEnvironment = {
4544

4645
async function setupMonaco () {
4746
monaco.languages.register({ id: 'gcode', extensions: ['gcode', 'g', 'gc', 'gco', 'ufp', 'nc'] })
48-
monaco.languages.register({ id: 'klipper-config', extensions: ['cfg', 'conf'] })
47+
monaco.languages.register({ id: 'klipper-config', extensions: ['cfg'] })
48+
monaco.languages.register({ id: 'moonraker-config', extensions: ['conf'] })
4949
monaco.languages.register({ id: 'log', extensions: ['log'] })
5050

5151
monaco.languages.setLanguageConfiguration('gcode', {
5252
comments: {
5353
lineComment: ';'
5454
}
5555
})
56-
monaco.languages.setLanguageConfiguration('klipper-config', {
57-
comments: {
58-
lineComment: '#'
59-
}
60-
})
56+
monaco.languages.setLanguageConfiguration('klipper-config', klipperConfigMonarchLanguage.conf)
57+
monaco.languages.setLanguageConfiguration('moonraker-config', moonrakerConfigMonarchLanguage.conf)
6158

6259
monaco.languages.setMonarchTokensProvider('gcode', gcodeMonarchLanguage)
63-
monaco.languages.setMonarchTokensProvider('klipper-config', klipperConfigMonarchLanguage)
60+
monaco.languages.setMonarchTokensProvider('klipper-config', klipperConfigMonarchLanguage.language)
61+
monaco.languages.setMonarchTokensProvider('moonraker-config', moonrakerConfigMonarchLanguage.language)
6462
monaco.languages.setMonarchTokensProvider('log', logMonarchLanguage)
6563

6664
const app = getVueApp()
@@ -77,14 +75,44 @@ async function setupMonaco () {
7775
window.open(url)
7876
})
7977

80-
monaco.languages.registerDocumentSymbolProvider('klipper-config', new MonacoDocumentSymbolProvider())
81-
82-
monaco.languages.registerCodeLensProvider('klipper-config', new MonacoCodeLensProvider())
83-
84-
monaco.languages.registerFoldingRangeProvider(['klipper-config', 'gcode'], new MonacoFoldingRangeProvider())
85-
86-
monaco.editor.defineTheme('dark-converted', themeDark as monaco.editor.IStandaloneThemeData)
87-
monaco.editor.defineTheme('light-converted', themeLight as monaco.editor.IStandaloneThemeData)
78+
monaco.languages.registerDocumentSymbolProvider(['klipper-config', 'moonraker-config'], new MonacoDocumentSymbolProvider())
79+
80+
monaco.languages.registerCodeLensProvider(['klipper-config', 'moonraker-config'], new MonacoCodeLensProvider())
81+
82+
monaco.languages.registerFoldingRangeProvider(['klipper-config', 'moonraker-config', 'gcode'], new MonacoFoldingRangeProvider())
83+
84+
monaco.editor.defineTheme('light-converted', {
85+
base: 'vs',
86+
inherit: true,
87+
rules: [
88+
{ token: 'comment.control.save-config', foreground: '7b2fbe', fontStyle: 'italic' },
89+
{ token: 'entity.name.section', foreground: '267f99', fontStyle: 'bold' },
90+
{ token: 'variable.name', foreground: '0070c1' },
91+
{ token: 'delimiter', foreground: '666666' },
92+
{ token: 'constant.language', foreground: '0000ff' },
93+
{ token: 'string', foreground: 'a31515' },
94+
{ token: 'comment', foreground: '008000', fontStyle: 'italic' },
95+
],
96+
colors: {},
97+
})
98+
monaco.editor.defineTheme('dark-converted', {
99+
base: 'vs-dark',
100+
inherit: true,
101+
rules: [
102+
{ token: 'comment.control.save-config', foreground: 'c586c0', fontStyle: 'italic' },
103+
{ token: 'entity.name.section', foreground: '4ec9b0', fontStyle: 'bold' },
104+
{ token: 'variable.name', foreground: '9cdcfe' },
105+
{ token: 'delimiter', foreground: '808080' },
106+
{ token: 'constant.language', foreground: '569cd6' },
107+
{ token: 'string', foreground: 'ce9178' },
108+
{ token: 'comment', foreground: '6a9955', fontStyle: 'italic' },
109+
],
110+
colors: {
111+
'editor.background': '#28282b',
112+
'editor.lineHighlightBackground': '#3a3a3e',
113+
'minimap.background': '#28282b'
114+
},
115+
})
88116

89117
return monaco
90118
}

src/monaco/README.md

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)