[mod] wsl

This commit is contained in:
Andy Bunce 2025-11-11 15:36:33 +00:00
parent b741dc5952
commit ddd772f563
69 changed files with 26660 additions and 25940 deletions

View file

@ -1,137 +1,137 @@
import { EditorState, StateEffect, Compartment } from '@codemirror/state';
import {
lineNumbers, highlightActiveLineGutter, highlightWhitespace,
drawSelection, rectangularSelection, crosshairCursor, highlightActiveLine,
keymap, dropCursor, EditorView,tooltips
} from '@codemirror/view';
import { openSearchPanel, highlightSelectionMatches, searchKeymap } from '@codemirror/search';
import { openLintPanel, lintGutter, lintKeymap, linter } from "@codemirror/lint"
import { indentWithTab, history, defaultKeymap, historyKeymap } from '@codemirror/commands';
import {
foldGutter, indentOnInput, indentUnit, bracketMatching, foldKeymap,
syntaxHighlighting, defaultHighlightStyle, StreamLanguage
} from '@codemirror/language';
import { closeBrackets, autocompletion, closeBracketsKeymap, completionKeymap } from '@codemirror/autocomplete';
import {
LSPClient, LSPPlugin, languageServerSupport, languageServerExtensions,
formatDocument, formatKeymap
} from "@codemirror/lsp-client";
import { xQuery } from "@codemirror/legacy-modes/mode/xquery"
// Language
import { xml } from "@codemirror/lang-xml";
import { showMinimap } from "@replit/codemirror-minimap"
let create = (v) => {
const dom = document.createElement('div');
return { dom }
}
const compartment = new Compartment();
let curOpts = {
lineWrap: true,
minimap: true,
highlightWhitespace: true
}
// array of extensions reflecting opts
function optExts(opts) {
let exts = []
if (opts.lineWrap) exts.push(EditorView.lineWrapping)
if (opts.highlightWhitespace) exts.push(highlightWhitespace())
if (opts.minimap) exts.push(
showMinimap.compute(['doc'], (state) => {
return {
create,
/* optional showOverlay: 'mouse-over' */
displayText: 'characters'
}
}));
return exts
}
function updateCompartment(opts) {
view.dispatch({
effects: [compartment.reconfigure(optExts(opts))]
});
}
// return promise with socket map or reject if no connect
function simpleWebSocketTransport(uri) {
let handlers = [];
return new Promise(function (resolve, reject) {
let sock = new WebSocket(uri);
sock.onmessage = e => { for (let h of handlers) h(e.data.toString()); };
sock.onerror = e => reject(e);
sock.onopen = () => resolve({
socket: sock,
send: (message) => sock.send(message),
subscribe: (handler) => handlers.push(handler),
unsubscribe: (handler) => handlers = handlers.filter(h => h != handler)
});
}
);
};
const baseExts = [
lineNumbers(),
highlightActiveLineGutter(),
history(),
foldGutter(),
lintGutter(),
drawSelection(),
dropCursor(),
EditorState.allowMultipleSelections.of(true),
tooltips({ }), // clipped
keymap.of([indentWithTab]),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
bracketMatching(),
closeBrackets(),
autocompletion(),
rectangularSelection(),
crosshairCursor(),
highlightActiveLine(),
highlightSelectionMatches(),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...searchKeymap,
...historyKeymap,
...foldKeymap,
...completionKeymap,
...lintKeymap
]),
StreamLanguage.define(xQuery),
compartment.of(optExts(curOpts))
];
// map cmd->{keybings,fn}
function listCommands(view) {
const commands = new Map();
const keymaps = view.state.facet(keymap);
for (let km of keymaps) {
for (let binding of km) {
if (binding.run && binding.run.name) {
commands.set(binding.run.name, { key: binding.key, fn: binding.run });
}
}
}
return commands;
};
export {
baseExts, EditorView, EditorState, StateEffect, LSPPlugin, LSPClient,
openSearchPanel, openLintPanel, languageServerSupport, languageServerExtensions,
simpleWebSocketTransport, linter, formatDocument, keymap, formatKeymap, listCommands, updateCompartment, curOpts
import { EditorState, StateEffect, Compartment } from '@codemirror/state';
import {
lineNumbers, highlightActiveLineGutter, highlightWhitespace,
drawSelection, rectangularSelection, crosshairCursor, highlightActiveLine,
keymap, dropCursor, EditorView,tooltips
} from '@codemirror/view';
import { openSearchPanel, highlightSelectionMatches, searchKeymap } from '@codemirror/search';
import { openLintPanel, lintGutter, lintKeymap, linter } from "@codemirror/lint"
import { indentWithTab, history, defaultKeymap, historyKeymap } from '@codemirror/commands';
import {
foldGutter, indentOnInput, indentUnit, bracketMatching, foldKeymap,
syntaxHighlighting, defaultHighlightStyle, StreamLanguage
} from '@codemirror/language';
import { closeBrackets, autocompletion, closeBracketsKeymap, completionKeymap } from '@codemirror/autocomplete';
import {
LSPClient, LSPPlugin, languageServerSupport, languageServerExtensions,
formatDocument, formatKeymap
} from "@codemirror/lsp-client";
import { xQuery } from "@codemirror/legacy-modes/mode/xquery"
// Language
import { xml } from "@codemirror/lang-xml";
import { showMinimap } from "@replit/codemirror-minimap"
let create = (v) => {
const dom = document.createElement('div');
return { dom }
}
const compartment = new Compartment();
let curOpts = {
lineWrap: true,
minimap: true,
highlightWhitespace: true
}
// array of extensions reflecting opts
function optExts(opts) {
let exts = []
if (opts.lineWrap) exts.push(EditorView.lineWrapping)
if (opts.highlightWhitespace) exts.push(highlightWhitespace())
if (opts.minimap) exts.push(
showMinimap.compute(['doc'], (state) => {
return {
create,
/* optional showOverlay: 'mouse-over' */
displayText: 'characters'
}
}));
return exts
}
function updateCompartment(opts) {
view.dispatch({
effects: [compartment.reconfigure(optExts(opts))]
});
}
// return promise with socket map or reject if no connect
function simpleWebSocketTransport(uri) {
let handlers = [];
return new Promise(function (resolve, reject) {
let sock = new WebSocket(uri);
sock.onmessage = e => { for (let h of handlers) h(e.data.toString()); };
sock.onerror = e => reject(e);
sock.onopen = () => resolve({
socket: sock,
send: (message) => sock.send(message),
subscribe: (handler) => handlers.push(handler),
unsubscribe: (handler) => handlers = handlers.filter(h => h != handler)
});
}
);
};
const baseExts = [
lineNumbers(),
highlightActiveLineGutter(),
history(),
foldGutter(),
lintGutter(),
drawSelection(),
dropCursor(),
EditorState.allowMultipleSelections.of(true),
tooltips({ }), // clipped
keymap.of([indentWithTab]),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
bracketMatching(),
closeBrackets(),
autocompletion(),
rectangularSelection(),
crosshairCursor(),
highlightActiveLine(),
highlightSelectionMatches(),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...searchKeymap,
...historyKeymap,
...foldKeymap,
...completionKeymap,
...lintKeymap
]),
StreamLanguage.define(xQuery),
compartment.of(optExts(curOpts))
];
// map cmd->{keybings,fn}
function listCommands(view) {
const commands = new Map();
const keymaps = view.state.facet(keymap);
for (let km of keymaps) {
for (let binding of km) {
if (binding.run && binding.run.name) {
commands.set(binding.run.name, { key: binding.key, fn: binding.run });
}
}
}
return commands;
};
export {
baseExts, EditorView, EditorState, StateEffect, LSPPlugin, LSPClient,
openSearchPanel, openLintPanel, languageServerSupport, languageServerExtensions,
simpleWebSocketTransport, linter, formatDocument, keymap, formatKeymap, listCommands, updateCompartment, curOpts
};

