From 09ab9a3fe2fa3276e822b5d992d4e6269bfe3be5 Mon Sep 17 00:00:00 2001 From: Stuart Gilbert Date: Wed, 28 Jan 2026 21:06:35 -0800 Subject: [PATCH] Add YAML file support: views, settings, and syntax highlighting (#26) Fixes #25 --- manifest.json | 6 ++-- package-lock.json | 54 +++++++++++++++++++++++++++-------- package.json | 1 + src/constants.ts | 3 ++ src/loader-plugin-settings.ts | 4 +++ src/loader-settings-tab.ts | 18 ++++++++++++ src/main.ts | 12 ++++++++ src/utils/obsidian-utils.ts | 4 ++- src/views/yaml-view.ts | 41 ++++++++++++++++++++++++++ 9 files changed, 127 insertions(+), 16 deletions(-) create mode 100644 src/views/yaml-view.ts diff --git a/manifest.json b/manifest.json index 223cca4..febaaf1 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,11 @@ { "id": "data-files-editor", "name": "Data Files Editor", - "version": "1.2.1", + "version": "1.2.2", "minAppVersion": "0.15.0", - "description": "Plugin to edit data files like txt, xml, json", + "description": "Plugin to edit data files like txt, xml, json, and yaml", "author": "ZukTol", "authorUrl": "https://github.com/ZukTol", "fundingUrl": "", "isDesktopOnly": false -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 788d6bf..b0b2179 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { "name": "data-files-loader", - "version": "1.2.0", + "version": "1.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-files-loader", - "version": "1.2.0", + "version": "1.2.1", "license": "MIT", "dependencies": { "@codemirror/commands": "^6.10.0", "@codemirror/lang-json": "^6.0.2", + "@codemirror/lang-yaml": "^6.1.1", "@codemirror/state": "^6.5.2", "@codemirror/theme-one-dark": "^6.1.3", "@codemirror/view": "^6.38.6", @@ -77,6 +78,21 @@ "@lezer/json": "^1.0.0" } }, + "node_modules/@codemirror/lang-yaml": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.2.tgz", + "integrity": "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.2.0", + "@lezer/lr": "^1.0.0", + "@lezer/yaml": "^1.0.0" + } + }, "node_modules/@codemirror/language": { "version": "6.9.2", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.9.2.tgz", @@ -592,16 +608,18 @@ "peer": true }, "node_modules/@lezer/common": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.1.0.tgz", - "integrity": "sha512-XPIN3cYDXsoJI/oDWoR2tD++juVrhgIago9xyKhZ7IhGlzdDM9QgC8D8saKNCz5pindGcznFr2HBSsEQSWnSjw==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.0.tgz", + "integrity": "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==", + "license": "MIT" }, "node_modules/@lezer/highlight": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.6.tgz", - "integrity": "sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "license": "MIT", "dependencies": { - "@lezer/common": "^1.0.0" + "@lezer/common": "^1.3.0" } }, "node_modules/@lezer/json": { @@ -614,13 +632,25 @@ } }, "node_modules/@lezer/lr": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.14.tgz", - "integrity": "sha512-z5mY4LStlA3yL7aHT/rqgG614cfcvklS+8oFRFBYrs4YaWLJyKKM4+nN6KopToX0o9Hj6zmH6M5kinOYuy06ug==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.7.tgz", + "integrity": "sha512-wNIFWdSUfX9Jc6ePMzxSPVgTVB4EOfDIwLQLWASyiUdHKaMsiilj9bYiGkGQCKVodd0x6bgQCV207PILGFCF9Q==", + "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" } }, + "node_modules/@lezer/yaml": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.3.tgz", + "integrity": "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.4.0" + } + }, "node_modules/@marijn/find-cluster-break": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", diff --git a/package.json b/package.json index 558ad3a..f8eba76 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "dependencies": { "@codemirror/commands": "^6.10.0", "@codemirror/lang-json": "^6.0.2", + "@codemirror/lang-yaml": "^6.1.1", "@codemirror/state": "^6.5.2", "@codemirror/theme-one-dark": "^6.1.3", "@codemirror/view": "^6.38.6", diff --git a/src/constants.ts b/src/constants.ts index 201573e..9ecbbf2 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,7 +2,10 @@ export const VIEW_TYPE_JSON = "json"; export const VIEW_TYPE_XML = "xml"; export const VIEW_TYPE_TXT = "txt"; export const VIEW_TYPE_MARKDOWN = "markdown"; +export const VIEW_TYPE_YAML = "yaml"; export const EXT_JSON = "json"; export const EXT_XML = "xml"; export const EXT_TXT = "txt"; +export const EXT_YAML = "yaml"; +export const EXT_YML = "yml"; diff --git a/src/loader-plugin-settings.ts b/src/loader-plugin-settings.ts index cc72dc3..8bbe52b 100644 --- a/src/loader-plugin-settings.ts +++ b/src/loader-plugin-settings.ts @@ -5,6 +5,8 @@ doCreateXml: boolean; doLoadJson: boolean; doCreateJson: boolean; + doLoadYaml: boolean; + doCreateYaml: boolean; doAutosaveFiles: boolean; lineWrapping: boolean; } @@ -16,6 +18,8 @@ export const DEFAULT_SETTINGS: LoaderPluginSettings = { doCreateXml: true, doLoadJson: true, doCreateJson: true, + doLoadYaml: true, + doCreateYaml: true, doAutosaveFiles: true, lineWrapping: true } diff --git a/src/loader-settings-tab.ts b/src/loader-settings-tab.ts index fa2efa6..3705683 100644 --- a/src/loader-settings-tab.ts +++ b/src/loader-settings-tab.ts @@ -72,6 +72,24 @@ export default class LoaderSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); })); + new Setting(containerEl) + .setName('Load .yaml/.yml files') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.doLoadYaml) + .onChange(async (value) => { + this.plugin.settings.doLoadYaml = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Create .yaml files') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.doCreateYaml) + .onChange(async (value) => { + this.plugin.settings.doCreateYaml = value; + await this.plugin.saveSettings(); + })); + new Setting(containerEl) .setName('Enable autosave for files') .addToggle(toggle => toggle diff --git a/src/main.ts b/src/main.ts index 74e8c43..ba92639 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,6 +4,7 @@ import * as constants from './constants' import {path} from "./utils"; import JsonView from "./views/json-view"; import TxtView from "./views/txt-view"; +import YamlView from "./views/yaml-view"; import {DEFAULT_SETTINGS, LoaderPluginSettings} from "./loader-plugin-settings"; export default class LoaderPlugin extends Plugin { @@ -18,6 +19,8 @@ export default class LoaderPlugin extends Plugin { this.tryRegisterXml(); + this.tryRegisterYaml(); + // This adds a settings tab so the user can configure various aspects of the plugin this.addSettingTab(new LoaderSettingTab(this.app, this)); } @@ -51,6 +54,15 @@ export default class LoaderPlugin extends Plugin { } } + private tryRegisterYaml(): void { + if (this.settings.doLoadYaml) { + this.registerView(constants.VIEW_TYPE_YAML, (leaf: WorkspaceLeaf) => new YamlView(leaf, this)); + this.registerExtensions([constants.EXT_YAML, constants.EXT_YML], constants.VIEW_TYPE_YAML); + } + if (this.settings.doCreateYaml) + this.registerContextMenuCommand(constants.EXT_YAML); + } + onunload(): void { } diff --git a/src/utils/obsidian-utils.ts b/src/utils/obsidian-utils.ts index 09b9748..62bd2a8 100644 --- a/src/utils/obsidian-utils.ts +++ b/src/utils/obsidian-utils.ts @@ -1,13 +1,15 @@ import {App} from "obsidian"; import BaseView from "../views/base-view"; -import {VIEW_TYPE_JSON, VIEW_TYPE_TXT} from "../constants"; +import {VIEW_TYPE_JSON, VIEW_TYPE_TXT, VIEW_TYPE_YAML} from "../constants"; import JsonView from "../views/json-view"; import TxtView from "../views/txt-view"; +import YamlView from "../views/yaml-view"; export function getLoaderViews(app: App): BaseView[] { const leaves = [ ...app.workspace.getLeavesOfType(VIEW_TYPE_JSON).filter(l => l.view instanceof JsonView), ...app.workspace.getLeavesOfType(VIEW_TYPE_TXT).filter(l => l.view instanceof TxtView), + ...app.workspace.getLeavesOfType(VIEW_TYPE_YAML).filter(l => l.view instanceof YamlView), ]; return leaves.map(l => l.view as BaseView); } diff --git a/src/views/yaml-view.ts b/src/views/yaml-view.ts new file mode 100644 index 0000000..6b76e7e --- /dev/null +++ b/src/views/yaml-view.ts @@ -0,0 +1,41 @@ +import { WorkspaceLeaf } from "obsidian"; +import { yaml } from "@codemirror/lang-yaml"; +import { Extension } from "@codemirror/state"; +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { tags } from "@lezer/highlight"; +import { VIEW_TYPE_YAML } from '../constants' +import LoaderPlugin from "../main"; +import { getIndentByTabExtension } from "../services/indentation-provider" +import BaseView from "./base-view"; + +const yamlDarkHighlight = HighlightStyle.define([ + { tag: tags.propertyName, color: "#e5c07b" }, // keys - warm yellow/gold + { tag: tags.string, color: "#98c379" }, // string values - green + { tag: tags.number, color: "#d19a66" }, // numbers - orange + { tag: tags.bool, color: "#d19a66" }, // booleans - orange + { tag: tags.null, color: "#d19a66" }, // null - orange + { tag: tags.comment, color: "#7f848e" }, // comments - gray +]); + +export default class YamlView extends BaseView { + constructor(leaf: WorkspaceLeaf, plugin: LoaderPlugin) { + super(leaf, plugin); + } + + getViewType(): string { + return VIEW_TYPE_YAML; + } + + protected getEditorExtensions(): Extension[] { + const extensions: Extension[] = [ + getIndentByTabExtension(), + yaml() + ]; + + if (document.body.classList.contains('theme-dark')) { + extensions.push(syntaxHighlighting(yamlDarkHighlight)); + } + + return extensions; + } +}