diff --git a/build-scripts/gulp/gen-icons-json.js b/build-scripts/gulp/gen-icons-json.js index 268ccb0ce5..8a69ba97af 100644 --- a/build-scripts/gulp/gen-icons-json.js +++ b/build-scripts/gulp/gen-icons-json.js @@ -156,3 +156,12 @@ gulp.task("gen-icons-json", (done) => { done(); }); + +gulp.task("gen-dummy-icons-json", (done) => { + if (!fs.existsSync(OUTPUT_DIR)) { + fs.mkdirSync(OUTPUT_DIR, { recursive: true }); + } + + fs.writeFileSync(path.resolve(OUTPUT_DIR, "iconList.json"), "[]"); + done(); +}); diff --git a/build-scripts/gulp/hassio.js b/build-scripts/gulp/hassio.js index 08370ad7c6..5b5e31650d 100644 --- a/build-scripts/gulp/hassio.js +++ b/build-scripts/gulp/hassio.js @@ -9,6 +9,7 @@ require("./compress.js"); require("./rollup.js"); require("./gather-static.js"); require("./translations.js"); +require("./gen-icons-json.js"); gulp.task( "develop-hassio", @@ -17,6 +18,7 @@ gulp.task( process.env.NODE_ENV = "development"; }, "clean-hassio", + "gen-dummy-icons-json", "gen-index-hassio-dev", "build-supervisor-translations", "copy-translations-supervisor", @@ -33,6 +35,7 @@ gulp.task( process.env.NODE_ENV = "production"; }, "clean-hassio", + "gen-dummy-icons-json", "build-supervisor-translations", "copy-translations-supervisor", "build-locale-data", diff --git a/src/components/ha-code-editor.ts b/src/components/ha-code-editor.ts index 2ec8a2e627..ff1364a934 100644 --- a/src/components/ha-code-editor.ts +++ b/src/components/ha-code-editor.ts @@ -11,6 +11,7 @@ import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import { loadCodeMirror } from "../resources/codemirror.ondemand"; import { HomeAssistant } from "../types"; +import "./ha-icon"; declare global { interface HASSDomEvents { @@ -26,6 +27,12 @@ const saveKeyBinding: KeyBinding = { }, }; +const renderIcon = (completion: Completion) => { + const icon = document.createElement("ha-icon"); + icon.icon = completion.label; + return icon; +}; + @customElement("ha-code-editor") export class HaCodeEditor extends ReactiveElement { public codemirror?: EditorView; @@ -47,6 +54,8 @@ export class HaCodeEditor extends ReactiveElement { private _loadedCodeMirror?: typeof import("../resources/codemirror"); + private _iconList?: Completion[]; + public set value(value: string) { this._value = value; } @@ -154,7 +163,10 @@ export class HaCodeEditor extends ReactiveElement { if (!this.readOnly && this.autocompleteEntities && this.hass) { extensions.push( this._loadedCodeMirror.autocompletion({ - override: [this._entityCompletions.bind(this)], + override: [ + this._entityCompletions.bind(this), + this._mdiCompletions.bind(this), + ], maxRenderedOptions: 10, }) ); @@ -209,6 +221,47 @@ export class HaCodeEditor extends ReactiveElement { }; } + private _getIconItems = async (): Promise => { + if (!this._iconList) { + let iconList: { + name: string; + keywords: string[]; + }[]; + if (__SUPERVISOR__) { + iconList = []; + } else { + iconList = (await import("../../build/mdi/iconList.json")).default; + } + + this._iconList = iconList.map((icon) => ({ + type: "variable", + label: `mdi:${icon.name}`, + detail: icon.keywords.join(", "), + info: renderIcon, + })); + } + + return this._iconList; + }; + + private async _mdiCompletions( + context: CompletionContext + ): Promise { + const match = context.matchBefore(/mdi:/); + + if (!match || (match.from === match.to && !context.explicit)) { + return null; + } + + const iconItems = await this._getIconItems(); + + return { + from: Number(match.from), + options: iconItems, + span: /^\w*.\w*$/, + }; + } + private _blockKeyboardShortcuts() { this.addEventListener("keydown", (ev) => ev.stopPropagation()); }