View file

@ -1,41 +1,41 @@
import {basicSetup, EditorView} from "codemirror"
import { EditorState } from '@codemirror/state';
import { LSPClient, LSPPlugin, languageServerSupport } from "@codemirror/lsp-client";
import {StreamLanguage} from "@codemirror/language"
import { xQuery } from "@codemirror/legacy-modes/mode/xquery"
function simpleWebSocketTransport(uri) {
let handlers = [];
return new Promise(function (resolve, reject) {
let sock = new WebSocket(uri);
sock.onmessage = e => { for (let h of handlers) h(e.data.toString()); };
sock.onerror = e => reject(e);
sock.onopen = () => resolve({
socket: sock,
send: (message) => sock.send(message),
subscribe: (handler) => handlers.push(handler),
unsubscribe: (handler) => handlers = handlers.filter(h => h != handler)
});
}
);
};
simpleWebSocketTransport("ws://localhost:3000/ws/lsp")
.then(transport => {
client = new LSPClient().connect(transport);
let extLsp = languageServerSupport(client, file, "xquery");
const doc = view.state.doc.toString();
const state = lsp.createEditorState(doc, [...lsp.baseExts, extLsp, extLint]);
view.setState(state);
})
.catch(r => { alert("connection failed: " + server) });
new EditorView({
doc: "xquery version '3.1';\n(:~ comment:)\nmodule namespace pdfbox='ns';\n",
extensions: [basicSetup, StreamLanguage.define(xQuery)],
parent: document.body
import {basicSetup, EditorView} from "codemirror"
import { EditorState } from '@codemirror/state';
import { LSPClient, LSPPlugin, languageServerSupport } from "@codemirror/lsp-client";
import {StreamLanguage} from "@codemirror/language"
import { xQuery } from "@codemirror/legacy-modes/mode/xquery"
function simpleWebSocketTransport(uri) {
let handlers = [];
return new Promise(function (resolve, reject) {
let sock = new WebSocket(uri);
sock.onmessage = e => { for (let h of handlers) h(e.data.toString()); };
sock.onerror = e => reject(e);
sock.onopen = () => resolve({
socket: sock,
send: (message) => sock.send(message),
subscribe: (handler) => handlers.push(handler),
unsubscribe: (handler) => handlers = handlers.filter(h => h != handler)
});
}
);
};
simpleWebSocketTransport("ws://localhost:3000/ws/lsp")
.then(transport => {
client = new LSPClient().connect(transport);
let extLsp = languageServerSupport(client, file, "xquery");
const doc = view.state.doc.toString();
const state = lsp.createEditorState(doc, [...lsp.baseExts, extLsp, extLint]);
view.setState(state);
})
.catch(r => { alert("connection failed: " + server) });
new EditorView({
doc: "xquery version '3.1';\n(:~ comment:)\nmodule namespace pdfbox='ns';\n",
extensions: [basicSetup, StreamLanguage.define(xQuery)],
parent: document.body
});

View file

@ -1,28 +1,28 @@
import * as aceBuilds from 'https://esm.run/ace-builds';
import ace from 'https://cdn.jsdelivr.net/npm/ace/+esm'
/* import 'ace-builds/src-noconflict/mode-javascript';
import 'ace-builds/src-noconflict/theme-chrome'; */
/* import {AceLanguageClient} from "ace-linters/build/ace-language-client";
const serverData = {
module: () => import("ace-linters/build/language-client"),
modes: "json|json5",
type: "socket",
socket: new WebSocket("ws://127.0.0.1:3000/ws/lsp"), // your websocket server address
}
*/
// Initialize the editor
const editor = ace.edit("editor", {
theme: "ace/theme/chrome",
mode: "ace/mode/javascript",
fontSize: "14px",
showPrintMargin: false,
useWorker: false // Disable web worker for this simple demo
});
// Create a language provider for WebSocket
//let languageProvider = AceLanguageClient.for(serverData);
import * as aceBuilds from 'https://esm.run/ace-builds';
import ace from 'https://cdn.jsdelivr.net/npm/ace/+esm'
/* import 'ace-builds/src-noconflict/mode-javascript';
import 'ace-builds/src-noconflict/theme-chrome'; */
/* import {AceLanguageClient} from "ace-linters/build/ace-language-client";
const serverData = {
module: () => import("ace-linters/build/language-client"),
modes: "json|json5",
type: "socket",
socket: new WebSocket("ws://127.0.0.1:3000/ws/lsp"), // your websocket server address
}
*/
// Initialize the editor
const editor = ace.edit("editor", {
theme: "ace/theme/chrome",
mode: "ace/mode/javascript",
fontSize: "14px",
showPrintMargin: false,
useWorker: false // Disable web worker for this simple demo
});
// Create a language provider for WebSocket
//let languageProvider = AceLanguageClient.for(serverData);
//languageProvider.registerEditor(editor);

View file

@ -1,44 +1,44 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<title>BaseX LSP</title>
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ace.js"></script>
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ext-language_tools.js"></script>
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-linters.js"></script>
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-language-client.js"></script>
</head>
<body>
<div>something</div>
<div id="editor" style="height: 100px">some text</div>
<script>
let servers = [
{
module: () => import("ace-linters/build/language-client"),
modes: "astro",
type: "socket",
socket: new WebSocket("ws://127.0.0.1:8080/ws/lsp"
//"ws://127.0.0.1:3000/exampleserver"
),
}
];
let languageProvider = AceLanguageClient.for(servers);
ace.require("ace/ext/language_tools"); //To allow autocompletion
var editor = ace.edit("editor", {
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
mode: "ace/mode/json"
});
languageProvider.registerEditor(editor);
editor.session.setMode("astro"); // mode now contains "ace/mode/javascript".
</script>
</body>
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<title>BaseX LSP</title>
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ace.js"></script>
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ext-language_tools.js"></script>
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-linters.js"></script>
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-language-client.js"></script>
</head>
<body>
<div>something</div>
<div id="editor" style="height: 100px">some text</div>
<script>
let servers = [
{
module: () => import("ace-linters/build/language-client"),
modes: "astro",
type: "socket",
socket: new WebSocket("ws://127.0.0.1:8080/ws/lsp"
//"ws://127.0.0.1:3000/exampleserver"
),
}
];
let languageProvider = AceLanguageClient.for(servers);
ace.require("ace/ext/language_tools"); //To allow autocompletion
var editor = ace.edit("editor", {
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
mode: "ace/mode/json"
});
languageProvider.registerEditor(editor);
editor.session.setMode("astro"); // mode now contains "ace/mode/javascript".
</script>
</body>
</html>

View file

@ -1,39 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Editor</title>
<style type="text/css" media="screen">
body {
overflow: hidden;
}
#editor {
margin: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
</head>
<body>
<pre id="editor">function foo(items) {
var i;
for (i = 0; i &lt; items.length; i++) {
alert("Ace Rocks " + items[i]);
}
}</pre>
<script src="src-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/twilight");
editor.session.setMode("ace/mode/javascript");
</script>
</body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Editor</title>
<style type="text/css" media="screen">
body {
overflow: hidden;
}
#editor {
margin: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
</head>
<body>
<pre id="editor">function foo(items) {
var i;
for (i = 0; i &lt; items.length; i++) {
alert("Ace Rocks " + items[i]);
}
}</pre>
<script src="src-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/twilight");
editor.session.setMode("ace/mode/javascript");
</script>
</body>
</html>

