searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

如何让Monaco-editor支持groovy语法高亮和代码提示

2024-07-09 10:00:48
343
0

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的语法高亮和代码提示,其实还是很粗糙,需要精心打磨下才能用得舒适。

 

0条评论
0 / 1000