简体   繁体   English

如何实现自动括弧关闭?

[英]How to implement auto bracket-closing?

I'm developing an eclipse plugin which contains a custom text editor. 我正在开发一个包含自定义文本编辑器的eclipse插件。
I want to implement the functionality of auto closing brackets (and quotation marks) meaning that when the user types ( the editor should automatically insert the corresponding closing bracket ) . 我要实现自动右括号(和引号)的功能,这意味着当用户键入时(编辑器应自动插入相应的右括号)

My current approach is to add a IDocumentListener to the underlying IDocument and whenever the document is changed I look at the new character and if it is one I want to add a closing character to, I'm adding it by setting the text of the document but this always throws my this exception: 我当前的方法是将IDocumentListener添加到基础IDocument ,每当文档更改时,我都会查看新字符,如果要添加一个结束字符,则通过设置文档文本来添加它但这总是抛出我这个异常:

!SESSION 2015-12-22 15:03:53.517 -----------------------------------------------
eclipse.buildId=unknown
java.version=1.8.0_45
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86_64, WS=win32, NL=de_DE
Framework arguments:  -product org.eclipse.sdk.ide
Command-line arguments:  -product org.eclipse.sdk.ide -data C:\Users\Robert Adam\Documents\eclipse.mars.pluginDev\workspace/../runtime-EclipseApplication(1) -dev file:C:/Users/Robert Adam/Documents/eclipse.mars.pluginDev/workspace/.metadata/.plugins/org.eclipse.pde.core/Eclipse Application (1)/dev.properties -os win32 -ws win32 -arch x86_64 -consoleLog

!ENTRY org.eclipse.text 4 2 2015-12-22 15:04:23.611
!MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.text".
!STACK 0
org.eclipse.core.runtime.AssertionFailedException: assertion failed: 
    at org.eclipse.core.runtime.Assert.isTrue(Assert.java:110)
    at org.eclipse.core.runtime.Assert.isTrue(Assert.java:96)
    at org.eclipse.ui.internal.texteditor.quickdiff.DocumentLineDiffer.handleAboutToBeChanged(DocumentLineDiffer.java:816)
    at org.eclipse.ui.internal.texteditor.quickdiff.DocumentLineDiffer.documentAboutToBeChanged(DocumentLineDiffer.java:785)
    at org.eclipse.jface.text.AbstractDocument.fireDocumentAboutToBeChanged(AbstractDocument.java:665)
    at org.eclipse.jface.text.AbstractDocument.set(AbstractDocument.java:1228)
    at org.eclipse.jface.text.AbstractDocument.set(AbstractDocument.java:1217)
    at raven.sqdev.editors.sqfeditor.SQFDocumentListener.handleAddition(SQFDocumentListener.java:61)
    at raven.sqdev.editors.sqfeditor.SQFDocumentListener.documentChanged(SQFDocumentListener.java:33)
    at org.eclipse.jface.text.AbstractDocument.doFireDocumentChanged2(AbstractDocument.java:769)
    at org.eclipse.jface.text.AbstractDocument.doFireDocumentChanged(AbstractDocument.java:736)
    at org.eclipse.jface.text.AbstractDocument.doFireDocumentChanged(AbstractDocument.java:721)
    at org.eclipse.jface.text.AbstractDocument.fireDocumentChanged(AbstractDocument.java:796)
    at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1191)
    at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1210)
    at org.eclipse.jface.text.DefaultDocumentAdapter.replaceTextRange(DefaultDocumentAdapter.java:248)
    at org.eclipse.swt.custom.StyledText.modifyContent(StyledText.java:7268)
    at org.eclipse.swt.custom.StyledText.sendKeyEvent(StyledText.java:8111)
    at org.eclipse.swt.custom.StyledText.doContent(StyledText.java:2481)
    at org.eclipse.swt.custom.StyledText.handleKey(StyledText.java:5955)
    at org.eclipse.swt.custom.StyledText.handleKeyDown(StyledText.java:5986)
    at org.eclipse.swt.custom.StyledText$7.handleEvent(StyledText.java:5663)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
    at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4353)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1061)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1085)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1070)
    at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1112)
    at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1108)
    at org.eclipse.swt.widgets.Widget.wmChar(Widget.java:1529)
    at org.eclipse.swt.widgets.Control.WM_CHAR(Control.java:4722)
    at org.eclipse.swt.widgets.Canvas.WM_CHAR(Canvas.java:343)
    at org.eclipse.swt.widgets.Control.windowProc(Control.java:4610)
    at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:339)
    at org.eclipse.swt.widgets.Display.windowProc(Display.java:5023)
    at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
    at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2549)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3759)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$9.run(PartRenderingEngine.java:1151)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1032)
    at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:148)
    at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:636)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:579)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
    at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:135)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:380)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:235)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:648)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:603)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1465)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1438)

As far as I know this is because I'm changing the text from the listener which is not a good idea as the change itself notifys the listener which can result in an infinite loop. 据我所知,这是因为我正在更改侦听器中的文本,这不是一个好主意,因为更改本身会通知侦听器,这可能导致无限循环。
However I just can't come up with a better idea to implement this functionality. 但是我只是想不出一个更好的主意来实现此功能。

I thought about that this kind of task may be associated with the ContentAssist but I can't find anything about it. 我考虑过这种任务可能与ContentAssist相关联,但是我找不到任何相关信息。

Does anybody know how to properly implement this functionality in my eclipse plugin? 有人知道如何在我的eclipse插件中正确实现此功能吗?

After looking in the sourceCode of the org.eclipse.jdt.ui plugin I found out that they created this feature using a VerifyKeyListener on the SourceViewer of the editor. 在查看org.eclipse.jdt.ui插件的sourceCode之后,我发现他们使用编辑器SourceViewer上的VerifyKeyListener创建了此功能。 It catches all key inputs and has access to the respective text through the event. 它捕获所有关键输入,并可以通过该事件访问相应的文本。

However it turned out to be quite tricky to get to the SourceViewer of my editor as it is created after my editor and therefore the method getSourceViewer() returned null when called in the constructor of my editor. 但是,要在编辑器之后创建它来创建编辑器的SourceViewer却非常棘手,因此在编辑器的构造函数中调用getSourceViewer()方法时返回null
The key was to override createSourceViewer() in my editor class that is declared in AbstractDecoratedTextEditor . 关键是要覆盖在AbstractDecoratedTextEditor声明的编辑器类中的createSourceViewer()
There I did something like this: 在那里,我做了这样的事情:

@Override
    public ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
        ISourceViewer viewer = super.createSourceViewer(parent, ruler, styles);

        if(viewer instanceof ITextViewerExtension) {
            ((ITextViewerExtension) viewer).appendVerifyKeyListener(<Listener>);
        }

        return viewer;
    }

I implemented my own VerifyKeyListern in which I handle finding pairing characters (like opening and closing brackets) and then used something like this inside of the verifyKey() -method: 我实现了自己的VerifyKeyListern在其中我要查找配对字符(例如VerifyKeyListern括号和verifyKey()括号),然后在verifyKey() - verifyKey()内部使用如下所示的verifyKey()

StyledText text = (StyledText) event.getSource();

text.insert(String.valueOf(<pairingCharacter>));

As the typed in character (the opening character) is inserted to the text anyway I only add the corresponding closing charakter via the insert() -method which has the nice effekt that afterwards my cursor is in between these two characters 无论如何,只要将键入的字符(开始字符)插入到文本中,我就只能通过insert()方法添加相应的结束字符-该方法具有很好的效果,之后我的光标位于这两个字符之间

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM