VS code 使用的代码编辑器

sxkk20082年前知识分享128

前言

有时候我们会有在需要在网页中写代码或者改代码配置的需求,这个时候就需要用到代码编辑器,常规的代码编辑器有 CodeMirrorMonaco Editor, CodeMirror 使用的人比较多,主要因为比较轻量,核心文件压缩后仅 70+ KB,根据所需要支持的语言按需打包,目前 CodeMirror 6 已经完全重构。它支持触摸屏并且极大地提高了库的可访问性。

另一个优秀的库就是 Monaco Editor,它比较重量级,但功能却十分优秀,本文主要介绍下 Monaco Editor 的用法。

Monaco Editor 介绍

Monaco Editor 是 VS code 使用的编辑器,支持丰富的代码格式,拥有良好的可扩展性,支持代码并排对比编辑器,并且友好的支持视觉障碍人士,拥有语音播报功能,但 Monaco Editor 在移动 web 中却不支持。

代码对比

功能

对以下语言支持代码感知和验证

TypeScript, JavaScript, CSS, LESS, SCSS, JSON, HTML

对以下语法支持代码高亮。

XML, PHP, C#, C++, Razor, Markdown, Diff, Java, VB, CoffeeScript, Handlebars, Batch, Pug, F#, Lua, Powershell, Python, Ruby, SASS, R, Objective-C

基本使用

1、 首先安装 monaco-editor

npm install monaco-editor

2、需要一个渲染编辑器的容器节点,我们设置是一个 id 为 container 的 div

<div id="container" style="height: 100%">div>

3、 在 js 文件中引入 monaco editor, 并创建编辑器

import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'

monaco.editor.create(document.getElementById('container'), {
  value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),
})

打开浏览器,我们可以看到编辑器已经成功展示出来

效果

常规配置

我们可以在 create 的第二个参数传递一个 option 参数。

参数说明类型默认值可选值
value编辑器的初始值string--
theme编辑器的主题样式,除了提供的可选值外,也可以通过 monaco.editor.defineTheme 自定义主题string'vs''vs','vs-dark','hc-black'
language编辑器的初始语言,例如可以设置为 javascript, json 等string--
model和编辑器关联的初始模型ITextModel--
lineNumbers控制行数的渲染,如果是 function,那么会使用 return 的内容作为行数展示string/Function'on''on','off','relative', 'interval', '(lineNumber: number) => string'
readOnly控制编辑器是否只读booleanfalse-
autoClosingBrackets自动闭合括号string'languageDefined''always'/'languageDefined'/'beforeWhitespace'/'never'
autoClosingOvertype自动闭合括号或引号string-'always'/'auto'/'never'
autoClosingQuotes自动闭合引号string'languageDefined''always'/'languageDefined'/'beforeWhitespace'/'never'
autoIndent自动缩进string'advanced''none'/'keep'/'brackets'/'advanced'/'full'

在 webpack 中使用

JS 代码

import * as monaco from 'monaco-editor'

self.MonacoEnvironment = {
  getWorkerUrl: function (moduleId, label) {
    if (label === 'json') {
      return './json.worker.bundle.js'
    }
    if (label === 'css' || label === 'scss' || label === 'less') {
      return './css.worker.bundle.js'
    }
    if (label === 'html' || label === 'handlebars' || label === 'razor') {
      return './html.worker.bundle.js'
    }
    if (label === 'typescript' || label === 'javascript') {
      return './ts.worker.bundle.js'
    }
    return './editor.worker.bundle.js'
  },
}

monaco.editor.create(document.getElementById('container'), {
  value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),
  language: 'javascript',
})

然后需要在 webpack 入口添加配置

module.exports = {
  mode: 'development',
  entry: {
    app: './index.js',
    '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',
  },
  output: {
    globalObject: 'self',
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.ttf$/,
        use: ['file-loader'],
      },
    ],
  },
}

上述加载方式是 ESM 的加载方式,默认情况下,monaco editor 附带的所有语言都将包含在内,如果你觉得这样配置麻烦,可以使用 monaco-editor-webpack-plugin,通过只选择特定的语言或者只选择特定的编辑器特性,这样可以用来生成一个更小的编辑器包。

修改 webpack.config.js ,在 languages 填写只包含支持的语言子集。

const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
const path = require('path')

module.exports = {
  entry: './index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'app.js',
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.ttf$/,
        use: ['file-loader'],
      },
    ],
  },
  plugins: [
    new MonacoWebpackPlugin({
      languages: ['typescript', 'html', 'css'],
    }),
  ],
}

值获取

editor.getValue()

获取编辑器中的所有文本,并生成一个字符串返回,会保留所有信息(换行、缩进、注释等等)。

editor.getSelection()

获取编辑器中被选中文案的 range ,返回一个对象,如下:

{
  "startLineNumber": 0,
  "startColumnNumber": 0,
  "endLineNumber": 0,
  "endColumnNumber": 0
}

自定义语言

monaco editor 还可以支持自定义语言,下面代码演示一个日志的编辑器

//  注册一个语言
monaco.languages.register({ id: 'mySpecialLanguage' })

