idea插件开发-自定义语言4-Syntax Highlighter

        SyntaxHighlighter用于指定应如何突出显示特定范围的文本,ColorSettingPage可以定义颜色。

一、Syntax Highter

1、文本属性键

        TextAttributesKey用于指定应如何突出显示特定范围的文本。不同类型的数据比如关键字、数字、字符串等如果要突出显示都需要创建一个TextAttributesKey实例。一个类型如果拥有多个TextAttributesKey突出显示时可以分层——例如,一个键可以定义类型的粗体和另一种颜色。

2、颜色设置

        EditorColorsScheme用来定义一个编辑器要使用哪些TextAttributesKey。这些是可以通过Settings | Editor | Color Scheme 来设置的。可通过com.intellij.colorSettingsPage进行扩展。

    另外 File | Export | Files or Selection to HTML 也采用了同样的配色方案。颜色设置可以参考示例:

final class PropertiesColorsPage implements ColorSettingsPage {private static final AttributesDescriptor[] ATTRS;static {ATTRS = Arrays.stream(PropertiesComponent.values()).map(component -> new AttributesDescriptor(component.getMessagePointer(), component.getTextAttributesKey())).toArray(AttributesDescriptor[]::new);}@Override@NotNullpublic String getDisplayName() {return OptionsBundle.message("properties.options.display.name");}@Overridepublic Icon getIcon() {return AllIcons.FileTypes.Properties;}@Overridepublic AttributesDescriptor @NotNull [] getAttributeDescriptors() {return ATTRS;}@Overridepublic ColorDescriptor @NotNull [] getColorDescriptors() {return ColorDescriptor.EMPTY_ARRAY;}@Override@NotNullpublic SyntaxHighlighter getHighlighter() {return new PropertiesHighlighter();}@Override@NotNullpublic String getDemoText() {return """# This comment starts with '#'greetings=Hello! This comment starts with '!'what\\=to\\=greet : \\'W\\o\\rld\\',\\tUniverse\\n\\uXXXX""";}@Overridepublic Map<String, TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() {return null;}
}

3、词法分析器

        SyntaxHighlighter提供了第一级的语法高亮级别功能,语法高亮器返回TextAttributesKey每个标记类型的实例都可以特别高亮显示。可参考示例:

