online_editor: Make outline widget print some data

This commit is contained in:
Tobias Hunger 2022-10-19 15:25:41 +02:00 committed by Tobias Hunger
parent ec79a98d0d
commit c629c4ab62
3 changed files with 160 additions and 8 deletions

View file

@ -109,8 +109,9 @@ class EditorPaneWidget extends Widget {
monaco.editor.ICodeEditorViewState | null | undefined
>;
#editor: monaco.editor.IStandaloneCodeEditor | null;
#keystroke_timeout_handle: number | undefined;
#base_url: string | undefined;
#client?: MonacoLanguageClient;
#keystroke_timeout_handle?: number;
#base_url?: string;
#edit_era: number;
#disposables: monaco.IDisposable[] = [];
#current_properties = "";
@ -184,6 +185,14 @@ class EditorPaneWidget extends Widget {
return commands.getCommands();
}
get language_client(): MonacoLanguageClient | undefined {
return this.#client;
}
get current_text_document_uri(): string | undefined {
return this.#editor?.getModel()?.uri.toString();
}
compile() {
this.update_preview();
}
@ -448,11 +457,14 @@ class EditorPaneWidget extends Widget {
);
const writer = new BrowserMessageWriter(lsp_worker);
const languageClient = createLanguageClient({ reader, writer });
this.#client = createLanguageClient({ reader, writer });
languageClient.start();
this.#client.start();
reader.onClose(() => languageClient.stop());
reader.onClose(() => {
this.#client.stop();
this.#client = null;
});
resolve_lsp_worker_promise();
}
@ -608,6 +620,14 @@ export class EditorWidget extends Widget {
return this.#editor.current_editor_content;
}
get language_client(): MonacoLanguageClient | undefined {
return this.#editor.language_client;
}
get current_text_document_uri(): string | undefined {
return this.#editor.current_text_document_uri;
}
compile() {
this.#editor.compile();
}

View file

@ -310,7 +310,9 @@ function main() {
],
[
() => {
return new OutlineWidget();
return new OutlineWidget(() => {
return [editor.language_client, editor.current_text_document_uri];
});
},
{ mode: "tab-after", ref: "Welcome" },
],

View file

@ -6,7 +6,79 @@
import { Message } from "@lumino/messaging";
import { Widget } from "@lumino/widgets";
import { MonacoLanguageClient } from "monaco-languageclient";
import {
DocumentSymbolRequest,
DocumentSymbolParams,
DocumentSymbol,
SymbolInformation,
} from "vscode-languageserver-protocol";
const SYMBOL_KIND_MAP = [
"kind-unknown",
"kind-file",
"kind-module",
"kind-namespace",
"kind-package",
"kind-class",
"kind-method",
"kind-property",
"kind-field",
"kind-constructor",
"kind-enum",
"kind-interface",
"kind-function",
"kind-variable",
"kind-constant",
"kind-string",
"kind-number",
"kind-boolean",
"kind-array",
"kind-object",
"kind-key",
"kind-null",
"kind-enum-member",
"kind-struct",
"kind-event",
"kind-operator",
"kind-type-parameter",
];
function set_data(
data: DocumentSymbol[],
indent: number,
table: HTMLTableElement,
) {
for (const d of data) {
const row = document.createElement("tr");
row.className = "outline-element";
if (d.deprecated || (d.tags != null && 1 in d.tags)) {
row.classList.add("deprecated");
}
if (d.kind >= SYMBOL_KIND_MAP.length || d.kind < 1) {
row.classList.add(SYMBOL_KIND_MAP[0]);
} else {
row.classList.add(SYMBOL_KIND_MAP[d.kind]);
}
row.classList.add("indent-" + indent);
const cell = document.createElement("td");
cell.innerText = d.name;
row.appendChild(cell);
table.appendChild(row);
if (d.children != null) {
set_data(d.children, indent + 1, table);
}
}
}
export class OutlineWidget extends Widget {
#callback: () => [MonacoLanguageClient | undefined, string | undefined];
#intervalId = -1;
static createNode(): HTMLElement {
const node = document.createElement("div");
const content = document.createElement("div");
@ -14,17 +86,75 @@ export class OutlineWidget extends Widget {
return node;
}
constructor() {
constructor(
callback: () => [MonacoLanguageClient | undefined, string | undefined],
) {
super({ node: OutlineWidget.createNode() });
this.#callback = callback;
this.setFlag(Widget.Flag.DisallowLayout);
this.addClass("content");
this.addClass("outline".toLowerCase());
this.addClass("outline");
this.title.label = "Document Outline";
this.title.closable = true;
this.title.caption = `Document Outline`;
this.#intervalId = window.setInterval(() => {
const [client, uri] = this.#callback();
if (client != null && uri != null) {
client
.sendRequest(DocumentSymbolRequest.type, {
textDocument: { uri: uri },
} as DocumentSymbolParams)
.then((r: DocumentSymbol[] | SymbolInformation[] | null) =>
this.update_data(r),
);
} else {
if (uri == null) {
// No document is open
this.clear_data();
} else {
this.set_error("Language server not available");
}
}
}, 5000);
}
protected get contentNode(): HTMLDivElement {
return this.node.getElementsByTagName("div")[0] as HTMLDivElement;
}
protected update_data(data: DocumentSymbol[] | SymbolInformation[] | null) {
if (data == null) {
this.set_error("No data received");
return;
}
if (data.length > 0 && "location" in data[0]) {
// location is a required key in SymbolInformation that does not exist in DocumentSymbol
this.set_error("Invalid data format received");
return;
}
const table = document.createElement("table");
table.className = "outline-table";
set_data(data as DocumentSymbol[], 0, table);
this.clear_data();
this.contentNode.appendChild(table);
}
protected clear_data() {
this.contentNode.innerText = "";
}
protected set_error(message: string) {
this.contentNode.innerHTML = '<div class="error">' + message + "</div>";
}
protected onCloseRequest(msg: Message): void {
if (this.#intervalId !== -1) {
clearInterval(this.#intervalId);
this.#intervalId = -1;
}
super.onCloseRequest(msg);
this.dispose();
}