// 通过正则注册解析规则
monaco.languages.setMonarchTokensProvider('mySpecialLanguage', {
  tokenizer: {
    root: [
      [/\[error.*/, 'custom-error'],
      [/\[notice.*/, 'custom-notice'],
      [/\[info.*/, 'custom-info'],
      [/\[[a-zA-Z 0-9:]+\]/, 'custom-date'],
    ],
  },
})

// 定义仅包含与此语言匹配的规则的新主题
monaco.editor.defineTheme('myCoolTheme', {
  base: 'vs',
  inherit: false,
  rules: [
    { token: 'custom-info', foreground: '808080' },
    { token: 'custom-error', foreground: 'ff0000', fontStyle: 'bold' },
    { token: 'custom-notice', foreground: 'FFA500' },
    { token: 'custom-date', foreground: '008800' },
  ],
  colors: {
    'editor.foreground': '#000000',
  },
})

// 注册新语言的代码提示
monaco.languages.registerCompletionItemProvider('mySpecialLanguage', {
  provideCompletionItems: () => {
    var suggestions = [
      {
        label: 'simpleText',
        kind: monaco.languages.CompletionItemKind.Text,
        insertText: 'simpleText',
      },
      {
        label: 'testing',
        kind: monaco.languages.CompletionItemKind.Keyword,
        insertText: 'testing(${1:condition})',
        insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
      },
      {
        label: 'ifelse',
        kind: monaco.languages.CompletionItemKind.Snippet,
        insertText: ['if (${1:condition}) {', '\t$0', '} else {', '\t', '}'].join('\n'),
        insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
        documentation: 'If-Else Statement',
      },
    ]
    return { suggestions: suggestions }
  },
})

monaco.editor.create(document.getElementById('container'), {
  theme: 'myCoolTheme',
  value: getCode(),
  language: 'mySpecialLanguage',
})

效果

image.png

通过这个例子,我们就可以在网页实现友好查看在线日志。

在 react 中使用

目前社区已经封装了 @monaco-editor/react, 而且不需要使用 webpack (或 rollup/parcel/etc)配置文件/插件。

import React from 'react'

import Editor from '@monaco-editor/react'

function App() {
  return <Editor height="90vh" defaultLanguage="javascript" defaultValue="// some comment" />
}

export default App

详情请参考仓库 npm

应用

tailwindcss 的在线运行网站就 https://play.tailwindcss.com/ 就是使用了 monaco-editor 并且拥有智能的语法提示,代码是开源的

play.tailwindcss.com

小结

本文简单介绍了下 monaco-editor,当然还有很多高级功能等待着我们去探索和挖掘, 文中罗列并不全面,深入挖掘请大家参考官网Github ,希望在未来的开发中能够快速上手类似的代码编辑器实现。

以上就是本文全部内容,希望这篇文章对大家有所帮助,也可以参考我往期的文章或者在评论区交流你的想法和心得,欢迎一起探索前端。

相关文章

AI换脸技术的发展与应用——改变面孔的科技革新

AI换脸技术的发展与应用——改变面孔的科技革新

    随着人工智能技术的快速发展,AI换脸技术成为了一个备受关注的热门话题。这项技术结合了深度学习、计算机视觉和图像处理等领域的研究成果,可以实现将一个人的面孔无缝地替换成...

AI绘画教程:从零开始探索数字艺术世界

AI绘画教程:从零开始探索数字艺术世界

  数字艺术是当下最热门的艺术形式之一,而AI技术的出现让数字艺术创作更加便捷和普及化。当下,AI绘画成为数字艺术的一个重要分支,不仅可以让普通人轻松上手进行绘画创作,还可以...

简单介绍一下自己

我是一名 90 后,12 年毕业,工作 9 年,发过传单,做过运营,也把自己当成产品经理。目前是一名小厂前端工程师,日常负责公司 2B 产品开发迭代交付,还有一些公司内部组件、脚手架维护等。这一年很少加班,调休全靠年假了 😊 。

我的 2021

完成的

除了完成开发工作之外,还完成了:

掘金后台统计

  1. 在掘金发布 12 篇文章

  2. 【全栈】第三次重构我的个人博客

  3. 【全栈】模仿在线流程图  processon.com,目前已经下线,掘金实现文章

  4. 【全栈】实现一个简易版 react 低代码平台 https://low-code.runjs.cool/, 目前只实现了视图层,后面的逻辑有些复杂,没有继续下去。

  5. https://dev.to/ 发布 1 篇

9 年小厂老前端的年终总结

前言时光飞逝,岁月如梭,转眼来到 2021 年底,这一年少了些理性,多了点感性,少了些自由,多了一份责任,这一年视乎没做什么事情,但又过得非常充实,最欣慰的是回家有个人等待着我的拥抱,最快乐的是耳边多...

vsinder

一个为程序员设计的约会应用程序,你可以在上面刷代码。

image

通过写一段代码,展现自己,然后通过系统自动匹配交友。还有 ios 和安卓版 app。

小霸王

小霸王是一款基于 vscode 的 nes 游戏插件,能让你在紧张的开发之余在 vscode 里放松身心。通过劳逸结合,提升开发效率。

image.png

盘点那些好玩有趣的 VSCODE 插件

🌈  彩虹屁老婆一个在你写代码时疯狂夸赞你的二次元鼓励师/老婆。📕 仓库地址: github.com📗 插件地址: marketplace.visualstudio.comvsinder一个为程序员设...

人工智能对生活的影响与未来发展趋势

人工智能对生活的影响与未来发展趋势

  随着科技的不断进步,人工智能(AI)已成为当今最热门的话题之一。从医疗到交通,从教育到娱乐,AI正在逐渐改变我们的生活方式和生产力水平。在本文中,我们将探讨人工智能对我们...

AI边缘盒子:新一代技术的创新助力智能化进程加速发展

AI边缘盒子:新一代技术的创新助力智能化进程加速发展

  近年来,随着人工智能技术的快速发展,各行各业都在积极探索如何利用AI推动智能化进程。而AI边缘盒子作为一项新兴技术,在实际应用中扮演着重要角色。本文将从多个角...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。