-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrate Python Language Server to Monaco Editor (Closes #1908, #571) #1910
base: master
Are you sure you want to change the base?
Changes from 3 commits
542f549
7aeebe0
da381fb
2802a5d
4503ae4
29775a7
b777e43
08291c5
dd9fe28
37c1ddc
03b41f5
c0fc77f
376fbc6
dcd5ae5
e26e7c3
f4facd8
5ca1db3
9e2525a
8bd0f3e
ddbf23a
b1df3f6
2bd224e
21ad734
c8227d1
a339b9c
087323b
aa84bc2
a9e321a
10bec66
89b2e68
20bd21f
193698d
d7b9a0d
aa60904
61bd70f
f75f652
c45823b
3d84cdb
d5bfa3f
ff110bc
36c6723
81657c3
71979a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,9 +5,13 @@ The script `deploy-deepforge` is used for standard deployment of deepforge using | |
|
||
Additionally, this contains a file with customizations to the standard docker-compose.yml file which allows us to modify the entrypoint and install a version of tensorflow [compatible with the CPU of the deployment machine](https://github.com/deepforge-dev/deepforge/issues/1561). | ||
|
||
The deployment is updated by first creating the custom docker compose file using [yaml-merge](https://github.com/alexlafroscia/yaml-merge): | ||
Moreover, we also a proxy server with that spins up different language servers that we provide for | ||
intelligent syntax | ||
highlighting in deepforge's browser. For more information checkout the language server's docker [file](../docker/Dockerfile.langservers) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "in deepforge's browser" -> "in DeepForge" |
||
|
||
The deployment is updated by first creating the custom docker compose file using [yq](https://github.com/mikefarah/yq): | ||
``` | ||
yaml-merge docker-compose.yml .deployment/docker-compose-overrides.yml > custom-docker-compose.yml | ||
yq m -a docker/docker-compose.yml "$DEEPFORGE_DEPLOYMENT_DIR"/docker-compose-overrides.yml > custom-docker-compose.yml | ||
``` | ||
Next, the generated file can be used with docker-compose: | ||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/bin/bash | ||
# Remove pypi tensorflow in favor of conda installation | ||
source activate base | ||
pip uninstall tensorflow -y | ||
conda install tensorflow==1.14 -y | ||
|
||
node $(npm root -g)/jsonrpc-ws-proxy/dist/server.js --port $PORT --languageServers ~/language-servers.yml | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,30 @@ | ||
const yaml = require('js-yaml'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
|
||
const SERVERS_YML = path.join(__dirname, '..', 'language-servers.yml'); | ||
|
||
function getAvailableLanguageServers () { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am a little wary about this. It seems to be assuming that any servers defined in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep. can it be solved by moving |
||
const parsed = yaml.safeLoad(fs.readFileSync(SERVERS_YML)); | ||
return parsed.langservers ? Object.keys(parsed.langservers): []; | ||
} | ||
|
||
function getWorkspaceURIs() { | ||
const availableServers = getAvailableLanguageServers(); | ||
const workspaces = {}; | ||
availableServers.forEach(server => { | ||
workspaces[server] = `file:///tmp/${server}-models/`; | ||
}); | ||
return workspaces; | ||
} | ||
|
||
module.exports = config => { | ||
config.extensions = {}; | ||
config.extensions.InteractiveComputeHost = process.env.DEEPFORGE_INTERACTIVE_COMPUTE_HOST; | ||
config.extensions.languageServers = { | ||
host: process.env.DEEPFORGE_LANGUAGE_SERVER_HOST, | ||
servers: getAvailableLanguageServers(), | ||
workspaceURIs: getWorkspaceURIs(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After looking at how this is used, maybe this should be called |
||
}; | ||
return config; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
FROM continuumio/anaconda3 | ||
|
||
EXPOSE 5000 | ||
|
||
ENV PORT 5000 | ||
|
||
RUN apt-get update && curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -y nodejs | ||
|
||
RUN npm install -g npm && npm install -g jsonrpc-ws-proxy | ||
|
||
RUN conda update conda -yq && conda install python=3.7 | ||
|
||
COPY src/plugins/GenerateJob/templates/environment.worker.yml . | ||
|
||
RUN conda env update -n base --file environment.worker.yml && rm environment.worker.yml && conda clean -afy | ||
|
||
ENTRYPOINT node $(npm root -g)/jsonrpc-ws-proxy/dist/server.js --port $PORT --languageServers ~/language-servers.yml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
name: deepforge | ||
dependencies: | ||
- python=3.7 | ||
- python-language-server | ||
umesh-timalsina marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ dependencies: | |
- matplotlib==3.2.2 | ||
- simplejson | ||
- plotly | ||
- python-language-server==0.25.0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
langservers: | ||
python: | ||
- pyls | ||
- --log-file | ||
- pyls.log |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* globals define */ | ||
|
||
define([ | ||
'./lib/vscode-ws-jsonrpc.min', | ||
'./lib/monaco-languageclient.min', | ||
'./lib/reconnecting-websocket.min', | ||
], function ( | ||
vscodeWSJSONRpc, | ||
LangaugeClient, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My bad on the typos. Sorry. |
||
RS | ||
) { | ||
const {ReconnectingWebSocket} = RS, | ||
{listen} = vscodeWSJSONRpc; | ||
const { | ||
MonacoLanguageClient, | ||
CloseAction, | ||
ErrorAction, | ||
Services, | ||
MonacoCommands, | ||
MonacoWorkspace, | ||
ConsoleWindow, | ||
MonacoLanguages, | ||
MonacoToProtocolConverter, | ||
ProtocolToMonacoConverter, | ||
createConnection | ||
} = LangaugeClient; | ||
|
||
class DeepForgeLanguageClient { | ||
constructor(editor, serverURL, opts) { | ||
const services = createServices(editor, opts); | ||
Services.install(services); | ||
this.serverURL = serverURL; | ||
this.socket = createReconnectingWebSocket(this.serverURL, opts); | ||
this._initializeClient(opts); | ||
} | ||
|
||
_initializeClient(opts) { | ||
listen({ | ||
webSocket: this.socket, | ||
onConnection: connection => { | ||
const languageClient = createLanguageClient(connection, opts); | ||
const disposable = languageClient.start(); | ||
connection.onClose(() => disposable.dispose()); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
const createLanguageClient = function (connection, opts) { | ||
return new MonacoLanguageClient( | ||
{ | ||
name: opts.name || 'DeepForge Language Client', | ||
clientOptions: { | ||
documentSelector: [opts.language || 'python'], | ||
errorHandler: { | ||
error: () => ErrorAction.Continue, | ||
closed: () => CloseAction.DoNotRestart | ||
} | ||
}, | ||
connectionProvider: { | ||
get(errorHandler, closeHandler, /*outputChannel*/) { | ||
return Promise.resolve( | ||
createConnection(connection, errorHandler, closeHandler) | ||
); | ||
} | ||
} | ||
} | ||
); | ||
}; | ||
|
||
const createReconnectingWebSocket = function (url, opts = {}) { | ||
const socketOpts = { | ||
maxReconnectionDelay: opts.socket.maxReconnectionDelay || 10000, | ||
minReconnectionDelay: opts.socket.minReconnectionDelay || 1000, | ||
reconnectionDelayGrowFactor: opts.socket.reconnectionDelayGrowFactor || 1.3, | ||
connectionTimeout: 10000, | ||
maxRetries: Infinity, | ||
debug: opts.socket.debug || false | ||
}; | ||
|
||
return new ReconnectingWebSocket( | ||
url, | ||
[], | ||
socketOpts | ||
); | ||
}; | ||
|
||
const createServices = function (editor, opts) { | ||
const m2p = new MonacoToProtocolConverter(); | ||
const p2m = new ProtocolToMonacoConverter(); | ||
let services = { | ||
commands: new MonacoCommands(editor), | ||
languages: new MonacoLanguages(p2m, m2p), | ||
workspace: new MonacoWorkspace(p2m, m2p, opts.rootUri) | ||
}; | ||
if (opts.debug) { | ||
services.window = new ConsoleWindow(); | ||
} | ||
return services; | ||
}; | ||
|
||
return DeepForgeLanguageClient; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like some odd line breaking...