Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

changes to import monaco-lsp code into jupyterlab-monaco #12

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"author": "Project Jupyter",
"files": [
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
"schema/*.json"
],
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand All @@ -30,19 +31,30 @@
"watch": "tsc -w"
},
"dependencies": {
"@jupyterlab/application": "^0.18.0",
"@jupyterlab/apputils": "^0.18.0",
"@jupyterlab/application": "^0.18.2",
"@jupyterlab/apputils": "^0.18.2",
"@jupyterlab/coreutils": "^2.0.2",
"@jupyterlab/fileeditor": "^0.18.0",
"monaco-editor": "^0.13.1"
"cors-anywhere": "^0.4.1",
"monaco-editor-core": "^0.14.6",
"monaco-languageclient": "^0.6.3",
"net": "^1.0.2",
"normalize-url": "^2.0.1",
"reconnecting-websocket": "^3.2.2",
"vscode-ws-jsonrpc": "^0.0.2-1"
},
"devDependencies": {
"@types/node": "^7.0.12",
"css-loader": "^1.0.0",
"style-loader": "^0.23.0",
"rimraf": "^2.6.1",
"style-loader": "^0.23.0",
"typescript": "~2.6.0",
"webpack": "^4.6.0",
"webpack-cli": "^2.0.14"
},
"jupyterlab": {
"extension": true
"extension": true,
"schemaDir": "schema"
}
}
15 changes: 15 additions & 0 deletions schema/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"jupyter.lab.setting-icon-class": "jp-TextEditorIcon",
"jupyter.lab.setting-icon-label": "Editor",
"title": "Monaco Editor",
"description": "Monaco editor settings.",
"properties": {
"lspServer": {
"type": "string",
"description": "The LSP server for Monaco editors.",
"default": "ws://localhost:8080/wala-ariadne/websocket"
}
},
"additionalProperties": false,
"type": "object"
}
130 changes: 100 additions & 30 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
*
*/

const LANGUAGE = "python"

require('monaco-editor-core');

import {
JupyterLab, JupyterLabPlugin
} from '@jupyterlab/application';
Expand All @@ -19,7 +23,7 @@ import {
} from '@jupyterlab/apputils';

import {
PathExt
PathExt, ISettingRegistry
} from '@jupyterlab/coreutils';

