当前位置:   article > 正文

idea插件开发-Editor_caretoffset

caretoffset

        idea中可操作的文件一种是Document,另一种是PSI,其中Editor组件就是操作Document的载体,在程序层面Editor组件实现为一个名为Editor的对象称为编辑器。Editor可以实现文件打开、定位文档等功能。本章将通过一个例子来完成以下功能:1、使用文本;2、编辑坐标系;3、编辑器事件;4、文本选择;5、文本编辑。完成后的效果如下图所示:

一、Editor组件

        其底层实现就是Swing的JTextArea,IntelliJ 平台给编辑器组件增加了:语法高亮支持、代码完成、代码折叠等功能。

1、组件初始化

Editor组件在初始化进可以指定以下设置:

  • 解析文本字段中的文本所依据的文件类型;
  • 文本字段是只读的还是可编辑的;
  • 文本字段是单行还是多行。

还可以通过EditorCustomization实现定制化:

  • SpellCheckingEditorCustomization禁用拼写检查;
  • HorizontalScrollBarEditorCustomization打开/关闭水平滚动条;
  • ErrorStripeEditorCustomization打开/关闭右侧的错误条纹;

2、组件类别

  • LanguageTextField:在Dialog中做为一个可编辑的字段;
  • TextFieldWithCompletion:附带自动完成功能;
  • EditorTextField:通用组件;

    一个示例程序如下:

  1. PsiFile psiFile = PsiDocumentManager.getInstance(project)
  2. .getPsiFile(editor.getDocument());
  3. PsiElement element = psiFile.findElementAt(editor.getCaretModel().getOffset());
  4. PsiExpressionCodeFragment code =
  5. JavaCodeFragmentFactory.getInstance(project)
  6. .createExpressionCodeFragment("", element, null, true);
  7. Document document =
  8. PsiDocumentManager.getInstance(project).getDocument(code);
  9. EditorTextField myInput =
  10. new EditorTextField(document, project, JavaFileType.INSTANCE);

二、Editor器操作

1、使用文本

实现org.intellij.sdk.editor.EditorIllustrationAction

复写update()方法

  1. public void update(@NotNull final AnActionEvent e) {
  2. // 得到当前打开的project
  3. final Project project = e.getProject();
  4. //也可以用这行代码代替:FileEditorManager.getInstance(project).getSelectedTextEditor()
  5. final Editor editor = e.getData(CommonDataKeys.EDITOR);
  6. // 设置菜单的可见性
  7. e.getPresentation().setEnabledAndVisible(
  8. project != null && editor != null && editor.getSelectionModel().hasSelection()
  9. );
  10. }

        上述代码中可能过以下两种方式取得Editor中的数据模型DataContext:

  • CommonDataKeys.EDITOR.getData(context);
  • FileEditorManager.getInstance(project).getSelectedTextEditor();

        Editor可选择的数据模型:CaretModel、FoldingModel、IndentsModel、ScrollingModel、SoftWrapModel、SelectionModel

复写actionPerformed()方法

  1. @Override
  2. public void actionPerformed(@NotNull final AnActionEvent e) {
  3. final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
  4. final Project project = e.getRequiredData(CommonDataKeys.PROJECT);
  5. final Document document = editor.getDocument();
  6. // 获取选择信息,Caret是一种文本表示方法
  7. Caret primaryCaret = editor.getCaretModel().getPrimaryCaret();
  8. int start = primaryCaret.getSelectionStart();
  9. int end = primaryCaret.getSelectionEnd();
  10. // 替换鼠标选择的文本内容为editor_basics
  11. WriteCommandAction.runWriteCommandAction(project, () ->
  12. document.replaceString(start, end, "editor_basics")
  13. );
  14. // 移除选择操作
  15. primaryCaret.removeSelection();
  16. }

plugin.xml配置

  1. <action
  2. id="EditorBasics.EditorIllustrationAction"
  3. class="org.intellij.sdk.editor.EditorIllustrationAction"
  4. text="Editor Replace Text"
  5. description="Replaces selected text with 'Replacement'."
  6. icon="SdkIcons.Sdk_default_icon">
  7. <add-to-group group-id="EditorPopupMenu" anchor="first"/>
  8. </action>

        最后runide,打开一个文件,鼠标选择文本|右键|Editor Replace Text,会把选择的文本替换为editor_basics。

2、获取文本坐标系

        在系统底层,如果想操作文档中的文本需要知识其坐标位置。坐标系统在idea中有一些比较复杂的逻辑,坐标是当前鼠标插入的位置(即鼠标闪烁处)具体分为:

  • 逻辑位置:最真实的位置,可由Editor.logicalToVisualPosition()取得,格式(row, column);
  • 视觉位置:受代码折叠等影响,可由Editor.getVisualPosition()取得,格式(row, column);
  • 列位置:逻辑(位置)行的开头到该行中当前插入符号位置的字符数,从0开始计数;
  • 行位置:从1开始计数;
  • 偏移位置:是从Document开头到插入符号位置的字符数,需要注意换行符算1个字符,而tab一般为4字符,从1开始计数;