View file

@ -1,3 +1,3 @@
REM default port 5008
REM https://download.eclipse.org/lemminx/releases/0.31.0/
REM default port 5008
REM https://download.eclipse.org/lemminx/releases/0.31.0/
java -cp org.eclipse.lemminx-uber.jar org.eclipse.lemminx.XMLServerSocketLauncher

View file

@ -1,72 +1,72 @@
(:~ web socket for ace
:)
module namespace lsp="urn:quodatum:vscode";
import module namespace ws = "http://basex.org/modules/ws";
declare
%ws:connect('/ws/exampleServer')
function lsp:connect()
as empty-sequence(){
let $_:=trace(ws:id(),"BaseX socket id: ")
return ()
};
(:~
: Processes a WebSocket message.
: @param $message message
:)
declare
%ws:message('/ws/exampleServer', '{$message}')
function lsp:message(
$message as xs:string
) as empty-sequence() {
let $json:=json:parse($message, map{ 'format': 'xquery' })
let $id:=$json?id
let $_:=trace($id,"MESSAGE id: ")
return switch($json?method=>trace("method: "))
case "initialize" return
let $a:=map{
"capabilities":map{"textDocumentSync":2,
"completionProvider":map{"resolveProvider":false(),"triggerCharacters":["\",":"]},
"hoverProvider":true(),
"documentSymbolProvider":true(),
"documentRangeFormattingProvider":false(),
"colorProvider":map{},
"foldingRangeProvider":true(),
"selectionRangeProvider":true(),
"documentLinkProvider":map{}
}
}
let $a:=trace($a,"A: ")
return lsp:send-result($a,$id,ws:id())
default
return error()
};
declare %ws:error('/ws/exampleServer', '{$error}')
function lsp:error($error)
{
let $_:=trace($error,"ERROR ")
return ()
};
(:~
: Closes a WebSocket connection. Unregisters the user and notifies all clients.
:)
declare
%ws:close('/ws/exampleServer')
function lsp:close() as empty-sequence() {
let $_:=trace("CLOSE")
return ()
};
declare
function lsp:send-result($result as map(*),$rpcId as xs:string, $wsId as xs:string)
as empty-sequence()
{
let $json:=map{"jsonrpc":"2.0","id":$rpcId,"result":$result}=>trace("RESULT: ")
return ws:send($json,$wsId)
};
(:~ web socket for ace
:)
module namespace lsp="urn:quodatum:vscode";
import module namespace ws = "http://basex.org/modules/ws";
declare
%ws:connect('/ws/exampleServer')
function lsp:connect()
as empty-sequence(){
let $_:=trace(ws:id(),"BaseX socket id: ")
return ()
};
(:~
: Processes a WebSocket message.
: @param $message message
:)
declare
%ws:message('/ws/exampleServer', '{$message}')
function lsp:message(
$message as xs:string
) as empty-sequence() {
let $json:=json:parse($message, map{ 'format': 'xquery' })
let $id:=$json?id
let $_:=trace($id,"MESSAGE id: ")
return switch($json?method=>trace("method: "))
case "initialize" return
let $a:=map{
"capabilities":map{"textDocumentSync":2,
"completionProvider":map{"resolveProvider":false(),"triggerCharacters":["\",":"]},
"hoverProvider":true(),
"documentSymbolProvider":true(),
"documentRangeFormattingProvider":false(),
"colorProvider":map{},
"foldingRangeProvider":true(),
"selectionRangeProvider":true(),
"documentLinkProvider":map{}
}
}
let $a:=trace($a,"A: ")
return lsp:send-result($a,$id,ws:id())
default
return error()
};
declare %ws:error('/ws/exampleServer', '{$error}')
function lsp:error($error)
{
let $_:=trace($error,"ERROR ")
return ()
};
(:~
: Closes a WebSocket connection. Unregisters the user and notifies all clients.
:)
declare
%ws:close('/ws/exampleServer')
function lsp:close() as empty-sequence() {
let $_:=trace("CLOSE")
return ()
};
declare
function lsp:send-result($result as map(*),$rpcId as xs:string, $wsId as xs:string)
as empty-sequence()
{
let $json:=map{"jsonrpc":"2.0","id":$rpcId,"result":$result}=>trace("RESULT: ")
return ws:send($json,$wsId)
};

View file

@ -1,4 +1,4 @@
<script>
const webSocket = new WebSocket("ws://localhost:5008");
alert("hi");
<script>
const webSocket = new WebSocket("ws://localhost:5008");
alert("hi");
</script>

View file

@ -1,30 +1,30 @@
import "ace-code/esm-resolver";
import {jsonContent} from "../docs-example/json-example";
import {json5Content, json5Schema} from "../docs-example/json5-example";
import {addFormatCommand, createEditorWithLSP} from "../utils";
import {AceLanguageClient, LanguageClientConfig} from "ace-linters/build/ace-language-client";
let modes = [
{name: "json", mode: "ace/mode/json", content: jsonContent, options: {jsonSchemaUri: "common-form.schema.json"}},
{name: "json5", mode: "ace/mode/json5", content: json5Content, options: {jsonSchemaUri: json5Schema}},
]
const serverData: LanguageClientConfig = {
module: () => import("ace-linters/build/language-client"),
modes: "json|json5",
type: "socket",
socket: new WebSocket("ws://127.0.0.1:3000/exampleServer"),
}
let languageProvider = AceLanguageClient.for(serverData);
let i = 0;
for (let mode of modes) {
// @ts-expect-error
createEditorWithLSP(mode, i, languageProvider);
i++;
}
// @ts-expect-error
addFormatCommand(languageProvider);
import "ace-code/esm-resolver";
import {jsonContent} from "../docs-example/json-example";
import {json5Content, json5Schema} from "../docs-example/json5-example";
import {addFormatCommand, createEditorWithLSP} from "../utils";
import {AceLanguageClient, LanguageClientConfig} from "ace-linters/build/ace-language-client";
let modes = [
{name: "json", mode: "ace/mode/json", content: jsonContent, options: {jsonSchemaUri: "common-form.schema.json"}},
{name: "json5", mode: "ace/mode/json5", content: json5Content, options: {jsonSchemaUri: json5Schema}},
]
const serverData: LanguageClientConfig = {
module: () => import("ace-linters/build/language-client"),
modes: "json|json5",
type: "socket",
socket: new WebSocket("ws://127.0.0.1:3000/exampleServer"),
}
let languageProvider = AceLanguageClient.for(serverData);
let i = 0;
for (let mode of modes) {
// @ts-expect-error
createEditorWithLSP(mode, i, languageProvider);
i++;
}
// @ts-expect-error
addFormatCommand(languageProvider);

View file

@ -1,11 +1,11 @@
# Sample language server
This is just sample websocket server based on vscode-json-languageserver
## Getting Started
To run the server, simply follow these steps:
1. Install dependencies by running `npm i`
2. Start the server by running `npm run start-server`
And that's it! Your sample language server on 3000 port should now be up and running.
# Sample language server
This is just sample websocket server based on vscode-json-languageserver
## Getting Started
To run the server, simply follow these steps:
1. Install dependencies by running `npm i`
2. Start the server by running `npm run start-server`
And that's it! Your sample language server on 3000 port should now be up and running.

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
{
"name": "sample-server",
"version": "1.0.0",
"scripts": {
"start-server": "node --loader ts-node/esm server.ts"
},
"dependencies": {
"vscode-json-languageserver": "^1.3.4",
"ts-node": "^10.8.1"
},
"type": "module"
}
{
"name": "sample-server",
"version": "1.0.0",
"scripts": {
"start-server": "node --loader ts-node/esm server.ts"
},
"dependencies": {
"vscode-json-languageserver": "^1.3.4",
"ts-node": "^10.8.1"
},
"type": "module"
}

View file

@ -1,98 +1,98 @@
import fs from "fs";
import {WebSocketServer} from 'ws';
import * as http from 'http';
import {fileURLToPath, URL} from 'url';
import * as net from 'net';
import express from 'express';
import * as rpc from 'vscode-ws-jsonrpc';
// @ts-ignore
import * as jsonServer from 'vscode-json-languageserver/out/jsonServer.js'
import requestLight from "request-light";
import vscodeUri from "vscode-uri";
import {createConnection} from 'vscode-languageserver/lib/node/main.js';
import path from 'path';
export function startLanguageServer(webSocket: rpc.IWebSocket) {
const messageReader = new rpc.WebSocketMessageReader(webSocket);
const messageWriter = new rpc.WebSocketMessageWriter(webSocket);
const connection = createConnection(messageReader, messageWriter);
jsonServer.startServer(connection, {
file: getFileService(),
http: getHTTPService(),
configureHttpRequests: requestLight.configure
});
}
function getHTTPService() {
return {
getContent(uri: any) {
const headers = {'Accept-Encoding': 'gzip, deflate'};
return requestLight.xhr({url: uri, followRedirects: 5, headers}).then(response => {
return response.responseText;
}, (error) => {
return Promise.reject(error.responseText || requestLight.getErrorStatusDescription(error.status) || error.toString());
});
}
};
}
function getFileService() {
return {
getContent(location: any) {
return new Promise((resolve, reject) => {
const uri = vscodeUri.URI.parse(location);
fs.readFile(uri.fsPath, 'utf8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
};
}
const serverFilePath = fileURLToPath(import.meta.url);
const serverDir = path.dirname(serverFilePath);
process.on('uncaughtException', (err: any) => {
console.error('Uncaught Exception: ', err.toString());
if (err.stack) {
console.error(err.stack);
}
});
const app = express();
app.use(express.static(serverDir));
const server = app.listen(3000);
const webSocketServer = new WebSocketServer({
noServer: true,
perMessageDeflate: false
});
server.on('upgrade', (request: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
const baseURL = `http://${request.headers.host}/`;
const pathname = request.url ? new URL(request.url, baseURL).pathname : undefined;
if (pathname === '/exampleServer') {
webSocketServer.handleUpgrade(request, socket, head, webSocket => {
const socket: rpc.IWebSocket = {
send: content => webSocket.send(content, error => {
if (error) {
throw error;
}
}),
onMessage: cb => webSocket.on('message', cb),
onError: cb => webSocket.on('error', cb),
onClose: cb => webSocket.on('close', cb),
dispose: () => webSocket.close()
};
if (webSocket.readyState === webSocket.OPEN) {
startLanguageServer(socket);
} else {
webSocket.on('open', () => startLanguageServer(socket));
}
});
}
});
import fs from "fs";
import {WebSocketServer} from 'ws';
import * as http from 'http';
import {fileURLToPath, URL} from 'url';
import * as net from 'net';
import express from 'express';
import * as rpc from 'vscode-ws-jsonrpc';
// @ts-ignore
import * as jsonServer from 'vscode-json-languageserver/out/jsonServer.js'
import requestLight from "request-light";
import vscodeUri from "vscode-uri";
import {createConnection} from 'vscode-languageserver/lib/node/main.js';
import path from 'path';
export function startLanguageServer(webSocket: rpc.IWebSocket) {
const messageReader = new rpc.WebSocketMessageReader(webSocket);
const messageWriter = new rpc.WebSocketMessageWriter(webSocket);
const connection = createConnection(messageReader, messageWriter);
jsonServer.startServer(connection, {
file: getFileService(),
http: getHTTPService(),
configureHttpRequests: requestLight.configure
});
}
function getHTTPService() {
return {
getContent(uri: any) {
const headers = {'Accept-Encoding': 'gzip, deflate'};
return requestLight.xhr({url: uri, followRedirects: 5, headers}).then(response => {
return response.responseText;
}, (error) => {
return Promise.reject(error.responseText || requestLight.getErrorStatusDescription(error.status) || error.toString());
});
}
};
}
function getFileService() {
return {
getContent(location: any) {
return new Promise((resolve, reject) => {
const uri = vscodeUri.URI.parse(location);
fs.readFile(uri.fsPath, 'utf8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
};
}
const serverFilePath = fileURLToPath(import.meta.url);
const serverDir = path.dirname(serverFilePath);
process.on('uncaughtException', (err: any) => {
console.error('Uncaught Exception: ', err.toString());
if (err.stack) {
console.error(err.stack);
}
});
const app = express();
app.use(express.static(serverDir));
const server = app.listen(3000);
const webSocketServer = new WebSocketServer({
noServer: true,
perMessageDeflate: false
});
server.on('upgrade', (request: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
const baseURL = `http://${request.headers.host}/`;
const pathname = request.url ? new URL(request.url, baseURL).pathname : undefined;
if (pathname === '/exampleServer') {
webSocketServer.handleUpgrade(request, socket, head, webSocket => {
const socket: rpc.IWebSocket = {
send: content => webSocket.send(content, error => {
if (error) {
throw error;
}
}),
onMessage: cb => webSocket.on('message', cb),
onError: cb => webSocket.on('error', cb),
onClose: cb => webSocket.on('close', cb),
dispose: () => webSocket.close()
};
if (webSocket.readyState === webSocket.OPEN) {
startLanguageServer(socket);
} else {
webSocket.on('open', () => startLanguageServer(socket));
}
});
}
});