Refactor code language and ts types (#9300)

* 🎨 Code block language list adds custom languages

* Update index.d.ts

* 🎨 Improve global variable type definition

* 🎨 Improve global variable type definition

* 🎨 Add constant `EXTRA_CODE_LANGUAGES`
This commit is contained in:
Yingyi / 颖逸 2023-09-28 22:38:49 +08:00 committed by GitHub
parent 17d2a16a94
commit b2a27bb54c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 86 additions and 72 deletions

View file

@ -541,9 +541,13 @@ export abstract class Constants {
public static readonly INLINE_TYPE: string[] = ["block-ref", "kbd", "text", "file-annotation-ref", "a", "strong", "em", "u", "s", "mark", "sup", "sub", "tag", "code", "inline-math", "inline-memo"];
public static readonly BLOCK_HINT_KEYS: string[] = ["((", "[[", "", "【【"];
public static readonly BLOCK_HINT_CLOSE_KEYS: IObject = {"((": "))", "[[": "]]", "": "", "【【": "】】"};
public static readonly CODE_LANGUAGES: string[] = [
public static readonly EXTRA_CODE_LANGUAGES: string[] = [
// 同名
"js", "ts", "html", "toml", "c#", "bat",
];
public static readonly CODE_LANGUAGES: string[] = [
// 附加
...Constants.EXTRA_CODE_LANGUAGES,
// common
"bash", "c", "csharp", "cpp", "css", "diff", "go", "xml", "json", "java", "javascript", "kotlin", "less", "lua", "makefile", "markdown", "objectivec", "php", "php-template", "perl", "plaintext", "python", "python-repl", "r", "ruby", "rust", "scss", "sql", "shell", "swift", "ini", "typescript", "vbnet", "yaml", "properties", "1c", "armasm", "avrasm", "actionscript", "ada", "angelscript", "accesslog", "apache", "applescript", "arcade", "arduino", "asciidoc", "aspectj", "abnf", "autohotkey", "autoit", "awk", "basic", "bnf", "dos", "brainfuck", "cal", "cmake", "csp", "cos", "capnproto", "ceylon", "clean", "clojure", "clojure-repl", "coffeescript", "coq", "crystal", "d", "dns", "dart", "delphi", "dts", "django", "dockerfile", "dust", "erb", "elixir", "elm", "erlang", "erlang-repl", "excel", "ebnf", "fsharp", "fix", "flix", "fortran", "gcode", "gams", "gauss", "glsl", "gml", "gherkin", "golo", "gradle", "groovy", "haml", "hsp", "http", "handlebars", "haskell", "haxe", "hy", "irpf90", "isbl", "inform7", "x86asm", "jboss-cli", "julia", "julia-repl", "ldif", "llvm", "lsl", "latex", "lasso", "leaf", "lisp", "livecodeserver", "livescript", "mel", "mipsasm", "matlab", "maxima", "mercury", "axapta", "routeros", "mizar", "mojolicious", "monkey", "moonscript", "n1ql", "nsis", "nestedtext", "nginx", "nim", "nix", "node-repl", "ocaml", "openscad", "ruleslanguage", "oxygene", "pf", "parser3", "pony", "pgsql", "powershell", "processing", "prolog", "protobuf", "puppet", "purebasic", "profile", "q", "qml", "reasonml", "rib", "rsl", "roboconf", "sas", "sml", "sqf", "step21", "scala", "scheme", "scilab", "smali", "smalltalk", "stan", "stata", "stylus", "subunit", "tp", "taggerscript", "tcl", "tap", "thrift", "twig", "vbscript", "vbscript-html", "vhdl", "vala", "verilog", "vim", "wasm", "mathematica", "wren", "xl", "xquery", "zephir", "crmsh", "dsconfig", "graphql",
// third

View file

@ -1218,7 +1218,7 @@ export class Gutter {
updateTransaction(protyle, id, nodeElement.outerHTML, html);
html = nodeElement.outerHTML;
event.stopPropagation();
const chartInstance = echarts.getInstanceById(nodeElement.firstElementChild.nextElementSibling.getAttribute("_echarts_instance_"));
const chartInstance = window.echarts.getInstanceById(nodeElement.firstElementChild.nextElementSibling.getAttribute("_echarts_instance_"));
if (chartInstance) {
chartInstance.resize();
}

View file

@ -58,7 +58,7 @@ export const previewDocImage = (src: string, id: string) => {
});
imagesElement.innerHTML = html;
// @ts-ignore
window.siyuan.viewer = new Viewer(imagesElement, {
window.siyuan.viewer = new window.Viewer(imagesElement, {
title: [1, (image: HTMLImageElement, imageData: IObject) => {
let name = image.alt;
if (!name) {

View file

@ -2,10 +2,6 @@ import {addScript} from "../util/addScript";
import {Constants} from "../../constants";
import {genIconHTML} from "./util";
declare const ABCJS: {
renderAbc(element: Element, text: string, options: { responsive: string }): void;
};
export const abcRender = (element: Element, cdn = Constants.PROTYLE_CDN) => {
let abcElements: Element[] = [];
if (element.getAttribute("data-subtype") === "abc") {
@ -30,7 +26,7 @@ export const abcRender = (element: Element, cdn = Constants.PROTYLE_CDN) => {
e.lastElementChild.insertAdjacentHTML("beforebegin", `<span style="position: absolute">${Constants.ZWSP}</span>`);
}
const renderElement = e.firstElementChild.nextElementSibling as HTMLElement;
ABCJS.renderAbc(renderElement, Lute.UnEscapeHTMLStr(e.getAttribute("data-content")), {
window.ABCJS.renderAbc(renderElement, Lute.UnEscapeHTMLStr(e.getAttribute("data-content")), {
responsive: "resize"
});
renderElement.setAttribute("contenteditable", "false");

View file

@ -41,14 +41,14 @@ export const chartRender = (element: Element, cdn = Constants.PROTYLE_CDN) => {
try {
renderElement.style.height = e.style.height;
const option = await looseJsonParse(Lute.UnEscapeHTMLStr(e.getAttribute("data-content")));
echarts.init(renderElement, window.siyuan.config.appearance.mode === 1 ? "dark" : undefined, {width}).setOption(option);
window.echarts.init(renderElement, window.siyuan.config.appearance.mode === 1 ? "dark" : undefined, {width}).setOption(option);
e.setAttribute("data-render", "true");
renderElement.classList.remove("ft__error");
if (!renderElement.textContent.endsWith(Constants.ZWSP)) {
renderElement.firstElementChild.insertAdjacentText("beforeend", Constants.ZWSP);
}
} catch (error) {
echarts.dispose(renderElement);
window.echarts.dispose(renderElement);
renderElement.classList.add("ft__error");
renderElement.innerHTML = `echarts render error: <br>${error}`;
}

View file

@ -2,12 +2,6 @@ import {addScript} from "../util/addScript";
import {Constants} from "../../constants";
import {genIconHTML} from "./util";
declare class Viz {
public renderSVGElement: (code: string) => Promise<any>;
constructor(worker: { worker: Worker });
}
export const graphvizRender = (element: Element, cdn = Constants.PROTYLE_CDN) => {
let graphvizElements: Element[] = [];
if (element.getAttribute("data-subtype") === "graphviz") {
@ -34,7 +28,7 @@ export const graphvizRender = (element: Element, cdn = Constants.PROTYLE_CDN) =>
const url = window.URL || window.webkitURL;
const blobUrl = url.createObjectURL(blob);
const worker = new Worker(blobUrl);
new Viz({worker})
new window.Viz({worker})
.renderSVGElement(Lute.UnEscapeHTMLStr(e.getAttribute("data-content"))).then((result: HTMLElement) => {
renderElement.innerHTML = result.outerHTML;
renderElement.classList.remove("ft__error");

View file

@ -66,7 +66,7 @@ export const highlightRender = (element: Element, cdn = Constants.PROTYLE_CDN) =
// bazaar readme
language = block.className.replace("language-", "");
}
if (!hljs.getLanguage(language)) {
if (!window.hljs.getLanguage(language)) {
language = "plaintext";
}
block.classList.add("hljs");
@ -110,7 +110,7 @@ export const highlightRender = (element: Element, cdn = Constants.PROTYLE_CDN) =
matchElement.scrollIntoView();
}
}
block.innerHTML = hljs.highlight(
block.innerHTML = window.hljs.highlight(
block.textContent + (block.textContent.endsWith("\n") ? "" : "\n"), // https://github.com/siyuan-note/siyuan/issues/4609
{
language,

View file

@ -4,16 +4,6 @@ import {Constants} from "../../constants";
import {hasNextSibling, hasPreviousSibling} from "../wysiwyg/getBlock";
import {hasClosestBlock} from "../util/hasClosest";
declare const katex: {
renderToString(math: string, option: {
displayMode: boolean;
output: string;
macros: IObject;
trust: boolean;
strict: (errorCode:string) => "ignore" | "warn";
}): string;
};
export const mathRender = (element: Element, cdn = Constants.PROTYLE_CDN, maxWidth = false) => {
let mathElements: Element[] = [];
if (element.getAttribute("data-subtype") === "math") {
@ -44,7 +34,7 @@ export const mathRender = (element: Element, cdn = Constants.PROTYLE_CDN, maxWid
console.warn("KaTex macros is not JSON", e);
}
try {
renderElement.innerHTML = katex.renderToString(Lute.UnEscapeHTMLStr(mathElement.getAttribute("data-content")), {
renderElement.innerHTML = window.katex.renderToString(Lute.UnEscapeHTMLStr(mathElement.getAttribute("data-content")), {
displayMode: mathElement.tagName === "DIV",
output: "html",
macros,

View file

@ -2,11 +2,6 @@ import {addScript} from "../util/addScript";
import {Constants} from "../../constants";
import {hasClosestByAttribute} from "../util/hasClosest";
declare const mermaid: {
initialize(options: any): void,
init(options: any, element: Element): void
};
export const mermaidRender = (element: Element, cdn = Constants.PROTYLE_CDN) => {
let mermaidElements: Element[] = [];
if (element.getAttribute("data-subtype") === "mermaid") {
@ -43,7 +38,7 @@ export const mermaidRender = (element: Element, cdn = Constants.PROTYLE_CDN) =>
if (window.siyuan.config.appearance.mode === 1) {
config.theme = "dark";
}
mermaid.initialize(config);
window.mermaid.initialize(config);
if (mermaidElements[0].firstElementChild.clientWidth === 0) {
const hideElement = hasClosestByAttribute(mermaidElements[0], "fold", "1");
if (!hideElement) {
@ -75,7 +70,7 @@ const initMermaid = (mermaidElements: Element[]) => {
renderElement.removeAttribute("data-processed");
renderElement.textContent = Lute.UnEscapeHTMLStr(item.getAttribute("data-content"));
setTimeout(() => {
mermaid.init(undefined, renderElement);
window.mermaid.init(undefined, renderElement);
}, Constants.TIMEOUT_LOAD * index);
item.setAttribute("data-render", "true");
renderElement.setAttribute("contenteditable", "false");

View file

@ -37,7 +37,7 @@ export const mindmapRender = (element: Element, cdn = Constants.PROTYLE_CDN) =>
const renderElement = e.firstElementChild.nextElementSibling as HTMLElement;
try {
renderElement.style.height = e.style.height;
echarts.init(renderElement, window.siyuan.config.appearance.mode === 1 ? "dark" : undefined, {
window.echarts.init(renderElement, window.siyuan.config.appearance.mode === 1 ? "dark" : undefined, {
width,
}).setOption({
series: [

View file

@ -2,10 +2,6 @@ import {addScript} from "../util/addScript";
import {Constants} from "../../constants";
import {genIconHTML} from "./util";
declare const plantumlEncoder: {
encode(options: string): string,
};
export const plantumlRender = (element: Element, cdn = Constants.PROTYLE_CDN) => {
let plantumlElements: Element[] = [];
if (element.getAttribute("data-subtype") === "plantuml") {
@ -27,7 +23,7 @@ export const plantumlRender = (element: Element, cdn = Constants.PROTYLE_CDN) =>
}
const renderElement = e.firstElementChild.nextElementSibling as HTMLElement;
try {
renderElement.innerHTML = `<img src=${window.siyuan.config.editor.plantUMLServePath}${plantumlEncoder.encode(Lute.UnEscapeHTMLStr(e.getAttribute("data-content")))}">`;
renderElement.innerHTML = `<img src=${window.siyuan.config.editor.plantUMLServePath}${window.plantumlEncoder.encode(Lute.UnEscapeHTMLStr(e.getAttribute("data-content")))}">`;
renderElement.classList.remove("ft__error");
e.setAttribute("data-render", "true");
} catch (error) {

View file

@ -1145,10 +1145,16 @@ export class Toolbar {
this.range = getEditorRange(nodeElement);
const id = nodeElement.getAttribute("data-node-id");
let oldHtml = nodeElement.outerHTML;
let html = `<div class="b3-list-item b3-list-item--focus">${window.siyuan.languages.clear}</div>`;
Constants.CODE_LANGUAGES.forEach((item) => {
html += `<div class="b3-list-item">${item}</div>`;
});
const languages = Array.from(new Set<string>([
...Constants.EXTRA_CODE_LANGUAGES,
...(window.hljs?.listLanguages() ?? []),
])).sort();
const html = [
`<div class="b3-list-item b3-list-item--focus">${window.siyuan.languages.clear}</div>`,
...languages.map(item => `<div class="b3-list-item">${item}</div>`),
].join("\n");
this.subElement.style.width = "";
this.subElement.style.padding = "";
this.subElement.innerHTML = `<div class="fn__flex-column" style="max-height:50vh"><input placeholder="${window.siyuan.languages.search}" style="margin: 0 8px 4px 8px" class="b3-text-field"/>
@ -1189,18 +1195,13 @@ export class Toolbar {
}
});
inputElement.addEventListener("input", (event) => {
const matchLanguages: string[] = [];
Constants.CODE_LANGUAGES.forEach((item) => {
if (item.indexOf(inputElement.value.toLowerCase()) > -1) {
matchLanguages.push(item);
}
});
const lowerCaseValue = inputElement.value.toLowerCase();
const matchLanguages = languages.filter(item => item.includes(lowerCaseValue));
let html = "";
// sort
let matchInput = false;
matchLanguages.sort((a, b) => {
if (a.startsWith(inputElement.value.toLowerCase()) && b.startsWith(inputElement.value.toLowerCase())) {
if (a.startsWith(lowerCaseValue) && b.startsWith(lowerCaseValue)) {
if (a.length < b.length) {
return -1;
} else if (a.length === b.length) {
@ -1208,9 +1209,9 @@ export class Toolbar {
} else {
return 1;
}
} else if (a.startsWith(inputElement.value.toLowerCase())) {
} else if (a.startsWith(lowerCaseValue)) {
return -1;
} else if (b.startsWith(inputElement.value.toLowerCase())) {
} else if (b.startsWith(lowerCaseValue)) {
return 1;
} else {
return 0;
@ -1219,7 +1220,7 @@ export class Toolbar {
if (inputElement.value === item) {
matchInput = true;
}
html += `<div class="b3-list-item">${item.replace(inputElement.value.toLowerCase(), "<b>" + inputElement.value.toLowerCase() + "</b>")}</div>`;
html += `<div class="b3-list-item">${item.replace(lowerCaseValue, "<b>" + lowerCaseValue + "</b>")}</div>`;
});
if (inputElement.value.trim() && !matchInput) {
html = `<div class="b3-list-item"><b>${inputElement.value.replace(/`| /g, "_")}</b></div>${html}`;

View file

@ -11,9 +11,9 @@ export const resize = (protyle: IProtyle) => {
// 不能 clearTimeout否则 split 时左侧无法 resize
setTimeout(() => {
if (abs.width > MIN_ABS || isNaN(abs.width)) {
if (typeof echarts !== "undefined") {
if (typeof window.echarts !== "undefined") {
protyle.wysiwyg.element.querySelectorAll('[data-subtype="echarts"], [data-subtype="mindmap"]').forEach((chartItem: HTMLElement) => {
const chartInstance = echarts.getInstanceById(chartItem.firstElementChild.nextElementSibling.getAttribute("_echarts_instance_"));
const chartInstance = window.echarts.getInstanceById(chartItem.firstElementChild.nextElementSibling.getAttribute("_echarts_instance_"));
if (chartInstance) {
chartInstance.resize();
}

View file

@ -1579,10 +1579,10 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => {
}
const insertElement = document.createElement("span");
let language = nodeElement.querySelector(".protyle-action__language").textContent;
if (!hljs.getLanguage(language)) {
if (!window.hljs.getLanguage(language)) {
language = "plaintext";
}
insertElement.innerHTML = hljs.highlight(text.substr(0, text.length - 1), {
insertElement.innerHTML = window.hljs.highlight(text.substr(0, text.length - 1), {
language,
ignoreIllegals: true
}).value;

View file

@ -81,6 +81,15 @@ type TAVFilterOperator =
declare module "blueimp-md5"
interface Window {
ABCJS?: IABCJS
Viewer?: Function
Viz?: IViz
echarts?: IECharts
hljs?: IHLJS
katex?: IKaTeX
mermaid?: IMermaid
plantumlEncoder?: IPlantumlEncoder
pdfjsLib: any
dataLayer: any[]
siyuan: ISiyuan

View file

@ -1,15 +1,13 @@
declare const echarts: {
init(element: HTMLElement, theme?: string, options?: { width: number }): IEChart;
dispose(element: Element): void;
getInstanceById(id: string): { resize: () => void };
};
interface IABCJS {
renderAbc(element: Element, text: string, options: { responsive: string }): void;
}
declare const hljs: {
highlight(text: string, options: { language?: string, ignoreIllegals: boolean }): { value: string };
getLanguage(text: string): { name: string };
};
interface IViz {
new(worker: { worker: Worker }): IViz;
renderSVGElement: (code: string) => Promise<any>;
}
interface IEChart {
interface IEChartsInstance {
setOption(option: any): void;
getZr(): any;
@ -21,6 +19,37 @@ interface IEChart {
resize(): void;
}
interface IECharts {
init(element: HTMLElement, theme?: string, options?: { width: number }): IEChartsInstance;
dispose(element: Element): void;
getInstanceById(id: string): { resize: () => void };
}
interface IHLJS {
highlight(text: string, options: { language?: string, ignoreIllegals: boolean }): { value: string };
getLanguage(text: string): { name: string };
listLanguages(): string[];
}
interface IKaTeX {
renderToString(math: string, option: {
displayMode: boolean;
output: string;
macros: IObject;
trust: boolean;
strict: (errorCode: string) => "ignore" | "warn";
}): string;
}
interface IMermaid {
initialize(options: any): void;
init(options: any, element: Element): void;
}
interface IPlantumlEncoder {
encode(options: string): string;
}
interface ILuteNode {
TokensStr: () => string;
__internal_object__: {