系列文章
本系列文章已收录到专栏,交流群号:689220994,也可点击链接加入。
前言
在上一篇文章中我们介绍了如何实现 i18n 的方式,其中提到官方建议我们在编写语言文件时将 ASCII 码范围外的字符都使用 Unicode 编码进行表示,这样就导致我们无法直观地看到原始文本,因此本文就来介绍如何实现对 Unicode 字符折叠预览的功能,最终实现效果如下,另外本文所涉及到的完整代码也已上传到GitHub。
实现方式
在正式实现之前先说一下整体的实现思路:
- 引入
com.intellij.properties
插件用于处理properties
格式的语言文件。 - 继承
om.intellij.lang.folding.FoldingBuilderEx
类,重写其中的方式实现折叠字符及预览文本。 - 将实现类注册到
plugin.xml
中。
实现步骤
首先是引入com.intellij.properties
插件并进行配置:
- build.gradle.kts
// 配置开发过程中运行的 IDEA 沙盒信息
intellij {
// IDEA 的版本
version.set("2023.2.5")
// 这里 IU 是指付费版, 也可以选择 IC 对应社区版
type.set("IU")
// 用到的插件
plugins.set(listOf("com.intellij.properties"))
}
- plugin.xml
<depends>com.intellij.properties</depends>
经过上述配置后,我们就可以很方便地去处理properties
文件了。
如果对这里的配置有疑问,建议先看一下本专栏中讲解 PSI 的部分,在 IntelliJ 插件开发中如果想去处理某种语言文件,除了 XML 这种内置的语言,其他都是需要引入相应的插件。
然后是继承FoldingBuilderEx
类,并实现其中的方法:
class UnicodeFoldBuilder: FoldingBuilderEx() {
override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean) =
// 对 properties 文件中的键值对进行遍历
(root as? PropertiesFile)?.properties?.filter {
// 只保留键值非空并且包含 Unicode 字符的键值对
it.value != null && it.key != null && containsUnicodeEscapeSequence(it.value!!)
}?.map {
// 获取折叠区域,这里只截取键值对中的值部分
val startOffset = it.psiElement.startOffset + it.key!!.length + 1
val endOffset = startOffset + it.value!!.length
FoldingDescriptor(it.psiElement.node, TextRange(startOffset, endOffset))
}?.toTypedArray() ?: emptyArray()
/**
* 用于判断字符串中是否包含 Unicode 编码过的字符
*/
private fun containsUnicodeEscapeSequence(str: String) =
Regex("\\\\u[0-9a-fA-F]{4}").containsMatchIn(str)
/**
* 将 Unicode 编码的字符进行反编码
* 这里只对键值对中的值进行反编码,通过截取原始文本中 = 后的内容
*/
override fun getPlaceholderText(node: ASTNode) =
decodeUnicode(node.text.substring(node.text.indexOf("=") + 1))
/**
* 用于将字符串转为 Unicode 编码
*/
private fun decodeUnicode(input: String) = input.replace("\\\\u([0-9a-fA-F]{4})".toRegex())
{
it.groupValues[1].toInt(16).toChar().toString()
}
/**
* 默认将符合条件的文本进行折叠
*/
override fun isCollapsedByDefault(node: ASTNode) = true
}
这里直接参照代码和相应的注释不难理解,其中buildFoldRegions
、getPlaceholderText
、isCollapsedByDefault
三个是我们重写的方法,buildFoldRegions
方法用于收集所有的折叠块区域,getPlaceholderText
用于设置折叠块的预览文本,isCollapsedByDefault
用于设置默认对符合条件的文本进行折叠。
最后在plugin.xml
中进行配置:
<lang.foldingBuilder
language="Properties"
implementationClass="cn.butterfly.unicode.fold.UnicodeFoldBuilder"/>
经过以上配置后,就已经实现了 Unicode 字符折叠预览的功能,不过对于刚编写的内容,还是没办法实现对 Unicode 字符进行折叠,因此这里再增加一个 Action 实现手动对 Unicode 字符进行折叠:
class UnicodeAction: AnAction() {
override fun actionPerformed(e: AnActionEvent) {
ActionManager.getInstance().getAction("CollapseRegion").actionPerformed(e)
}
}
其实平台默认也已经为我们提供了相应的功能,在编辑器中也可以通过右键菜单中的选择来手动对代码块进行折叠和展开:
总结
本文介绍了如何通过 IntelliJ 提供的接口来实现对 Unicode 字符折叠预览的功能,整体实现方式也比较简单,下一篇文章将会介绍如何开发主题。