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的官方介紹請看 //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上也有現成的項目可以用 //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的語法高亮和代碼提示,其實還是很粗糙,需要精心打磨下才能用得舒適。