import {
Expand All @@ -31,40 +35,52 @@ import {
} from '@jupyterlab/fileeditor';

import {
PromiseDelegate,
UUID
UUID, PromiseDelegate
} from '@phosphor/coreutils';

import {
Widget
} from '@phosphor/widgets';

import * as monaco from 'monaco-editor';

import '../style/index.css';

import * as monacoCSS from 'file-loader!../lib/css.worker.bundle.js';
import * as monacoEditor from 'file-loader!../lib/editor.worker.bundle.js';
import * as monacoHTML from 'file-loader!../lib/html.worker.bundle.js';
import * as monacoJSON from 'file-loader!../lib/json.worker.bundle.js';
import * as monacoTS from 'file-loader!../lib/ts.worker.bundle.js';


let URLS: {[key: string]: string} = {
css: monacoCSS,
html: monacoHTML,
javascript: monacoTS,
json: monacoJSON,
typescript: monacoTS
};

(self as any).MonacoEnvironment = {
getWorkerUrl: function (moduleId: string, label: string): string {
let url = URLS[label] || monacoEditor;
return url;
return monacoEditor;
}
}

import { listen, MessageConnection } from 'vscode-ws-jsonrpc';
import {
BaseLanguageClient, CloseAction, ErrorAction,
createMonacoServices, createConnection
} from 'monaco-languageclient';

const ReconnectingWebSocket = require('reconnecting-websocket');

function createWebSocket(url: string): WebSocket {
const socketOptions = {
maxReconnectionDelay: 10000,
minReconnectionDelay: 1000,
reconnectionDelayGrowFactor: 1.3,
connectionTimeout: 10000,
maxRetries: Infinity,
debug: false
};
return new ReconnectingWebSocket(url, undefined, socketOptions);
}

// register the Python language with Monaco
monaco.languages.register({
id: LANGUAGE,
extensions: ['.py'],
aliases: ['Python', 'PYTHON', 'py'],
mimetypes: ['text/plain']
});


/**
* An monaco widget.
*/
Expand All @@ -73,7 +89,7 @@ class MonacoWidget extends Widget {
/**
* Construct a new Monaco widget.
*/
constructor(context: DocumentRegistry.CodeContext) {
constructor(context: DocumentRegistry.CodeContext, lspServer: string) {
super();
this.id = UUID.uuid4();
this.title.label = PathExt.basename(context.localPath);
Expand All @@ -87,18 +103,62 @@ class MonacoWidget extends Widget {
if(monaco.editor.getModel(uri)) {
monaco_model = monaco.editor.getModel(uri);
} else {
monaco_model = monaco.editor.createModel(content, undefined, uri);
monaco_model = monaco.editor.createModel(content, LANGUAGE, uri);
}

monaco.editor.setModelLanguage(monaco_model, "python");

this.editor = monaco.editor.create(this.node, {
model: monaco_model
model: monaco_model,
glyphMargin: true,
lightbulb: {
enabled: true
}
});

monaco_model.onDidChangeContent((event) => {
var mm = this.editor.getModel();
mm.onDidChangeContent((event) => {
this.context.model.value.text = this.editor.getValue();
});

context.ready.then(() => { this._onContextReady(); });

const services = createMonacoServices(this.editor);
function createLanguageClient(connection: MessageConnection): BaseLanguageClient {
return new BaseLanguageClient({
name: "Sample Language Client",
clientOptions: {
// use a language id as a document selector
documentSelector: [LANGUAGE],
// disable the default error handler
errorHandler: {
error: () => ErrorAction.Continue,
closed: () => CloseAction.DoNotRestart
}
},
services,
// create a language client connection from the JSON RPC connection on demand
connectionProvider: {
get: (errorHandler, closeHandler) => {
return Promise.resolve(createConnection(connection, errorHandler, closeHandler))
}
}
})
}

// create the web socket
const webSocket = createWebSocket(lspServer);
// listen when the web socket is opened
listen({
webSocket,
onConnection:
connection => {
// create and start the language client
const languageClient = createLanguageClient(connection);
const disposable = languageClient.start();
connection.onClose(() => disposable.dispose());
}
});
}

/**
Expand Down Expand Up @@ -157,13 +217,20 @@ class MonacoWidget extends Widget {
* A widget factory for editors.
*/
export
class MonacoEditorFactory extends ABCWidgetFactory<IDocumentWidget<MonacoWidget>, DocumentRegistry.ICodeModel> {

class MonacoEditorFactory extends ABCWidgetFactory<IDocumentWidget<MonacoWidget>, DocumentRegistry.ICodeModel> {
private lspServer: string;

constructor(a: any, b: string) {
super(a);
this.lspServer = b;
}

/**
* Create a new widget given a context.
*/
protected createNewWidget(context: DocumentRegistry.CodeContext): IDocumentWidget<MonacoWidget> {
const content = new MonacoWidget(context);
const content = new MonacoWidget(context, this.lspServer);
const widget = new DocumentWidget({ content, context });
return widget;
}
Expand All @@ -177,16 +244,19 @@ class MonacoEditorFactory extends ABCWidgetFactory<IDocumentWidget<MonacoWidget>
* 'defaultFor' runs *after* the file editors defaultFor.
*/
const extension: JupyterLabPlugin<void> = {
id: 'jupyterlab-monaco',
id: 'jupyterlab-monaco:plugin',
autoStart: true,
requires: [ICommandPalette, IEditorTracker],
activate: (app: JupyterLab, palette: ICommandPalette, editorTracker: IEditorTracker) => {
requires: [ISettingRegistry, ICommandPalette, IEditorTracker],
activate: async (app: JupyterLab, registry: ISettingRegistry, palette: ICommandPalette, editorTracker: IEditorTracker) => {
const settings = await registry.load(extension.id);
const server = settings.composite['lspServer'] as string;
console.log("starting " + extension.id + " with " + server);

const factory = new MonacoEditorFactory({
name: 'Monaco Editor',
fileTypes: ['*'],
defaultFor: ['*']
});
}, server);
app.docRegistry.addWidgetFactory(factory);

// Add an application command
Expand Down
12 changes: 3 additions & 9 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ const webpack = require('webpack');

module.exports = {
entry: {
// Package each language's worker and give these filenames in `getWorkerUrl`
"editor.worker": 'monaco-editor/esm/vs/editor/editor.worker.js',
"json.worker": 'monaco-editor/esm/vs/language/json/json.worker',
"css.worker": 'monaco-editor/esm/vs/language/css/css.worker',
"html.worker": 'monaco-editor/esm/vs/language/html/html.worker',
"ts.worker": 'monaco-editor/esm/vs/language/typescript/ts.worker',
"editor.worker": 'monaco-editor-core/esm/vs/editor/editor.worker.js'
},
output: {
filename: '[name].bundle.js',
Expand All @@ -18,11 +13,9 @@ module.exports = {
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
use: ['style-loader', 'css-loader']
}]
},
mode: 'development',
devtool: 'source-map',
plugins: [
// Ignore require() calls in vs/language/typescript/lib/typescriptServices.js
new webpack.IgnorePlugin(
Expand All @@ -31,3 +24,4 @@ module.exports = {
)
]
};

Loading