codemirror怎么高亮指定文本

先上图
在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/c070cde11a314c45a859ccb0ca7f41c7.png
产品经理的需求是编辑框中用了占位符的话,占位符中的变量高亮,简单吧!还有一个附加要求,必须是外部定义的变量,不是只用{{}}来区分的,从图中也能看到{{xxx}}就没有高亮。

接到这个需求我的第一反应是想跟产品经理说,这个需求提的很好,下次别提了,哈哈,开玩笑的。

我第一反应想到了用codemirror,以我对codemirror不多的理解,这个需求应该用语言高亮的功能能实现,毕竟我也简单的用过@codemirror/lang-javascript。然后我就开始研究语言包怎么写。研究结果是,语言包只能给定规则,这是用Lezer定义的上下文无关文法实现的,但是我没想到动态传入变量的方法,也就是解决不了上图中{{xxx}}不高亮的问题。

开始了啃codemirror文档的漫长之旅。我参考了文档https://codemirror.net/examples/decoration/中添加下划线的代码,基本实现了使用我想要的功能,不过不完善。

然后把这个需求的优先级放低,先做手上的工作,有空就研究codemirror文档。其实也没啥空。也就昨天下午到今天有空,不死心又去啃文档了。今天终于解决了!最终的解决方案是借鉴了@codemirror/search中的代码实现的

看codemirror的源码发现自己的能力差太多了,好羡慕人家那么强的能力,有空我想通读一下codemirror的源码,一想到它里面对字符串的操作算法我就头大,根本看不懂:)

代码有空在写进来,今天就这样

补全代码如下

// 代码参考了@codemirror/search
import { Decoration, EditorView, ViewPlugin, ViewUpdate, type DecorationSet } from '@codemirror/view'
import { Facet, combineConfig } from '@codemirror/state'

//#region 定义插件
type HighlightOptions = {
  getKeywords: () => string[];
}

const defaultHighlightOptions: HighlightOptions = {
  getKeywords: () => [] 
}

const highlightConfig = Facet.define<HighlightOptions, Required<HighlightOptions>>({
  combine(options: readonly HighlightOptions[]) {
    return combineConfig(options, {})
  }
})

const matchDeco = Decoration.mark({class: "cm-variableMatch"})

const matchHighlighter = ViewPlugin.fromClass(class {
  decorations: DecorationSet
  constructor(view: EditorView) {
    this.decorations = this.getDeco(view)
  }

  generateRanges(text: string, keywords: string[]) {
    const ret = [] as Array<{from: number; to: number}>
    keywords.forEach(keyword => {
        let index = 0
        while((index = text.indexOf(`{{${keyword}}}`, index)) !== -1) {
            ret.push({ from: index + 2, to: index + 2 + keyword.length })
            index += 4 + keyword.length
        }
    })
    return ret
  }

  update(update: ViewUpdate) {
    if (update.docChanged || update.viewportChanged) {
      this.decorations = this.getDeco(update.view)
    }
  }

  getDeco(view: EditorView) {
    const keywords = view.state.facet(highlightConfig).getKeywords()
    const ranges = this.generateRanges(view.state.doc.toString(), keywords)
    if (ranges.length) {
      return Decoration.set(ranges.map(r => matchDeco.range(r.from, r.to)), true)
    }
    return Decoration.none
  }
}, {
  decorations: v => v.decorations
})

const defaultTheme = EditorView.baseTheme({
    ".cm-variableMatch": { color: "#1890FF" }
})
//#endregion

export default (options: HighlightOptions) => {
  return [defaultTheme, matchHighlighter, highlightConfig.of(options)]
}

如果您觉得对您有帮助,请点赞哦:)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值