From 12b124e5a38f66a644d5094f984e0db14a3d9223 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 26 Feb 2021 18:01:48 +0100 Subject: [PATCH] Add search, history to codemirror (#8469) And prevent jump on focus --- package.json | 2 + src/components/ha-code-editor.ts | 19 ++++----- src/panels/lovelace/hui-editor.ts | 7 +++- src/resources/codemirror.ts | 69 +++++++++++++++++++++++++++++-- yarn.lock | 33 +++++++++++++++ 5 files changed, 114 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index f189d9dce1..a5cc01cfb9 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "@codemirror/commands": "^0.17.2", "@codemirror/gutter": "^0.17.2", "@codemirror/highlight": "^0.17.2", + "@codemirror/history": "^0.17.2", "@codemirror/legacy-modes": "^0.17.1", + "@codemirror/search": "^0.17.1", "@codemirror/state": "^0.17.1", "@codemirror/stream-parser": "^0.17.1", "@codemirror/text": "^0.17.2", diff --git a/src/components/ha-code-editor.ts b/src/components/ha-code-editor.ts index 4946fd9e8a..4232b1ce3d 100644 --- a/src/components/ha-code-editor.ts +++ b/src/components/ha-code-editor.ts @@ -129,28 +129,25 @@ export class HaCodeEditor extends UpdatingElement { doc: this._value, extensions: [ loaded.lineNumbers(), + loaded.history(), + loaded.highlightSelectionMatches(), loaded.keymap.of([ ...loaded.defaultKeymap, - { - key: "Tab", - run: loaded.indentMore, - }, - { - key: "Shift-Tab", - run: loaded.indentLess, - }, + ...loaded.searchKeymap, + ...loaded.historyKeymap, + ...loaded.tabKeyBindings, saveKeyBinding, ]), loaded.tagExtension(modeTag, this._mode), loaded.theme, loaded.Prec.fallback(loaded.highlightStyle), - loaded.EditorView.updateListener.of((update) => - this._onUpdate(update) - ), loaded.tagExtension( readOnlyTag, loaded.EditorView.editable.of(!this.readOnly) ), + loaded.EditorView.updateListener.of((update) => + this._onUpdate(update) + ), ], }), root: shadowRoot, diff --git a/src/panels/lovelace/hui-editor.ts b/src/panels/lovelace/hui-editor.ts index 909dfd9d59..2f7614b63f 100644 --- a/src/panels/lovelace/hui-editor.ts +++ b/src/panels/lovelace/hui-editor.ts @@ -1,3 +1,4 @@ +import { undoDepth } from "@codemirror/history"; import "@material/mwc-button"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; @@ -148,11 +149,13 @@ class LovelaceFullConfigEditor extends LitElement { } private _yamlChanged() { - this._changed = true; - if (!window.onbeforeunload) { + this._changed = undoDepth(this.yamlEditor.codemirror!.state) > 0; + if (this._changed && !window.onbeforeunload) { window.onbeforeunload = () => { return true; }; + } else if (!this._changed && window.onbeforeunload) { + window.onbeforeunload = null; } } diff --git a/src/resources/codemirror.ts b/src/resources/codemirror.ts index 35497aaaa3..cf357ff708 100644 --- a/src/resources/codemirror.ts +++ b/src/resources/codemirror.ts @@ -3,24 +3,35 @@ import { EditorView as CMEditorView } from "@codemirror/view"; import { StreamLanguage } from "@codemirror/stream-parser"; import { jinja2 } from "@codemirror/legacy-modes/mode/jinja2"; import { yaml } from "@codemirror/legacy-modes/mode/yaml"; +import { indentLess, indentMore } from "@codemirror/commands"; export { keymap } from "@codemirror/view"; export { CMEditorView as EditorView }; export { EditorState, Prec, tagExtension } from "@codemirror/state"; -export { defaultKeymap, indentLess, indentMore } from "@codemirror/commands"; +export { defaultKeymap } from "@codemirror/commands"; export { lineNumbers } from "@codemirror/gutter"; +export { searchKeymap, highlightSelectionMatches } from "@codemirror/search"; +export { history, historyKeymap } from "@codemirror/history"; export const langs = { jinja2: StreamLanguage.define(jinja2), yaml: StreamLanguage.define(yaml), }; +export const tabKeyBindings = [ + { key: "Tab", run: indentMore }, + { + key: "Shift-Tab", + run: indentLess, + }, +]; + export const theme = CMEditorView.theme({ $: { color: "var(--primary-text-color)", backgroundColor: "var(--code-editor-background-color, var(--card-background-color))", - "& ::selection": { backgroundColor: "rgba(var(--rgb-primary-color), 0.2)" }, + "& ::selection": { backgroundColor: "rgba(var(--rgb-primary-color), 0.3)" }, height: "var(--code-mirror-height, auto)", }, @@ -30,7 +41,57 @@ export const theme = CMEditorView.theme({ "$$focused $cursor": { borderLeftColor: "#var(--secondary-text-color)" }, "$$focused $selectionBackground, $selectionBackground": { - backgroundColor: "rgba(var(--rgb-primary-color), 0.2)", + backgroundColor: "rgba(var(--rgb-primary-color), 0.3)", + }, + + $panels: { + backgroundColor: "var(--primary-background-color)", + color: "var(--primary-text-color)", + }, + "$panels.top": { borderBottom: "1px solid var(--divider-color)" }, + "$panels.bottom": { borderTop: "1px solid var(--divider-color)" }, + + "$panel.search": { + padding: "2px 6px 4px", + position: "relative", + "& [name=close]": { + position: "absolute", + top: "0", + right: "4px", + backgroundColor: "inherit", + border: "none", + font: "inherit", + padding: "4px", + margin: 0, + outline: "none", + fontSize: "150%", + }, + }, + + $button: { + border: "1px solid var(--primary-color)", + padding: "8px", + textTransform: "uppercase", + margin: "4px", + background: "none", + }, + + $textfield: { + backgroundColor: "var(--secondary-background-color)", + padding: "8px", + }, + + $selectionMatch: { + backgroundColor: "rgba(var(--rgb-primary-color), 0.1)", + }, + + $searchMatch: { + backgroundColor: "rgba(var(--rgb-accent-color), .2)", + outline: "1px solid rgba(var(--rgb-accent-color), .4)", + }, + "$searchMatch.selected": { + backgroundColor: "rgba(var(--rgb-accent-color), .4)", + outline: "1px solid var(--accent-color)", }, $gutters: { @@ -40,10 +101,12 @@ export const theme = CMEditorView.theme({ border: "none", borderRight: "1px solid var(--paper-input-container-color, var(--secondary-text-color))", + paddingRight: "1px", }, "$$focused $gutters": { borderRight: "2px solid var(--paper-input-container-focus-color, var(--primary-color))", + paddingRight: "0", }, "$gutterElementags.lineNumber": { color: "inherit" }, }); diff --git a/yarn.lock b/yarn.lock index 25e3d6c924..3252bc38af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1938,6 +1938,14 @@ lezer-tree "^0.13.0" style-mod "^3.2.0" +"@codemirror/history@^0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@codemirror/history/-/history-0.17.2.tgz#d94273af95f7dbd8a0c41c370984e4bbf55d54e8" + integrity sha512-ML/FA6VJMMwsQrx7HFXaOAg/LqrLxUktE5pu230UOn0u5bxIPxbX0lLGs34994s9HPruqbCqIikSc+IfjLkFcA== + dependencies: + "@codemirror/state" "^0.17.0" + "@codemirror/view" "^0.17.0" + "@codemirror/language@^0.17.0": version "0.17.5" resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-0.17.5.tgz#77b551680f0bb8a6e40de7659e518de1e0c637a0" @@ -1966,6 +1974,14 @@ "@codemirror/view" "^0.17.0" lezer-tree "^0.13.0" +"@codemirror/panel@^0.17.0": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@codemirror/panel/-/panel-0.17.1.tgz#9dfd3b464c537caebec43fffbd8a283b0210d4c1" + integrity sha512-2it2Sk02eF4WFwPVoRLhr9lPGq9lwwwHZFyb4olqI6tOyTPwk6leZ4ntabYrhvjRc7gD6S6vM14KhOtjm4hjqg== + dependencies: + "@codemirror/state" "^0.17.0" + "@codemirror/view" "^0.17.0" + "@codemirror/rangeset@^0.17.0": version "0.17.1" resolved "https://registry.yarnpkg.com/@codemirror/rangeset/-/rangeset-0.17.1.tgz#41066bcf4b70b2c7595cb1363780688cc3f1235b" @@ -1973,6 +1989,18 @@ dependencies: "@codemirror/state" "^0.17.0" +"@codemirror/search@^0.17.1": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-0.17.1.tgz#eb6ae529093b09f92b1d62c4d0ad8d09c4e218f7" + integrity sha512-wY0KP9my/0uKQk9AU39EqmkY6zMVv2Erej5b1rRBksM78JZXzjNUl4gyhtx1/0om84IZ1ocmW8MRElkAY6r1rw== + dependencies: + "@codemirror/panel" "^0.17.0" + "@codemirror/rangeset" "^0.17.0" + "@codemirror/state" "^0.17.0" + "@codemirror/text" "^0.17.0" + "@codemirror/view" "^0.17.0" + crelt "^1.0.5" + "@codemirror/state@^0.17.0", "@codemirror/state@^0.17.1": version "0.17.2" resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-0.17.2.tgz#b94846def08c2258bfdf09839359c31823e663ff" @@ -6199,6 +6227,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +crelt@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.5.tgz#57c0d52af8c859e354bace1883eb2e1eb182bb94" + integrity sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA== + cropperjs@^1.5.7: version "1.5.7" resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.7.tgz#b65019725bae1c6285e881fb661b2141fa57025b"