编辑器坐标系:位置和偏移
编辑器坐标系:位置和偏移
在上一个文本编辑 教程中,展示了如何从Document 对象中获取到 文本插入符(caret) 相关信息。这个示例展示如何使用 文本插入符(caret) 替换 选择的文本。
每个文本插入符(caret) 都包含一些描述它位置的信息。这个教程将带你了解如何从编辑器中获取文本插入符(caret) ,及如何从文本插入符(caret) 中获取信息。
简介
看这部分内容之前,需要了解如何创建和注册Actions,可以查看Action教程
该教程中,使用了示例插件editor_basics 来演示如何获取文本插入符(caret)。示例插件editor_basics 中注册了一个 Caret Position Action。
Caret Position Action 的源码是editor_basics 示例中的EditorIllustrationAction 类,主要看这个类的 EditorAreaIllustration.actionPerformed() 方法,代码如下:
public class EditorAreaIllustration extends AnAction {
public void actionPerformed(@NotNull AnActionEvent event) {
//获取 编辑器 对象
Editor editor = event.getRequiredData(CommonDataKeys.EDITOR);
//获取 文本插入符(caret) 对象
CaretModel caretModel = editor.getCaretModel();
// 获取 primary 文本插入符对象
Caret primaryCaret = caretModel.getPrimaryCaret();
//从 文本插入符(caret) 对象 中获取相关信息
//视觉位置 详见下文
LogicalPosition logicalPos = primaryCaret.getLogicalPosition();
//视觉位置 详见下文
VisualPosition visualPos = primaryCaret.getVisualPosition();
int caretOffset = primaryCaret.getOffset();
// 拼接并显示位置信息
String report = logicalPos.toString() + "\n" +
visualPos.toString() + "\n" +
"Offset: " + caretOffset;
Messages.showInfoMessage(report, "Caret Parameters Inside The Editor");
}
}
下面将分步骤介绍上述代码:
获取文本插入符位置
CaretModel 对象封装了 文本插入符(caret) 的信息,示例代码如下:
public class EditorAreaIllustration extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
//获取 编辑器 对象
Editor editor = event.getRequiredData(CommonDataKeys.EDITOR);
//获取 文本插入符(caret) 对象
CaretModel caretModel = editor.getCaretModel();
}
}
编辑器坐标系统
打开一个Document 时,编辑器会分配一个从0开始 的坐标系。Document 中的第1行和每一行的第1个字符坐标都是从0开始。
每一个字符都会分配一个偏移量对象Offset ,偏移量对象封装了从Document 第一个字符到当前位置的字符数量。
逻辑位置(LogicalPosition )坐标系统包含了当前字符所在行的行号,以及在当前行的位置。注意:逻辑位置坐标系是从0开始的,但是在编辑器的UI上显示的是从1开始的
从编辑器(Editor)还可以通过 HintManager.getHintPosition() 获取代码补全 提示框位置。
还可以获取到编辑器中显示的自定义视觉元素位置,它们被封装为 Inlay 对象。
下面的图表显示了逻辑位置坐标系。下图文本插入符(caret) 选中的红框中的 "s" 的的行号=1 ,列号=9,偏移量=28(注意:行尾的换行符计数,而换行符后的空格不计数),可以从 Offsets 对象中获取到更多的位置信息。
在同一个编辑器中如果只有一个文本插入符(caret),那就是 Primary Caret 对象。 可以在 多个文本插入符 文档中查看多文本插入符 相关内容。
文本插入符逻辑位置
文本插入符的逻辑位置从0开始计数,逻辑位置信息被封装为LogicalPosition 对象。
文本插入符视觉位置
文本插入符的视觉位置从0开始计数,视觉位置信息被封装为VisualPosition 对象。
和逻辑位置不同,代码折叠 和软换行 时 都会 修改字符视觉位置。
如下图:代码折叠后,文本插入符(caret) 的逻辑位置(LogicalPosition)没有改变,但是视觉位置(VisualPosition)第6行在视觉上变成了第2行
如下图:软换行后,文本插入符(caret) 的逻辑位置(LogicalPosition)没有改变,但是视觉位置(VisualPosition)第5行在视觉上变成了第6行
从文本插入符(caret)( Caret) 对象里获取逻辑位置(LogicalPosition)和视觉位置(VisualPosition)对象,代码如下:
public class EditorAreaIllustration extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
//获取 编辑器 和 文本插入符(caret) 对象
Editor editor = event.getRequiredData(CommonDataKeys.EDITOR);
CaretModel caretModel = editor.getCaretModel();
Caret primaryCaret = caretModel.getPrimaryCaret();
//逻辑位置
LogicalPosition logicalPos = primaryCaret.getLogicalPosition();
//视觉位置
VisualPosition visualPos = primaryCaret.getVisualPosition();
}
}
文本插入符列位置
列位置指的是从当前行的开头到 当前插入符 的位置。从0开始计数。注意:注意:列位置从0开始计算的,但是在编辑器的UI上显示的是从1开始的
列位置包含以下信息:
空格,例如 Tabs。Tab占用的列数 等于 Tab设置的占用字符数
文本插入符(caret) 选中的文本
文本插入符倾向(lean)-(还没明白有什么用...)
当文本插入符(caret) 位于2个字符中间时,文本插入符(caret) 可能会关联到它的上一个字符,也可能会关联到它的下一个字符。这个关系很重要,因为视觉位置(VisualPosition)和逻辑位置(LogicalPosition) 并不是完全相等的。
在逻辑位置(LogicalPosition )类中,如果 文本插入符(caret) 跟它的下一个字符有关联性,它就是 Leans Forward 。如果不是Leans Forward,文本插入符(caret) 就跟它的前一个字符有关联性。
在视觉位置(VisualPosition )类中,如果 文本插入符(caret) 跟它的下一个字符有关联性,它就是 Leans Right 。如果不是Leans Right,文本插入符(caret) 就跟它的前一个字符有关联性。
文本插入符偏移量(Offset)
文本插入符的偏移量(Offset)指的是从 Document 开始到文本插入符位置的字符数。偏移量(Offset)是通过逻辑位置(LogicalPosition)计算的,偏移量(Offset)包括以下信息:
Document 第一个字符
空白字符,包括换行符和制表符(Tab)
在 Settings/Preferences | Editor | General | Virtual Space 里配置after end-of-line的字符
文本插入符(caret) 选中的字符
下图示例中,文本插入符(caret) 选中的第2行(逻辑位置从0开始计数,逻辑位置是第1行时,在ui上显示为第2行) 第一个 "/" ,显示的偏移量=22,是因为第1行的换行符也占用了一个字符。