const view = new lsp.EditorView({ extensions: lsp.baseExts, parent: document.getElementById("editor") }); let doc = "xquery version '3.1';\n(:~ comment:)\nmodule namespace pdfbox='ns';\n"; var client; var extLint; function $(id) { return document.getElementById(id) }; // Load saved content from localStorage when the page loads window.addEventListener('load', () => { const savedText = localStorage.getItem('code'); if (savedText) doc = savedText; let svr = localStorage.getItem('lsp'); if (!svr) { let x = new URL(window.location.href); x.protocol = "ws"; x.pathname = "ws/lsp" svr = x.href; } $("iServer").value = svr; formFromStore('fSettings'); view.setState(lsp.EditorState.create({ doc: doc, extensions: lsp.baseExts })); lsp.updateCompartment(objectFromForm('fSettings')) connect(); }); // Save content to localStorage when the page is about to unload window.addEventListener('beforeunload', () => { const doc = view.state.doc.toString(); localStorage.setItem('code', doc); localStorage.setItem('lsp', $("iServer").value); }); $("connect").onclick = e => { e.preventDefault(); connect() }; $("search").onclick = e => lsp.openSearchPanel(view); $("fullscreen").onclick = e => $("editor").requestFullscreen(); $("wordAt").onclick = e => { let pos = view.state.selection.main.head; let w = view.state.wordAt(pos); alert("wordAt " + JSON.stringify(w)); }; $("symbols2").onclick = e => { client.sync(); client.request("textDocument/documentSymbol", { "textDocument": { "uri": $("iFile").value } }) .then(r => { console.log("symbols", r) $("symPanel").open = true; const icons = [ 'symbol-file', 'symbol-class', 'symbol-namespace', 'symbol-structure', 'symbol-class', 'symbol-method', 'symbol-property', 'symbol-field', 'symbol-method-arrow', 'symbol-enum', 'symbol-interface', 'symbol-method', 'symbol-variable', 'symbol-constant', 'symbol-string', 'symbol-numeric', 'symbol-boolean', 'symbol-array', 'symbol-structure', 'symbol-key', 'dash', 'symbol-enum-member', 'symbol-misc', 'symbol-event', 'symbol-operator', 'symbol-parameter' ]; $("symList").setData(r, icons); }); }; $("cmd").onclick = e => { let cmds = lsp.listCommands(view); let result=""; [...cmds.keys()].sort().forEach(key => { result+=`
  • ${key} ${cmds.get(key).key}
  • ` }); $("popHelpInfo").innerHTML=`` $("popHelp").showPopover() console.log(result) }; $("symList").addEventListener("itemSelected", e => { const sel=e.detail.selectionRange; console.log("SYM selection range",sel); const an=17*e.detail.kind view.dispatch({selection: {anchor: an,head:an+34},scrollIntoView:true}); }); $("lint").onclick = async e => { console.log("word", view.state.wordAt(1)); lsp.openLintPanel(view); }; $("sync").onclick = e => { client.sync(); console.log("XXXsync"); }; $("format").onclick = e => { console.log("FMT", lsp.formatDocument(view)); }; $("load").onchange = e => { const url = e.target.value; if (url.length == 0) return fetch(url) .then(response => response.text()) .then(t => { view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: t } }) //client.sync(); //console.log("SYNC"); }); $("load").value = ""; }; function updateSettings(event) { event.preventDefault(); console.log("COPTS", lsp.curOpts); const opts = { lineWrap: $("lineWrap").checked, minimap: $("minimap").checked } console.log(opts) lsp.updateCompartment(opts); $('popSettings').hidePopover(); formToStore("fSettings"); }; $("fSettings").addEventListener("submit", updateSettings); function connect() { const server = $("iServer").value; const file = $("iFile").value; lsp.simpleWebSocketTransport(server) .then(transport => { transport.socket.onclose = (event) => connectStatus(false); transport.socket.oneror = (event) => $("msg").innerText = "sock error!"; transport.subscribe(incoming); client = new lsp.LSPClient({ extensions: lsp.languageServerExtensions() }); client.connect(transport); $("popConnect").hidePopover(); connectStatus(true); let extLsp = client.plugin(file, "xquery"); view.dispatch({ effects: lsp.StateEffect.appendConfig.of( [lsp.linter(null, { autoPanel: true }), ...extLsp, lsp.keymap.of([...lsp.formatKeymap])]) }) }) .catch(e => { console.log(e); connectStatus(false); alert("connection failed: " + server) }); }; function connectStatus(bool) { if (bool) { $("popcon").querySelector("i").classList.value = "codicon codicon-vm-active"; $("popcon").classList.remove("btn-danger") $("popcon").classList.add("btn-success") } else { $("popcon").querySelector("i").classList.value = "codicon codicon-vm-outline"; $("popcon").classList.add("btn-danger") $("popcon").classList.remove("btn-success") } }; function incoming(msg) { const rpc = JSON.parse(msg); log(rpc); }; function log(rpc) { console.log("<-", rpc) if (rpc.id) return const text = rpc.method; const li = document.createElement("li"); const n = $("traffic").childElementCount + " "; li.appendChild(document.createTextNode(n + text)); $("traffic").insertBefore(li, $("traffic").firstChild) }; function formFromStore(name) { let v = localStorage.getItem(name) if (!!v) formDeserialize($(name), v); }; function formToStore(name) { localStorage.setItem(name, formSerialize($(name))); }; function objectFromForm(name) { const data = new FormData($(name)); //https://stackabuse.com/convert-form-data-to-javascript-object/ return Object.fromEntries(data.entries()); } function formSerialize(form) { const data = new FormData(form); //https://stackoverflow.com/a/44033425/1869660 return new URLSearchParams(data).toString(); } function formDeserialize(form, data) { const entries = (new URLSearchParams(data)).entries(); for (const [key, val] of entries) { //http://javascript-coder.com/javascript-form/javascript-form-value.phtml const input = form.elements[key]; switch (input.type) { case 'checkbox': input.checked = !!val; break; default: input.value = val; break; } } }