Skip to content

Commit b55d436

Browse files
authored
Monaco editor example (#37)
1 parent 506b699 commit b55d436

21 files changed

+369
-13
lines changed

packages/server/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist_index

packages/server/.npmignore

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/server/bin/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import yargs from 'yargs'
2-
import createServer from '../createServer'
2+
import { createServer } from '../createServer'
33

44
const cli = yargs
55
.usage('SQL Language Server Command Line Interface')

packages/server/createServer.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ type Args = {
2525
method?: ConnectionMethod
2626
}
2727

28-
export default function createServer() {
29-
let connection: IConnection = createConnection((yargs.argv as Args).method || 'node-ipc')
28+
export function createServerWithConnection(connection: IConnection) {
3029
initializeLogging()
3130
const logger = log4js.getLogger()
3231
let documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument)
@@ -201,3 +200,8 @@ export default function createServer() {
201200
logger.info('start sql-languager-server')
202201
return connection
203202
}
203+
204+
export function createServer() {
205+
let connection: IConnection = createConnection((yargs.argv as Args).method || 'node-ipc')
206+
return createServerWithConnection(connection)
207+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lib
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## SQLLanguageServer monaco-editor example
2+
3+
### how to setup
4+
5+
```sh
6+
$ yarn && yarn build
7+
$ yarn start
8+
```
9+
10+
Then connect to http://localhost:3000 on your browser.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"private": true,
3+
"name": "sql-lsp-monaco-editor-example",
4+
"version": "1.0.0",
5+
"main": "index.js",
6+
"license": "MIT",
7+
"scripts": {
8+
"compile": "tsc",
9+
"copy": "cp src/index.html lib/index.html",
10+
"build": "yarn build:server && yarn build:client",
11+
"build:client": "yarn compile && webpack && yarn run copy",
12+
"build:server": "cd ../../ && yarn",
13+
"start": "node lib/server.js"
14+
},
15+
"dependencies": {
16+
"express": "^4.17.1",
17+
"monaco-editor-core": "^0.20.0",
18+
"monaco-languageclient": "^0.13.1-next.1",
19+
"reconnecting-websocket": "^4.4.0",
20+
"vscode-ws-jsonrpc": "^0.2.0",
21+
"ws": "^7.3.1"
22+
},
23+
"devDependencies": {
24+
"@types/express": "^4.17.6",
25+
"@types/ws": "^7.2.6",
26+
"css-loader": "^3.6.0",
27+
"file-loader": "^6.0.0",
28+
"source-map-loader": "^1.0.1",
29+
"style-loader": "^1.2.1",
30+
"typescript": "^3.9.6",
31+
"webpack": "^4.43.0",
32+
"webpack-cli": "^3.3.12"
33+
}
34+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/// <reference types="monaco-editor-core/monaco"/>
2+
3+
import { listen, MessageConnection } from "vscode-ws-jsonrpc";
4+
import {
5+
MonacoLanguageClient,
6+
MonacoServices,
7+
createConnection,
8+
} from "monaco-languageclient";
9+
import ReconnectingWebSocket from "reconnecting-websocket";
10+
11+
monaco.languages.register({
12+
id: "sql",
13+
extensions: [".sql"],
14+
aliases: ["SQL", "sql"],
15+
mimetypes: ["application/json"],
16+
});
17+
18+
const value = `SELECT * FROM users`;
19+
const editor = monaco.editor.create(document.getElementById("container")!, {
20+
model: monaco.editor.createModel(
21+
value,
22+
"sql",
23+
monaco.Uri.parse("inmemory://model.sql"),
24+
),
25+
glyphMargin: true,
26+
tabCompletion: 'on'
27+
});
28+
29+
MonacoServices.install(editor);
30+
31+
const URL = "ws://localhost:3000/server";
32+
const webSocket = createWebSocket(URL) as WebSocket;
33+
listen({
34+
webSocket,
35+
onConnection: (connection) => {
36+
const languageClient = createLanguageClient(connection);
37+
const disposable = languageClient.start();
38+
connection.onClose(() => disposable.dispose());
39+
},
40+
});
41+
42+
function createLanguageClient(
43+
connection: MessageConnection
44+
): MonacoLanguageClient {
45+
return new MonacoLanguageClient({
46+
name: "SQL Language Server MonacoClient",
47+
clientOptions: {
48+
documentSelector: ["sql"],
49+
},
50+
connectionProvider: {
51+
get: (errorHandler, closeHandler) => {
52+
return Promise.resolve(
53+
createConnection(connection, errorHandler, closeHandler)
54+
);
55+
},
56+
},
57+
});
58+
}
59+
60+
function createWebSocket(url: string): ReconnectingWebSocket {
61+
const socketOptions = {
62+
maxReconnectionDelay: 10000,
63+
minReconnectionDelay: 1000,
64+
reconnectionDelayGrowFactor: 1.3,
65+
connectionTimeout: 10000,
66+
maxRetries: Infinity,
67+
debug: false,
68+
};
69+
return new ReconnectingWebSocket(url, [], socketOptions);
70+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
7+
</head>
8+
9+
<body>
10+
<h2>Monaco Language Client SQLLanguageServer Sample</h2>
11+
<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
12+
<script src="main.bundle.js"></script>
13+
</html
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as path from "path";
2+
import * as rpc from "vscode-ws-jsonrpc";
3+
import * as server from "vscode-ws-jsonrpc/lib/server";
4+
import * as lsp from "vscode-languageserver";
5+
import { createConnection } from 'vscode-languageserver';
6+
import { createServerWithConnection } from '../../../dist_index/index'
7+
8+
export function launchServer(socket: rpc.IWebSocket) {
9+
const reader = new rpc.WebSocketMessageReader(socket);
10+
const writer = new rpc.WebSocketMessageWriter(socket);
11+
const asExternalProccess =
12+
process.argv.findIndex((value) => value === "--external") !== -1;
13+
if (asExternalProccess) {
14+
// start the language server as an external process
15+
// TODO: implement it
16+
17+
// const extJsonServerPath = path.resolve(__dirname, "ext-json-server.js");
18+
// const socketConnection = server.createConnection(reader, writer, () =>
19+
// socket.dispose()
20+
// );
21+
// const serverConnection = server.createServerProcess("JSON", "node", [
22+
// extJsonServerPath,
23+
// ]);
24+
// server.forward(socketConnection, serverConnection, (message) => {
25+
// if (rpc.isRequestMessage(message)) {
26+
// if (message.method === lsp.InitializeRequest.type.method) {
27+
// const initializeParams = message.params as lsp.InitializeParams;
28+
// initializeParams.processId = process.pid;
29+
// }
30+
// }
31+
// return message;
32+
// });
33+
} else {
34+
// start the language server inside the current process
35+
const connection = createConnection(reader, writer)
36+
createServerWithConnection(connection)
37+
}
38+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require('monaco-editor-core');
2+
(self as any).MonacoEnvironment = {
3+
getWorkerUrl: () => './editor.worker.bundle.js'
4+
}
5+
require('./client');
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import * as express from "express";
2+
import * as ws from "ws";
3+
import * as http from "http";
4+
import * as net from "net";
5+
import * as url from "url";
6+
import * as rpc from "vscode-ws-jsonrpc";
7+
import { launchServer } from './launchServer'
8+
9+
process.on("uncaughtException", function (err: any) {
10+
console.error("Uncaught Exception: ", err.toString());
11+
if (err.stack) {
12+
console.error(err.stack);
13+
}
14+
});
15+
16+
const app = express();
17+
app.use(express.static(__dirname));
18+
19+
const server = app.listen(3000);
20+
21+
const wss = new ws.Server({
22+
noServer: true,
23+
perMessageDeflate: false,
24+
});
25+
26+
server.on(
27+
"upgrade",
28+
(request: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
29+
const path = request.url ? url.parse(request.url).pathname : undefined;
30+
if (path === "/server") {
31+
wss.handleUpgrade(request, socket, head, (webSocket) => {
32+
const socket: rpc.IWebSocket = {
33+
send: (content) =>
34+
webSocket.send(content, (error) => {
35+
if (error) {
36+
throw error;
37+
}
38+
}),
39+
onMessage: (cb) => webSocket.on("message", cb),
40+
onError: (cb) => webSocket.on("error", cb),
41+
onClose: (cb) => webSocket.on("close", cb),
42+
dispose: () => webSocket.close(),
43+
};
44+
if (webSocket.readyState === webSocket.OPEN) {
45+
console.log("ready to launch server");
46+
launchServer(socket)
47+
} else {
48+
webSocket.on("open", () => {
49+
// launch(socket)
50+
console.log("ready to raunch server2");
51+
launchServer(socket)
52+
});
53+
}
54+
});
55+
}
56+
}
57+
);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"compilerOptions": {
3+
"strict": true,
4+
"target": "es6",
5+
"module": "commonjs",
6+
"moduleResolution": "node",
7+
"outDir": "lib",
8+
"skipLibCheck": true,
9+
"sourceMap": true,
10+
"declarationMap": true,
11+
"inlineSources": false,
12+
"declaration": true,
13+
"stripInternal": true,
14+
"lib": [
15+
"es2016",
16+
"dom"
17+
],
18+
},
19+
"include": [
20+
"src"
21+
],
22+
"exclude": [ "node_modules" ]
23+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const path = require('path')
2+
const lib = path.resolve(__dirname, 'lib')
3+
4+
module.exports = {
5+
entry: {
6+
main: path.resolve(lib, 'main.js'),
7+
'editor.worker': 'monaco-editor-core/esm/vs/editor/editor.worker.js'
8+
},
9+
output: {
10+
filename: '[name].bundle.js',
11+
path: lib
12+
},
13+
target: 'web',
14+
node: {
15+
fs: 'empty',
16+
child_process: 'empty',
17+
net: 'empty',
18+
crypto: 'empty'
19+
},
20+
resolve: {
21+
alias: {
22+
'vscode': require.resolve('monaco-languageclient/lib/vscode-compatibility')
23+
},
24+
extensions: ['.js', '.json', '.ttf']
25+
},
26+
devtool: 'source-map',
27+
module: {
28+
rules: [{
29+
test: /\.css$/i,
30+
use: ['style-loader', 'css-loader']
31+
},
32+
{
33+
test: /\.ttf$/,
34+
use: ['file-loader']
35+
},
36+
{
37+
test: /\.js$/,
38+
enforce: 'pre',
39+
loader: 'source-map-loader'
40+
}]
41+
}
42+
}

packages/server/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { createServer, createServerWithConnection } from './createServer'
2+
export { createServer, createServerWithConnection }

packages/server/package.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
{
22
"name": "sql-language-server",
3-
"version": "0.10.8",
4-
"main": "index.js",
3+
"version": "0.10.0",
4+
"main": "dist_index/index.js",
55
"bin": {
66
"sql-language-server": "./dist/cli.js"
77
},
88
"license": "MIT",
99
"scripts": {
10-
"compile": "rollup -c",
10+
"compile:cli": "rm -rf dist && rollup -c",
11+
"compile:index": "rm -rf dist_index && rollup -c rollup.index.config.js",
12+
"compile:sqlint": "cd ../sqlint && yarn && yarn build",
13+
"clean": "rm -rf dist dist_index",
1114
"watch": "rollup -c -w",
1215
"test": "jest",
13-
"prepublish": "yarn run compile"
16+
"prepublish": "yarn compile:sqlint && yarn compile:cli && yarn compile:index"
1417
},
1518
"files": [
1619
"package.json",
17-
"dist"
20+
"dist",
21+
"dist_index"
1822
],
1923
"dependencies": {
2024
"@types/pg": "^7.4.10",

0 commit comments

Comments
 (0)