diff --git a/src/components/TheEditor.vue b/src/components/TheEditor.vue
index e740c7db8..dcd593119 100644
--- a/src/components/TheEditor.vue
+++ b/src/components/TheEditor.vue
@@ -31,6 +31,16 @@
{{ mdiHelp }}
{{ $t('Editor.ConfigReference') }}
+
+ {{ mdiFormatListCheckbox }}
+ {{ $t('Editor.FileStructure') }}
+
-
+
+
+
+
@@ -139,9 +183,11 @@ import {
mdiHelpCircle,
mdiRestart,
mdiUsb,
+ mdiFormatListCheckbox,
} from '@mdi/js'
import type Codemirror from '@/components/inputs/Codemirror.vue'
import DevicesDialog from '@/components/dialogs/DevicesDialog.vue'
+import { ConfigFileSection } from '@/store/files/types'
@Component({
components: { DevicesDialog, Panel, CodemirrorAsync },
@@ -149,6 +195,9 @@ import DevicesDialog from '@/components/dialogs/DevicesDialog.vue'
export default class TheEditor extends Mixins(BaseMixin) {
dialogConfirmChange = false
dialogDevices = false
+ fileStructureSidebar = true
+ structureActive: number[] = []
+ structureOpen: number[] = []
formatFilesize = formatFilesize
@@ -164,6 +213,7 @@ export default class TheEditor extends Mixins(BaseMixin) {
mdiFileDocumentEditOutline = mdiFileDocumentEditOutline
mdiFileDocumentOutline = mdiFileDocumentOutline
mdiUsb = mdiUsb
+ mdiFormatListCheckbox = mdiFormatListCheckbox
declare $refs: {
editor: Codemirror
@@ -305,6 +355,44 @@ export default class TheEditor extends Mixins(BaseMixin) {
return url
}
+ get configFileStructure() {
+ if (['conf', 'cfg'].includes(this.fileExtension)) {
+ const sourcecode = this.sourcecode
+ const lines = sourcecode.split(/\n/gi)
+ const regex = /^[^#\S]*?(\[(?.*?)]|(?\w+)\s*?[:=])/gim
+ let section = null
+ let name = null
+ let structure: ConfigFileSection[] = []
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i]
+ const matches = [...line.matchAll(regex)]
+ if (matches.length > 0) {
+ const match = matches[0]
+ if (match['groups']['section']) {
+ section = match['groups']['section']
+ structure.push({
+ name: section,
+ type: 'section',
+ line: i + 1,
+ children: [],
+ })
+ } else if (match['groups']['name']) {
+ name = match['groups']['name']
+ structure[structure.length - 1]['children'].push({
+ name: name,
+ type: 'item',
+ line: i + 1,
+ })
+ }
+ }
+ }
+ this.fileStructureSidebar = true
+ return structure
+ }
+ this.fileStructureSidebar = false
+ return null
+ }
+
cancelDownload() {
this.$store.dispatch('editor/cancelLoad')
}
@@ -337,6 +425,29 @@ export default class TheEditor extends Mixins(BaseMixin) {
})
}
+ showFileStructure() {
+ this.fileStructureSidebar = !this.fileStructureSidebar
+ }
+
+ activeChanges(key: any) {
+ this.$refs.editor.gotoLine(key)
+ }
+
+ lineChanges(line: number) {
+ this.configFileStructure?.map((item) => {
+ if (item.line == line) {
+ this.structureActive = [line]
+ } else {
+ item.children?.map((child) => {
+ if (child.line == line) {
+ this.structureActive = [line]
+ if (!this.structureOpen.includes(item.line)) this.structureOpen.push(item.line)
+ }
+ })
+ }
+ })
+ }
+
@Watch('changed')
changedChanged(newVal: boolean) {
if (!this.confirmUnsavedChanges) return
@@ -398,4 +509,15 @@ export default class TheEditor extends Mixins(BaseMixin) {
background-color: var(--color-primary);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E %3Cpath d='M15.88 8.29L10 14.17l-1.88-1.88a.996.996 0 1 0-1.41 1.41l2.59 2.59c.39.39 1.02.39 1.41 0L17.3 9.7a.996.996 0 0 0 0-1.41c-.39-.39-1.03-.39-1.42 0z' fill='%23fffff'/%3E %3C/svg%3E");
}
+
+@media screen and (min-width: 960px) {
+ .structure {
+ margin-right: 300px
+ }
+ .structure-sidebar {
+ width: 300px;
+ overflow-y: auto;
+ }
+}
+
diff --git a/src/components/inputs/Codemirror.vue b/src/components/inputs/Codemirror.vue
index 9c54459ec..7f6cd3e38 100644
--- a/src/components/inputs/Codemirror.vue
+++ b/src/components/inputs/Codemirror.vue
@@ -79,7 +79,6 @@ export default class Codemirror extends Mixins(BaseMixin) {
setCmValue(content: string) {
this.cminstance?.setState(EditorState.create({ doc: content, extensions: this.cmExtensions }))
}
-
get cmExtensions() {
const extensions = [
EditorView.theme({}, { dark: true }),
@@ -88,6 +87,10 @@ export default class Codemirror extends Mixins(BaseMixin) {
indentUnit.of(' '.repeat(this.tabSize)),
keymap.of([indentWithTab]),
EditorView.updateListener.of((update) => {
+ if(update.selectionSet) {
+ const line = this.cminstance?.state?.doc.lineAt(this.cminstance?.state?.selection.main.head).number
+ this.$emit('lineChange', line)
+ }
this.content = update.state?.doc.toString()
if (this.$emit) {
this.$emit('input', this.content)
@@ -110,5 +113,13 @@ export default class Codemirror extends Mixins(BaseMixin) {
get tabSize() {
return this.$store.state.gui.editor.tabSize || 2
}
+
+ gotoLine(line:number){
+ const l:any = this.cminstance?.state?.doc.line(line);
+ this.cminstance?.dispatch({
+ selection: { head: l.from, anchor: l.to },
+ scrollIntoView: true
+ });
+ }
}
diff --git a/src/locales/en.json b/src/locales/en.json
index 5c403574b..04205db9b 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -203,7 +203,8 @@
"UnsavedChanges": "Unsaved Changes",
"UnsavedChangesMessage": "Do you want to save your changes made to {filename}?",
"UnsavedChangesSubMessage": "Your changes will be lost if you don't save them. You can disable this message in the editor settings.",
- "Uploading": "Uploading"
+ "Uploading": "Uploading",
+ "FileStructure": "File Structure"
},
"EmergencyStopDialog": {
"AreYouSure": "Are you sure?",
@@ -375,7 +376,6 @@
"EntryNextPerform": "Next perform:",
"EntryPerformedAt": "Performed at {date}.",
"EntrySince": "Used since:",
- "EstimatedFilament": "Estimated Filament",
"EstimatedFilamentWeight": "Estimated Filament Weight",
"EstimatedTime": "Estimated Time",
"FilamentBasedReminder": "Filament",
@@ -426,7 +426,6 @@
"SelectedJobs": "Selected Jobs",
"SelectedPrinttime": "Selected Print Time",
"Slicer": "Slicer",
- "SlicerVersion": "Slicer Version",
"StartTime": "Start Time",
"Statistics": "Statistics",
"Status": "Status",
diff --git a/src/locales/zh.json b/src/locales/zh.json
index 9ff1fadbf..2722244f3 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -199,7 +199,8 @@
"UnsavedChanges": "有未保存的更改",
"UnsavedChangesMessage": "是否保存对{filename}的更改?",
"UnsavedChangesSubMessage": "如果不保存,您的更改将丢失。您可以在编辑器设置中关闭此提示。",
- "Uploading": "正在上传"
+ "Uploading": "正在上传",
+ "FileStructure": "结构"
},
"EmergencyStopDialog": {
"AreYouSure": "确定要执行此操作吗?",
diff --git a/src/store/files/types.ts b/src/store/files/types.ts
index 55197c159..468025733 100644
--- a/src/store/files/types.ts
+++ b/src/store/files/types.ts
@@ -97,3 +97,13 @@ export interface ApiGetDirectoryReturnFile {
filename: string
permissions: string
}
+
+export interface ConfigFileKey{
+ name: string,
+ type: string,
+ line: number
+}
+
+export interface ConfigFileSection extends ConfigFileKey{
+ children: ConfigFileKey[]
+}