public class PropertiesHighlighter extends SyntaxHighlighterBase {@Override@NotNullpublic Lexer getHighlightingLexer() {return new PropertiesHighlightingLexer();}@Overridepublic TextAttributesKey @NotNull [] getTokenHighlights(IElementType tokenType) {final PropertiesComponent type = PropertiesComponent.getByTokenType(tokenType);TextAttributesKey key = null;if (type != null) {key = type.getTextAttributesKey();}return SyntaxHighlighterBase.pack(key);}public enum PropertiesComponent {PROPERTY_KEY(TextAttributesKey.createTextAttributesKey("PROPERTIES.KEY", DefaultLanguageHighlighterColors.KEYWORD),PropertiesBundle.messagePointer("options.properties.attribute.descriptor.property.key"),PropertiesTokenTypes.KEY_CHARACTERS),PROPERTY_VALUE(TextAttributesKey.createTextAttributesKey("PROPERTIES.VALUE", DefaultLanguageHighlighterColors.STRING),PropertiesBundle.messagePointer("options.properties.attribute.descriptor.property.value"),PropertiesTokenTypes.VALUE_CHARACTERS),PROPERTY_COMMENT(TextAttributesKey.createTextAttributesKey("PROPERTIES.LINE_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT),PropertiesBundle.messagePointer("options.properties.attribute.descriptor.comment"),PropertiesTokenTypes.END_OF_LINE_COMMENT),PROPERTY_KEY_VALUE_SEPARATOR(TextAttributesKey.createTextAttributesKey("PROPERTIES.KEY_VALUE_SEPARATOR", DefaultLanguageHighlighterColors.OPERATION_SIGN),PropertiesBundle.messagePointer("options.properties.attribute.descriptor.key.value.separator"),PropertiesTokenTypes.KEY_VALUE_SEPARATOR),PROPERTIES_VALID_STRING_ESCAPE(TextAttributesKey.createTextAttributesKey("PROPERTIES.VALID_STRING_ESCAPE", DefaultLanguageHighlighterColors.VALID_STRING_ESCAPE),PropertiesBundle.messagePointer("options.properties.attribute.descriptor.valid.string.escape"),StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN),PROPERTIES_INVALID_STRING_ESCAPE(TextAttributesKey.createTextAttributesKey("PROPERTIES.INVALID_STRING_ESCAPE", DefaultLanguageHighlighterColors.INVALID_STRING_ESCAPE),PropertiesBundle.messagePointer("options.properties.attribute.descriptor.invalid.string.escape"),StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN);private static final Map<IElementType, PropertiesComponent> elementTypeToComponent;private static final Map<TextAttributesKey, PropertiesComponent> textAttributeKeyToComponent;static {elementTypeToComponent = Arrays.stream(values()).collect(Collectors.toMap(PropertiesComponent::getTokenType, Function.identity()));textAttributeKeyToComponent = Arrays.stream(values()).collect(Collectors.toMap(PropertiesComponent::getTextAttributesKey, Function.identity()));}private final TextAttributesKey myTextAttributesKey;private final Supplier<@Nls String> myMessagePointer;private final IElementType myTokenType;PropertiesComponent(TextAttributesKey textAttributesKey, Supplier<@Nls String> messagePointer, IElementType tokenType) {myTextAttributesKey = textAttributesKey;myMessagePointer = messagePointer;myTokenType = tokenType;}public TextAttributesKey getTextAttributesKey() {return myTextAttributesKey;}Supplier<@Nls String> getMessagePointer() {return myMessagePointer;}IElementType getTokenType() {return myTokenType;}static PropertiesComponent getByTokenType(IElementType tokenType) {return elementTypeToComponent.get(tokenType);}static PropertiesComponent getByTextAttribute(TextAttributesKey textAttributesKey) {return textAttributeKeyToComponent.get(textAttributesKey);}static @Nls String getDisplayName(TextAttributesKey key) {final PropertiesComponent component = getByTextAttribute(key);if (component == null) return null;return component.getMessagePointer().get();}static @Nls HighlightSeverity getSeverity(TextAttributesKey key) {final PropertiesComponent component = getByTextAttribute(key);return component == PROPERTIES_INVALID_STRING_ESCAPE? HighlightSeverity.WARNING: null;}}}

语义高亮

        语义突出显示其实是提供了一个额外的着色层,以改善几个相关项(例如,方法参数、局部变量)的视觉区分。可实现com.intellij.highlightVisitor扩展点,这里的颜色设置要实现RainbowColorSettingsPage接口。

4、解析器

        第二级错误突出显示发生在解析期间。如果根据语言的语法,特定的标记序列是无效的,则PsiBuilder.error()方法可以突出显示无效标记并显示一条错误消息,说明它们无效的原因。

5、注释器

        第三层高亮是通过Annotator接口实现。一个插件可以在扩展点中注册一个或多个注释器com.intellij.annotator,这些注释器在后台高亮过程中被调用,以处理自定义语言的 PSI 树中的元素。属性language应设置为此注释器适用的语言 ID。

        注释器不仅可以分析语法,还可以用于 PSI 分析语义,因此可以提供更复杂的语法和错误突出显示逻辑。注释器还可以为其检测到的问题提供快速修复。文件更改时,将增量调用注释器以仅处理 PSI 树中更改的元素。

错误/警告

        大体的代码实现如下:

holder.newAnnotation(HighlightSeverity.WARNING,"Invalid code") // or HighlightSeverity.ERROR.withFix(new MyFix(psiElement)).create();

句法

        大体的代码实现如下:

holder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rangeToHighlight).textAttributes(MyHighlighter.EXTRA_HIGHLIGHT_ATTRIBUTE).create();
完整的示例可参考:
public class PropertiesAnnotator implements Annotator {private static final ExtensionPointName<DuplicatePropertyKeyAnnotationSuppressor>EP_NAME = ExtensionPointName.create("com.intellij.properties.duplicatePropertyKeyAnnotationSuppressor");@Overridepublic void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {if (!(element instanceof Property property)) return;PropertiesFile propertiesFile = property.getPropertiesFile();final String key = property.getUnescapedKey();if (key == null) return;Collection<IProperty> others = propertiesFile.findPropertiesByKey(key);ASTNode keyNode = ((PropertyImpl)property).getKeyNode();if (keyNode == null) return;if (others.size() != 1 &&EP_NAME.findFirstSafe(suppressor -> suppressor.suppressAnnotationFor(property)) == null) {holder.newAnnotation(HighlightSeverity.ERROR,PropertiesBundle.message("duplicate.property.key.error.message")).range(keyNode).withFix(PropertiesQuickFixFactory.getInstance().createRemovePropertyFix(property)).create();}highlightTokens(property, keyNode, holder, new PropertiesHighlighter());ASTNode valueNode = ((PropertyImpl)property).getValueNode();if (valueNode != null) {highlightTokens(property, valueNode, holder, new PropertiesValueHighlighter());}}private static void highlightTokens(final Property property, final ASTNode node, final AnnotationHolder holder, PropertiesHighlighter highlighter) {Lexer lexer = highlighter.getHighlightingLexer();final String s = node.getText();lexer.start(s);while (lexer.getTokenType() != null) {IElementType elementType = lexer.getTokenType();TextAttributesKey[] keys = highlighter.getTokenHighlights(elementType);for (TextAttributesKey key : keys) {final String displayName = PropertiesComponent.getDisplayName(key);final HighlightSeverity severity = PropertiesComponent.getSeverity(key);if (severity != null && displayName != null) {int start = lexer.getTokenStart() + node.getTextRange().getStartOffset();int end = lexer.getTokenEnd() + node.getTextRange().getStartOffset();TextRange textRange = new TextRange(start, end);TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(key);AnnotationBuilder builder = holder.newAnnotation(severity, displayName).range(textRange).enforcedTextAttributes(attributes);int startOffset = textRange.getStartOffset();if (key == PropertiesComponent.PROPERTIES_INVALID_STRING_ESCAPE.getTextAttributesKey()) {builder = builder.withFix(new IntentionAction() {@Override@NotNullpublic String getText() {return PropertiesBundle.message("unescape");}@Override@NotNullpublic String getFamilyName() {return getText();}@Overridepublic boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {if (!BaseIntentionAction.canModify(file)) return false;String text = file.getText();return text.length() > startOffset && text.charAt(startOffset) == '\\';}@Overridepublic void invoke(@NotNull Project project, Editor editor, PsiFile file) {if (file.getText().charAt(startOffset) == '\\') {editor.getDocument().deleteString(startOffset, startOffset + 1);}}@Overridepublic boolean startInWriteAction() {return true;}});}builder.create();}}lexer.advance();}}
}

二、示例

1、定义SyntaxHighlighterFactory

public class SimpleSyntaxHighlighter extends SyntaxHighlighterBase {public static final TextAttributesKey SEPARATOR =createTextAttributesKey("SIMPLE_SEPARATOR", DefaultLanguageHighlighterColors.OPERATION_SIGN);public static final TextAttributesKey KEY =createTextAttributesKey("SIMPLE_KEY", DefaultLanguageHighlighterColors.KEYWORD);public static final TextAttributesKey VALUE =createTextAttributesKey("SIMPLE_VALUE", DefaultLanguageHighlighterColors.STRING);public static final TextAttributesKey COMMENT =createTextAttributesKey("SIMPLE_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT);public static final TextAttributesKey BAD_CHARACTER =createTextAttributesKey("SIMPLE_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER);private static final TextAttributesKey[] BAD_CHAR_KEYS = new TextAttributesKey[]{BAD_CHARACTER};private static final TextAttributesKey[] SEPARATOR_KEYS = new TextAttributesKey[]{SEPARATOR};private static final TextAttributesKey[] KEY_KEYS = new TextAttributesKey[]{KEY};private static final TextAttributesKey[] VALUE_KEYS = new TextAttributesKey[]{VALUE};private static final TextAttributesKey[] COMMENT_KEYS = new TextAttributesKey[]{COMMENT};private static final TextAttributesKey[] EMPTY_KEYS = new TextAttributesKey[0];@NotNull@Overridepublic Lexer getHighlightingLexer() {return new SimpleLexerAdapter();}@Overridepublic TextAttributesKey @NotNull [] getTokenHighlights(IElementType tokenType) {if (tokenType.equals(SimpleTypes.SEPARATOR)) {return SEPARATOR_KEYS;}if (tokenType.equals(SimpleTypes.KEY)) {return KEY_KEYS;}if (tokenType.equals(SimpleTypes.VALUE)) {return VALUE_KEYS;}if (tokenType.equals(SimpleTypes.COMMENT)) {return COMMENT_KEYS;}if (tokenType.equals(TokenType.BAD_CHARACTER)) {return BAD_CHAR_KEYS;}return EMPTY_KEYS;}}
<extensions defaultExtensionNs="com.intellij"><lang.syntaxHighlighterFactorylanguage="Simple"implementationClass="org.intellij.sdk.language.SimpleSyntaxHighlighterFactory"/>
</extensions>

2、定义颜色设置界面

public class SimpleColorSettingsPage implements ColorSettingsPage {private static final AttributesDescriptor[] DESCRIPTORS = new AttributesDescriptor[]{new AttributesDescriptor("Key", SimpleSyntaxHighlighter.KEY),new AttributesDescriptor("Separator", SimpleSyntaxHighlighter.SEPARATOR),new AttributesDescriptor("Value", SimpleSyntaxHighlighter.VALUE),new AttributesDescriptor("Bad value", SimpleSyntaxHighlighter.BAD_CHARACTER)};@Nullable@Overridepublic Icon getIcon() {return SimpleIcons.FILE;}@NotNull@Overridepublic SyntaxHighlighter getHighlighter() {return new SimpleSyntaxHighlighter();}@NotNull@Overridepublic String getDemoText() {return "# You are reading the \".properties\" entry.\n" +"! The exclamation mark can also mark text as comments.\n" +"website = https://en.wikipedia.org/\n" +"language = English\n" +"# The backslash below tells the application to continue reading\n" +"# the value onto the next line.\n" +"message = Welcome to \\\n" +"          Wikipedia!\n" +"# Add spaces to the key\n" +"key\\ with\\ spaces = This is the value that could be looked up with the key \"key with spaces\".\n" +"# Unicode\n" +"tab : \\u0009";}@Nullable@Overridepublic Map<String, TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() {return null;}@Overridepublic AttributesDescriptor @NotNull [] getAttributeDescriptors() {return DESCRIPTORS;}@Overridepublic ColorDescriptor @NotNull [] getColorDescriptors() {return ColorDescriptor.EMPTY_ARRAY;}@NotNull@Overridepublic String getDisplayName() {return "Simple";}}

支持通过用 分隔节点来对运算符或大括号等相关属性进行分组//,例如:

AttributesDescriptor[] DESCRIPTORS = new AttributesDescriptor[] {new AttributesDescriptor("Operators//Plus", MySyntaxHighlighter.PLUS),new AttributesDescriptor("Operators//Minus", MySyntaxHighlighter.MINUS),new AttributesDescriptor("Operators//Advanced//Sigma", MySyntaxHighlighter.SIGMA),new AttributesDescriptor("Operators//Advanced//Pi", MySyntaxHighlighter.PI),//...
};
<extensions defaultExtensionNs="com.intellij"><colorSettingsPageimplementation="org.intellij.sdk.language.SimpleColorSettingsPage"/>
</extensions>

3、测试运行

        颜色配置页面可从Settings | Editor | Color Scheme | Simple查看。如下图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/13380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码-【5 二叉树非递归后序遍历,找指定结点的父节点】

二叉树T按二叉链表存储&#xff0c;求指定结点q的父节点&#xff1a;

【Ubuntu系统18.04虚拟机ros下实现darknet_ros(YOLO V3)检测问题解析最全】

原本打算在搭载Ubuntu18.04的智能小车上面运行使用darknet_ros 包来进行yolov3的检测&#xff0c;但是运行过程中遇到了不少问题&#xff0c;从头到尾部的运行包括遇到的解决方法以及对应的文章一并列出&#xff0c;免得到处查找。 首先是在ROS下实现darknet_ros(YOLO V3)检测…

浅谈自动化测试

谈谈那些实习测试工程师应该掌握的基础知识&#xff08;一&#xff09;_什么时候才能变强的博客-CSDN博客https://blog.csdn.net/qq_17496235/article/details/131839453谈谈那些实习测试工程师应该掌握的基础知识&#xff08;二&#xff09;_什么时候才能变强的博客-CSDN博客h…

使用克拉默法则进行三点定圆(二维)

目录 1.二维圆2.python代码3.计算结果 本文由CSDN点云侠原创&#xff0c;爬虫网站请自重。 1.二维圆 已知不共线的三个点&#xff0c;设其坐标为 ( x 1 , y 1 ) (x_1,y_1) (x1​,y1​)、 ( x 2 , y 2 ) (x_2,y_2) (x2​,y2​)、 ( x 3 , y 3 ) (x_3,y_3) (x3​,y3​)&#xf…

FSM:Full Surround Monodepth from Multiple Cameras

参考代码&#xff1a;None 介绍 深度估计任务作为基础环境感知任务&#xff0c;在基础上构建的3D感知才能更加准确&#xff0c;并且泛化能力更强。单目的自监督深度估计已经有MonoDepth、ManyDepth这些经典深度估计模型了&#xff0c;而这篇文章是对多目自监督深度估计进行探…

使用云服务器和Frp(快速反向代理)框架快速部署实现内网穿透

目录 一. 背景1.1 内网穿透1.2 Frp介绍1.3 Frp配置流程 二. 云服务器配置2.1 配置安全组2.2 编写frps.ini 三. 内网主机配置3.1 编辑frpc.ini文件3.2 启动服务并配置开机自启动 四. 参考文献 一. 背景 现在有一台ubuntu云服务器&#xff0c;我想通过内网穿透将一台内网的主机当…

python多线程

目录 一.多线程的定义 A.什么是多线程&#xff1f; B.多线程如今遇到的挑战 C.总结 二.python中的多线程 A.python中的多线程底层原理&#xff1a; B.全局解释器锁导致python多线程不能实现真正的并行执行&#xff01; C.总结应用场景 三.java多线程&#xff0c;以及…

【Matlab】判断点和多面体位置关系的两种方法实现

我的主页&#xff1a; 技术邻&#xff1a;小铭的ABAQUS学习的技术邻主页博客园 : HF_SO4的主页哔哩哔哩&#xff1a;小铭的ABAQUS学习的个人空间csdn&#xff1a;qgm1702 博客园文章链接&#xff1a; https://www.cnblogs.com/aksoam/p/17590039.html 分别是向量判别法&…

Ubuntu 22.04下对无线网络作静态ip设置

内容如题所示&#xff0c;最近本人安全毕业&#xff0c;参加工作了&#xff0c;此处应有鲜花和掌声&#xff0c;哈哈哈。但新的生活总是有很多的小问题&#xff0c;坎坎坷坷&#xff0c;所以&#xff0c;我继续记录工作和学习生活中遇到的问题。 今天带我的云哥给了我一个ip&am…

Python入门【变量的作用域(全局变量和局部变量)、参数的传递、浅拷贝和深拷贝、参数的几种类型 】(十一)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

51单片机:数码管和矩阵按键

目录 一:动态数码管模块 1:介绍 2:共阴极和共阳极 A:共阴极 B:共阳极 C:转化表 3:74HC138译码器 4:74HC138译码器控制动态数码管 5:数码管显示完整代码 二:矩阵按键模块 1:介绍 2:原理图 3:矩阵按键代码 一:动态数码管模块 1:介绍 LED数码管&#xff1a;数码管是一种…

Verilog语法学习——LV10_使用函数实现数据大小端转换

LV10_使用函数实现数据大小端转换 题目来源于牛客网 [牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page1&tabVerilog篇&topicId301) 题目 描述 在数字芯片设计中&#xff0c;经常把实现特定功能的模块编写成函数&…

一.安装k8s环境

1.初始操作 默认3台服务器都执行 # 关闭防火墙 systemctl stop firewalld systemctl disable firewalld# 关闭selinux sed -i s/enforcing/disabled/ /etc/selinux/config # 永久 setenforce 0 # 临时# 关闭swap swapoff -a # 临时 sed -ri s/.*swap.*/#&/ /etc/fstab…

QT--day3(定时器事件、对话框)

头文件代码&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimerEvent> //定时器事件处理时间头文件 #include <QTime> //时间类 #include <QtTextToSpeech> #include <QPushButton> #include <QLabel&g…

【数据结构】实验六:队列

实验六 队列 一、实验目的与要求 1&#xff09;熟悉C/C语言&#xff08;或其他编程语言&#xff09;的集成开发环境&#xff1b; 2&#xff09;通过本实验加深对队列的理解&#xff0c;熟悉基本操作&#xff1b; 3&#xff09; 结合具体的问题分析算法时间复杂度。 二、…

ubuntu23.04 flush DNS caches

如何在Ubuntu 23.04中刷新DNS缓存 现在&#xff0c;如果你运行的是Ubuntu 23.04&#xff0c;"系统解决 "的方法将不再适用于你。让我们检查一下你目前的缓存大小。打开你的Ubuntu终端&#xff0c;运行以下command&#xff1a; resolvectl statistics现在&#xff0c…

mysql主从同步怎么跳过错误

今天介绍两种mysql主从同步跳过错误的方法&#xff1a; 一、两种方法介绍 1、跳过指定数量的事务&#xff1a; mysql>slave stop; mysql>SET GLOBAL SQL_SLAVE_SKIP_COUNTER 1 #跳过一个事务 mysql>slave start2、修改mysql的配置文件&#xff0c;通过slav…

【QT 网络云盘客户端】——实现文件属性窗口

目录 文件属性对话框 设置字体样式 获取文件的信息 显示文件属性对话框 当我们点击文件中的属性&#xff0c;则会弹出一个属性对话框&#xff1a; 实现过程&#xff1a; 0.设置 属性 菜单项的槽函数。 1.鼠获取鼠标选中的QListWidgetItem,它包含 图标和文件名 2.根据文件…

POLARDB IMCI 白皮书 云原生HTAP 数据库系统 一 数据压缩和打包处理与数据更新

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

十一、数据结构——树(Tree)的基本概念

数据结构之树(Tree) 目录 树的基本概念树的分类树的基本操作树的应用结语 树的基本概念 树是一种重要的数据结构&#xff0c;它在计算机科学中被广泛应用。树的特点是以分层的方式存储数据&#xff0c;具有层次结构&#xff0c;类似于现实生活中的树状结构。在树中&#xff…