实现org.intellij.sdk.editor.EditorAreaIllustration

        update()方法参考EditorIllustrationAction.java类的写法

  1. @Override
  2. public void actionPerformed(@NotNull final AnActionEvent e) {
  3. final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
  4. final CaretModel caretModel = editor.getCaretModel();
  5. final Caret primaryCaret = caretModel.getPrimaryCaret();
  6. // 得到当前鼠标光标的坐标信息
  7. LogicalPosition logicalPos = primaryCaret.getLogicalPosition();
  8. VisualPosition visualPos = primaryCaret.getVisualPosition();
  9. int caretOffset = primaryCaret.getOffset();
  10. String report = logicalPos.toString() + "\n" + visualPos.toString() + "\n" +
  11. "Offset: " + caretOffset;
  12. Messages.showInfoMessage(report, "Caret Parameters Inside The Editor");
  13. }

plugin.xml配置

  1. <action id="EditorBasics.LogicalPositionIllustration"
  2. class="org.intellij.sdk.editor.EditorAreaIllustration"
  3. text="Caret Position"
  4. description="Reports information about the caret position."
  5. icon="SdkIcons.Sdk_default_icon">
  6. <keyboard-shortcut keymap="$default" first-keystroke="control alt G"/>
  7. <add-to-group group-id="EditorPopupMenu" anchor="first"/>
  8. </action>

        最后runide,打开一个文件,鼠标放在文本的任意位置|右键|Caret Position,如下:

       

3、编辑器事件

        本例中实现的功能是任意一次键盘事件都会在文档开头插入一个固定的字符串,详细可参考EditorActionHandler  和 TypedActionHandler 之两个实现。

org.intellij.sdk.editor.EditorHandlerIllustration实现

  1. public class EditorHandlerIllustration extends AnAction {
  2. /**
  3. * Clones a new caret at a higher Logical Position line number.
  4. */
  5. @Override
  6. public void actionPerformed(@NotNull final AnActionEvent e) {
  7. // Editor is known to exist from update, so it's not null
  8. final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
  9. // Get the action manager in order to get the necessary action handler...
  10. final EditorActionManager actionManager = EditorActionManager.getInstance();
  11. // Get the action handler registered to clone carets
  12. final EditorActionHandler actionHandler =
  13. actionManager.getActionHandler(IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW);
  14. // Clone one caret below the active caret
  15. actionHandler.execute(editor, editor.getCaretModel().getPrimaryCaret(), e.getDataContext());
  16. }
  17. @Override
  18. public void update(@NotNull final AnActionEvent e) {
  19. final Project project = e.getProject();
  20. final Editor editor = e.getData(CommonDataKeys.EDITOR);
  21. // Make sure at least one caret is available
  22. boolean menuAllowed = false;
  23. if (editor != null && project != null) {
  24. // Ensure the list of carets in the editor is not empty
  25. menuAllowed = !editor.getCaretModel().getAllCarets().isEmpty();
  26. }
  27. e.getPresentation().setEnabledAndVisible(menuAllowed);
  28. }
  29. }

需要注意上述代码.getActionHandler(IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW); 中IdeActions.ACTION_EDITOR_CLONE_CARET_BELOW的描述。在一个editor中有很多处理器,这些全是全局性的。

plugin.xml配置

  1. <action id="EditorBasics.EditorHandlerIllustration"
  2. class="org.intellij.sdk.editor.EditorHandlerIllustration"
  3. text="Editor Add Caret"
  4. description="Adds a second caret below the existing one."
  5. icon="SdkIcons.Sdk_default_icon">
  6. <add-to-group group-id="EditorPopupMenu" anchor="first"/>
  7. </action>

定义handler

  1. public class MyTypedHandler extends TypedHandlerDelegate {
  2. @NotNull
  3. @Override
  4. public Result charTyped(char c, @NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
  5. // Get the document and project
  6. final Document document = editor.getDocument();
  7. // Construct the runnable to substitute the string at offset 0 in the document
  8. Runnable runnable = () -> document.insertString(0, "editor_basics\n");
  9. // Make the document change in the context of a write action.
  10. WriteCommandAction.runWriteCommandAction(project, runnable);
  11. return Result.STOP;
  12. }
  13. }

配置handler

实现方式有两种,两种二选一:

  • xml配置(建议)

  1. <extensions defaultExtensionNs="com.intellij">
  2. <typedHandler implementation="org.intellij.sdk.editor.MyTypedHandler"/>
  3. </extensions>
  •   编码实现

  1. public class EditorHandlerIllustration extends AnAction {
  2. static {
  3. EditorActionManager actionManager = EditorActionManager.getInstance();
  4. TypedAction typedAction = actionManager.getTypedAction();
  5. typedAction.setupHandler(new MyTypedHandler());
  6. }
  7. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/112110
推荐阅读
相关标签
  

闽ICP备14008679号