extract code editor stuff

This commit is contained in:
Lukas Bach 2023-09-26 18:00:39 +02:00
parent baa92c9cee
commit ea9681df58
3 changed files with 403 additions and 368 deletions

View file

@ -3,22 +3,24 @@
import { TextFileView, TFile, WorkspaceLeaf } from "obsidian";
import { viewType } from "./common";
import CodeFilesPlugin from "./codeFilesPlugin";
import { mountCodeEditor } from "./mountCodeEditor";
import { getLanguage } from "./getLanguage";
export class CodeEditorView extends TextFileView {
static i = 0;
id = CodeEditorView.i++;
value = "";
codeEditor: ReturnType<typeof mountCodeEditor>;
iframe: HTMLIFrameElement;
initialValue: string;
constructor(leaf: WorkspaceLeaf, private plugin: CodeFilesPlugin) {
super(leaf);
}
getDisplayText(): string {
return this.file?.name;
return this.file?.name ?? "Code Editor";
}
getViewType(): string {
@ -26,399 +28,47 @@ export class CodeEditorView extends TextFileView {
}
getContext(file?: TFile) {
return file?.path ?? this.file?.path;
return file?.path ?? this.file?.path ?? "";
}
async onClose() {
await super.onClose();
// console.log("!!onClose", this.file?.name, this.id);
this.iframe?.remove();
this.codeEditor.destroy();
}
async onLoadFile(file: TFile) {
await super.onLoadFile(file);
// console.log("!!onLoadFile", this.id, this.file?.name, file.name)
const theme = (app as any).getTheme() === "obsidian" ? "vs-dark" : "vs";
const queryParameters = new URLSearchParams();
queryParameters.append("context", this.getContext(file));
queryParameters.append("lang", this.getLanguage());
queryParameters.append("theme", theme);
queryParameters.append("background", "transparent");
queryParameters.append(
"folding",
this.plugin.settings.folding ? "true" : "false"
);
queryParameters.append(
"lineNumbers",
this.plugin.settings.lineNumbers ? "on" : "off"
);
queryParameters.append(
"minimap",
this.plugin.settings.minimap ? "true" : "false"
);
queryParameters.append("javascriptDefaults", "true");
queryParameters.append("typescriptDefaults", "true");
queryParameters.append(
"javascriptDefaultsNoSemanticValidation",
!this.plugin.settings.semanticValidation ? "true" : "false"
);
queryParameters.append(
"typescriptDefaultsNoSemanticValidation",
!this.plugin.settings.semanticValidation ? "true" : "false"
);
queryParameters.append(
"javascriptDefaultsNoSyntaxValidation",
!this.plugin.settings.syntaxValidation ? "true" : "false"
);
queryParameters.append(
"typescriptDefaultsNoSyntaxValidation",
!this.plugin.settings.syntaxValidation ? "true" : "false"
this.codeEditor = mountCodeEditor(
this.plugin,
getLanguage(file.extension),
this.initialValue,
this.getContext(file)
);
this.iframe = document.createElement("iframe");
this.iframe.src = `https://embeddable-monaco.lukasbach.com?${queryParameters.toString()}`;
this.iframe.style.width = "100%";
this.iframe.style.height = "100%";
this.contentEl.style.overflow = "hidden";
this.contentEl.append(this.iframe);
window.addEventListener("message", ({ data }) => {
switch (data.type) {
case "ready": {
this.send("change-value", { value: this.value });
this.send("change-language", {
language: this.getLanguage(),
});
this.send("change-background", {
background: "transparent",
theme,
});
break;
}
case "change": {
if (data.context === this.getContext()) {
// console.log("!change event", data.value, data.context);
this.value = data.value;
} else {
// console.log("!change event", data.value, data.context, "ignored!!!!!!!!!!!!");
}
// this.requestSave();
break;
}
default:
break;
}
});
this.contentEl.append(this.codeEditor.iframe);
}
async onUnloadFile(file: TFile) {
await super.onUnloadFile(file);
// console.log("!!onUnloadFile", this.id, file.name)
this.iframe?.remove();
this.codeEditor.destroy();
}
async onOpen() {
await super.onOpen();
// console.log("!!onOpen", this.id, this.file?.name)
}
clear(): void {
// console.log("!!clear", this.id, this.file?.name);
this.value = "";
this.send("change-value", { value: "" });
this.codeEditor.clear();
}
getViewData(): string {
// console.log("!!get view data", this.id, this.file?.name, this.value)
return this.value;
return this.codeEditor.getValue();
}
setViewData(data: string): void {
// console.log("!!set view data", this.id, this.file?.name, data, clear)
this.value = data;
this.send("change-value", { value: data });
}
getLanguage() {
switch (this.file?.extension) {
case "js":
case "es6":
case "jsx":
case "cjs":
case "mjs":
return "javascript";
case "ts":
case "tsx":
case "cts":
case "mts":
return "typescript";
case "json":
return "json";
case "py":
case "rpy":
case "pyu":
case "cpy":
case "gyp":
case "gypi":
return "python";
case "css":
return "css";
case "html":
case "htm":
case "shtml":
case "xhtml":
case "mdoc":
case "jsp":
case "asp":
case "aspx":
case "jshtm":
return "html";
case "cpp":
case "cc":
case "cxx":
case "hpp":
case "hh":
case "hxx":
return "cpp";
case "graphql":
case "gql":
return "graphql";
case "java":
case "jav":
return "java";
case "php":
case "php4":
case "php5":
case "phtml":
case "ctp":
return "php";
case "sql":
return "sql";
case "yaml":
case "yml":
return "yaml";
case "bat":
case "batch":
return "bat";
case "lua":
return "lua";
case "rb":
case "rbx":
case "rjs":
case "gemspec":
return "ruby";
case "markdown":
case "mdown":
case "mkdn":
case "mkd":
case "mdwn":
case "mdtxt":
case "mdtext":
case "mdx":
return "markdown";
case "r":
case "rhistory":
case "rmd":
case "rprofile":
case "rt":
return "r";
case "ftl":
case "ftlh":
case "ftlx":
return "freemarker2";
case "rst":
return "restructuredtext";
case "hcl":
case "tf":
case "tfvars":
return "hcl";
case "ini":
case "properties":
case "gitconfig":
return "ini";
case "pug":
case "jade":
return "pug";
case "dart":
return "dart";
case "rs":
case "rlib":
return "rust";
case "less":
return "less";
case "cls":
return "apex";
case "tcl":
return "tcl";
case "abap":
return "abap";
case "ecl":
return "ecl";
case "pla":
return "pla";
case "cmd":
return "bat";
case "vb":
return "vb";
case "sb":
return "sb";
case "m3":
case "i3":
case "mg":
case "ig":
return "m3";
case "go":
return "go";
case "s":
return "mips";
case "pl":
case "pm":
return "perl";
case "wgsl":
return "wgsl";
case "twig":
return "twig";
case "scss":
return "scss";
case "redis":
return "redis";
case "sh":
case "bash":
return "shell";
case "scala":
case "sc":
case "sbt":
return "scala";
case "jl":
return "julia";
case "dax":
case "msdax":
return "msdax";
case "lex":
return "lexon";
case "cshtml":
return "razor";
case "bicep":
return "bicep";
case "azcli":
return "azcli";
case "swift":
case "Swift":
return "swift";
case "flow":
return "flow9";
case "xml":
case "xsd":
case "dtd":
case "ascx":
case "csproj":
case "config":
case "props":
case "targets":
case "wxi":
case "wxl":
case "wxs":
case "xaml":
case "svgz":
case "opf":
case "xslt":
case "xsl":
return "xml";
case "kt":
case "kts":
return "kotlin";
case "cypher":
case "cyp":
return "cypher";
case "coffee":
return "coffeescript";
case "fs":
case "fsi":
case "ml":
case "mli":
case "fsx":
case "fsscript":
return "fsharp";
case "scm":
case "ss":
case "sch":
case "rkt":
return "scheme";
case "rq":
return "sparql";
case "aes":
return "aes";
case "liquid":
case "html.liquid":
return "liquid";
case "pas":
case "p":
case "pp":
return "pascal";
case "ex":
case "exs":
return "elixir";
case "qs":
return "qsharp";
case "cs":
case "csx":
case "cake":
return "csharp";
case "clj":
case "cljs":
case "cljc":
case "edn":
return "clojure";
case "mligo":
return "cameligo";
case "sol":
return "sol";
case "proto":
return "proto";
case "dats":
case "sats":
case "hats":
return "postiats";
case "ligo":
return "pascaligo";
case "dockerfile":
return "dockerfile";
case "handlebars":
case "hbs":
return "handlebars";
case "pq":
case "pqm":
return "powerquery";
case "m":
return "objective-c";
case "sv":
case "svh":
return "systemverilog";
case "v":
case "vh":
return "verilog";
case "st":
case "iecst":
case "iecplc":
case "lc3lib":
return "st";
case "c":
case "h":
return "c";
default:
return "plaintext";
}
}
send(type: string, payload: any) {
// console.log("!!send", this.id, !!this.iframe, !!this.iframe?.contentWindow)
this.iframe?.contentWindow?.postMessage(
{
type,
...payload,
},
"*"
);
this.initialValue = data;
this.codeEditor?.setValue(data);
}
}

270
src/getLanguage.ts Normal file
View file

@ -0,0 +1,270 @@
export const getLanguage = (extension: string) => {
switch (extension) {
case "js":
case "es6":
case "jsx":
case "cjs":
case "mjs":
return "javascript";
case "ts":
case "tsx":
case "cts":
case "mts":
return "typescript";
case "json":
return "json";
case "py":
case "rpy":
case "pyu":
case "cpy":
case "gyp":
case "gypi":
return "python";
case "css":
return "css";
case "html":
case "htm":
case "shtml":
case "xhtml":
case "mdoc":
case "jsp":
case "asp":
case "aspx":
case "jshtm":
return "html";
case "cpp":
case "cc":
case "cxx":
case "hpp":
case "hh":
case "hxx":
return "cpp";
case "graphql":
case "gql":
return "graphql";
case "java":
case "jav":
return "java";
case "php":
case "php4":
case "php5":
case "phtml":
case "ctp":
return "php";
case "sql":
return "sql";
case "yaml":
case "yml":
return "yaml";
case "bat":
case "batch":
return "bat";
case "lua":
return "lua";
case "rb":
case "rbx":
case "rjs":
case "gemspec":
return "ruby";
case "markdown":
case "mdown":
case "mkdn":
case "mkd":
case "mdwn":
case "mdtxt":
case "mdtext":
case "mdx":
return "markdown";
case "r":
case "rhistory":
case "rmd":
case "rprofile":
case "rt":
return "r";
case "ftl":
case "ftlh":
case "ftlx":
return "freemarker2";
case "rst":
return "restructuredtext";
case "hcl":
case "tf":
case "tfvars":
return "hcl";
case "ini":
case "properties":
case "gitconfig":
return "ini";
case "pug":
case "jade":
return "pug";
case "dart":
return "dart";
case "rs":
case "rlib":
return "rust";
case "less":
return "less";
case "cls":
return "apex";
case "tcl":
return "tcl";
case "abap":
return "abap";
case "ecl":
return "ecl";
case "pla":
return "pla";
case "cmd":
return "bat";
case "vb":
return "vb";
case "sb":
return "sb";
case "m3":
case "i3":
case "mg":
case "ig":
return "m3";
case "go":
return "go";
case "s":
return "mips";
case "pl":
case "pm":
return "perl";
case "wgsl":
return "wgsl";
case "twig":
return "twig";
case "scss":
return "scss";
case "redis":
return "redis";
case "sh":
case "bash":
return "shell";
case "scala":
case "sc":
case "sbt":
return "scala";
case "jl":
return "julia";
case "dax":
case "msdax":
return "msdax";
case "lex":
return "lexon";
case "cshtml":
return "razor";
case "bicep":
return "bicep";
case "azcli":
return "azcli";
case "swift":
case "Swift":
return "swift";
case "flow":
return "flow9";
case "xml":
case "xsd":
case "dtd":
case "ascx":
case "csproj":
case "config":
case "props":
case "targets":
case "wxi":
case "wxl":
case "wxs":
case "xaml":
case "svgz":
case "opf":
case "xslt":
case "xsl":
return "xml";
case "kt":
case "kts":
return "kotlin";
case "cypher":
case "cyp":
return "cypher";
case "coffee":
return "coffeescript";
case "fs":
case "fsi":
case "ml":
case "mli":
case "fsx":
case "fsscript":
return "fsharp";
case "scm":
case "ss":
case "sch":
case "rkt":
return "scheme";
case "rq":
return "sparql";
case "aes":
return "aes";
case "liquid":
case "html.liquid":
return "liquid";
case "pas":
case "p":
case "pp":
return "pascal";
case "ex":
case "exs":
return "elixir";
case "qs":
return "qsharp";
case "cs":
case "csx":
case "cake":
return "csharp";
case "clj":
case "cljs":
case "cljc":
case "edn":
return "clojure";
case "mligo":
return "cameligo";
case "sol":
return "sol";
case "proto":
return "proto";
case "dats":
case "sats":
case "hats":
return "postiats";
case "ligo":
return "pascaligo";
case "dockerfile":
return "dockerfile";
case "handlebars":
case "hbs":
return "handlebars";
case "pq":
case "pqm":
return "powerquery";
case "m":
return "objective-c";
case "sv":
case "svh":
return "systemverilog";
case "v":
case "vh":
return "verilog";
case "st":
case "iecst":
case "iecplc":
case "lc3lib":
return "st";
case "c":
case "h":
return "c";
default:
return "plaintext";
}
};

115
src/mountCodeEditor.ts Normal file
View file

@ -0,0 +1,115 @@
import CodeFilesPlugin from "./codeFilesPlugin";
export const mountCodeEditor = (
plugin: CodeFilesPlugin,
language: string,
initialValue: string,
codeContext: string
) => {
let value = initialValue;
const theme = (app as any).getTheme() === "obsidian" ? "vs-dark" : "vs";
const queryParameters = new URLSearchParams();
queryParameters.append("context", codeContext);
queryParameters.append("lang", language);
queryParameters.append("theme", theme);
queryParameters.append("background", "transparent");
queryParameters.append(
"folding",
plugin.settings.folding ? "true" : "false"
);
queryParameters.append(
"lineNumbers",
plugin.settings.lineNumbers ? "on" : "off"
);
queryParameters.append(
"minimap",
plugin.settings.minimap ? "true" : "false"
);
queryParameters.append("javascriptDefaults", "true");
queryParameters.append("typescriptDefaults", "true");
queryParameters.append(
"javascriptDefaultsNoSemanticValidation",
!plugin.settings.semanticValidation ? "true" : "false"
);
queryParameters.append(
"typescriptDefaultsNoSemanticValidation",
!plugin.settings.semanticValidation ? "true" : "false"
);
queryParameters.append(
"javascriptDefaultsNoSyntaxValidation",
!plugin.settings.syntaxValidation ? "true" : "false"
);
queryParameters.append(
"typescriptDefaultsNoSyntaxValidation",
!plugin.settings.syntaxValidation ? "true" : "false"
);
const iframe: HTMLIFrameElement = document.createElement("iframe");
iframe.src = `https://embeddable-monaco.lukasbach.com?${queryParameters.toString()}`;
iframe.style.width = "100%";
iframe.style.height = "100%";
const send = (type: string, payload: any) => {
iframe?.contentWindow?.postMessage(
{
type,
...payload,
},
"*"
);
};
window.addEventListener("message", ({ data }) => {
switch (data.type) {
case "ready": {
send("change-value", { value });
send("change-language", {
language,
});
send("change-background", {
background: "transparent",
theme,
});
break;
}
case "change": {
if (data.context === codeContext) {
// console.log("!change event", data.value, data.context);
value = data.value;
} else {
// console.log("!change event", data.value, data.context, "ignored!!!!!!!!!!!!");
}
// this.requestSave();
break;
}
default:
break;
}
});
const clear = () => {
send("change-value", { value: "" });
value = "";
};
const setValue = (newValue: string) => {
value = newValue;
send("change-value", { value: newValue });
};
const getValue = () => value;
const destroy = () => {
iframe.remove();
};
return {
iframe,
send,
clear,
getValue,
setValue,
destroy,
};
};