1,Monaco-editor与Groovy简介
Monaco-editor是一款功能丰富、高度可定制的代码编辑器,由微软开发并广泛应用于多个开源项目和Web应用程序中。
Monaco-editor支持超过40种编程语言,具有语法高亮、智能代码补全、代码导航、代码片段、错误提示、多光标编辑、自定义键盘快捷键、智能缩进、代码折叠等高级编辑功能。
Monaco-editor对前端语言比较友好,像javascript、css,都自带有语法提示,但像java这类后端语言,Monaco-editor就需要额外的配置才能支持语法提示。
Groovy是一种运行在Java平台上的敏捷动态语言,它结合了Python、Ruby和Smalltalk等语言的许多强大特性,同时保持了与Java的互操作性。Groovy代码简洁、表达力强,能够显著提高开发效率,减少样板代码。它支持静态类型检查,也支持动态类型,让开发者可以根据需要选择最适合的方式编写代码。Groovy广泛用于快速应用开发、脚本编写以及作为Java应用的扩展或替代。由于其与Java的无缝集成,Groovy能够轻松访问Java类库和框架,使得在现有Java项目中引入Groovy变得非常容易。
2,支持Groovy
虽然说Groovy的使用已经比较普遍了,但Monaco-editor仍没有正式支持groovy,不过我们可以给Monaco-editor添加自定义语言来支持groovy。
支持groovy可以分两步走:1)支持groovy语法高亮 2)支持groovy代码提示
2.1,支持groovy语法高亮
npm i monaco-editor@0.30.0 --save
npm i monaco-editor-webpack-plugin@6.0.0 --save-dev
npm i monaco-ace-tokenizer@0.2.3 --save --force // 这个组件版本不太兼容,需要强制安装
安装以上依赖,然后在monaco-editor中注册groovy自定义语言
import { registerRulesForLanguage } from 'monaco-ace-tokenizer';
import GroovyHighlightRules from 'monaco-ace-tokenizer/lib/ace/definitions/groovy';
import * as monaco from 'monaco-editor';
// 注册groovy语言
monaco.languages.register({id: 'groovy'});
// 设置语法高亮规则
registerRulesForLanguage('groovy', new GroovyHighlightRules());
然后就能看到效果了,虽然有点粗糙,但聊胜于无吧。
2.2,支持groovy代码提示
支持groovy代码提示,需要搭建一个groovy的LSP(Language Server Protocol)服务,然后用websocket连接monoca-editor和LSP服务。关于LSP的官方介绍请看 https://microsoft.github.io/language-server-protocol/
LSP官网上列举了Groovy的3个可用LSP服务,笔者选择了第二个
但是LSP服务本身并不支持websocket,它本身是读取控制台输入,然后在控制台返回数据
public class GroovyLanguageServer implements LanguageServer, LanguageClientAware {
public static void main(String[] args) {
InputStream systemIn = System.in;
OutputStream systemOut = System.out;
// redirect System.out to System.err because we need to prevent
// System.out from receiving anything that isn't an LSP message
System.setOut(new PrintStream(System.err));
GroovyLanguageServer server = new GroovyLanguageServer();
Launcher<LanguageClient> launcher = Launcher.createLauncher(server, LanguageClient.class, systemIn, systemOut);
server.connect(launcher.getRemoteProxy());
launcher.startListening();
}
...
}
所以得改造一下,先把输出和输入都对接到websocket。
github上也有现成的项目可以用 https://github.com/MartinKayJr/groovy-ws-language-server.git,直接跑起来就能用,需要jdk17或以上
LSP解决了,接下来就是前端的对接,先安装依赖
npm i @codingame/monaco-jsonrpc@0.3.1 --save
npm i monaco-languageclient@0.18.1 --save
editor.vue
<template>
<div style="width: 100%;height:100%;">
<div class="hello" ref="main" style="width: 100%;height:100%;text-align: left" v-show="model">
</div>
</div>
</template>
<script>
import { listen } from "@codingame/monaco-jsonrpc"
import * as monaco from 'monaco-editor/esm/vs/editor/editor.main.js'
import 'monaco-editor/esm/vs/basic-languages/java/java.contribution'
const { MonacoLanguageClient, CloseAction, ErrorAction, MonacoServices, createConnection } = require('monaco-languageclient')
export default {
name: 'GroovyEditor',
props: {
scriptContent: String
},
data() {
return {
editor: null,
websocket: null,
model: null
}
},
methods: {
createLanguageClient(connection) {
return new MonacoLanguageClient({
name: "Groovy LSP client",
clientOptions: {
documentSelector: ['groovy'],
errorHandler: {
error: () => ErrorAction.Continue,
closed: () => CloseAction.DoNotRestart
}
},
connectionProvider: {
get: (errorHandler, closeHandler) => {
return Promise.resolve(createConnection(connection, errorHandler, closeHandler))
}
}
})
},
createModel (code) {
return monaco.editor.createModel(code, 'groovy', monaco.Uri.file('/home/clouder/temp/Test.groovy'));
},
getValue() {
return this.model.getValue();
}
},
mounted() {
let self = this
MonacoServices.install(monaco)
console.log('init code: ' + this.scriptContent)
let model = this.createModel(this.scriptContent)
this.model = model
this.$nextTick(() => {
this.editor = monaco.editor.create(this.$refs.main, {
model: model
})
// const url = 'ws://127.0.0.1:8666/java-lsp'
const url = `ws://${window.location.hostname}:8999/groovy`
this.websocket = new WebSocket(url)
listen({
webSocket: self.websocket,
onConnection: connection => {
console.log("connect")
const client = self.createLanguageClient(connection);
const disposable = client.start()
connection.onClose(() => disposable.dispose());
console.log(`Connected to "${url}" and started the language client.`);
}
})
})
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
大功告成
3,总结
这里主要是借助了monaco-editor的扩展功能增加了groovy的语法高亮和代码提示,其实还是很粗糙,需要精心打磨下才能用得舒适。