Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Netbeans cannot delete some text when editing TOML files #8174

Open
niabot opened this issue Jan 20, 2025 · 15 comments · May be fixed by #8192
Open

Netbeans cannot delete some text when editing TOML files #8174

niabot opened this issue Jan 20, 2025 · 15 comments · May be fixed by #8192
Assignees
Labels

Comments

@niabot
Copy link

niabot commented Jan 20, 2025

Apache NetBeans version

Apache NetBeans 24

What happened

When editing TOML files for Gradle projects the editor hangs if there is a temporary syntax error in the files. At first the editor won't let me type anything within unmatched curly braces. Deleting the braces is also not possible. Under some circumstances the entire editor (and netbeans) hangs (endless loop). I get the following or similar exceptions:

java.lang.IllegalStateException: Lexer org.netbeans.modules.languages.toml.TomlLexer@4eeb0fe6
  returned null token but lexerInput.readLength()=2
  lexer-state: -1
  tokenStartOffset=1778, readOffset=1780, lookaheadOffset=1781
  Chars: "\n\n" - these characters need to be tokenized.
Fix the lexer to not return null token in this state.
	at org.netbeans.lib.lexer.LexerInputOperation.checkLexerInputFinished(LexerInputOperation.java:435)
	at org.netbeans.lib.lexer.LexerInputOperation.nextToken(LexerInputOperation.java:193)
	at org.netbeans.lib.lexer.inc.IncTokenList.tokenOrEmbeddingImpl(IncTokenList.java:170)
	at org.netbeans.lib.lexer.inc.IncTokenList.tokenOrEmbedding(IncTokenList.java:165)
	at org.netbeans.api.lexer.TokenSequence.moveNext(TokenSequence.java:458)
	at org.netbeans.modules.textmate.lexer.SyntaxHighlighting$TSInfo.moveNextToken(SyntaxHighlighting.java:785)
	at org.netbeans.modules.textmate.lexer.SyntaxHighlighting$HSImpl.moveTheSequence(SyntaxHighlighting.java:482)
	at org.netbeans.modules.textmate.lexer.SyntaxHighlighting$HSImpl.moveNext(SyntaxHighlighting.java:431)
	at org.netbeans.modules.editor.lib2.highlighting.DirectMergeContainer$Wrapper.fetchNextHighlight(DirectMergeContainer.java:600)
	at org.netbeans.modules.editor.lib2.highlighting.DirectMergeContainer$HlSequence.updateMergeVars(DirectMergeContainer.java:337)
	at org.netbeans.modules.editor.lib2.highlighting.DirectMergeContainer$HlSequence.nextMerge(DirectMergeContainer.java:303)
	at org.netbeans.modules.editor.lib2.highlighting.DirectMergeContainer$HlSequence.moveNext(DirectMergeContainer.java:234)
	at org.netbeans.modules.editor.lib2.highlighting.HighlightsReader.readUntil(HighlightsReader.java:59)
	at org.netbeans.modules.editor.lib2.view.HighlightsViewFactory.restart(HighlightsViewFactory.java:168)
	at org.netbeans.modules.editor.lib2.view.ViewBuilder$FactoryState.init(ViewBuilder.java:1299)
	at org.netbeans.modules.editor.lib2.view.ViewBuilder.createViews(ViewBuilder.java:699)
	at org.netbeans.modules.editor.lib2.view.ViewBuilder.createReplaceRepaintViews(ViewBuilder.java:660)
	at org.netbeans.modules.editor.lib2.view.ViewUpdates.reinitAllViews(ViewUpdates.java:189)
	at org.netbeans.modules.editor.lib2.view.DocumentViewOp.checkViewsInited(DocumentViewOp.java:621)
	at org.netbeans.modules.editor.lib2.view.DocumentView.getPreferredSpan(DocumentView.java:226)
	at java.desktop/javax.swing.plaf.basic.BasicTextUI$RootView.getPreferredSpan(BasicTextUI.java:1454)
	at java.desktop/javax.swing.plaf.basic.BasicTextUI.getPreferredSize(BasicTextUI.java:950)
	at java.desktop/javax.swing.JComponent.getPreferredSize(JComponent.java:1734)
	at java.desktop/javax.swing.JEditorPane.getPreferredSize(JEditorPane.java:1390)
	at org.netbeans.modules.editor.NbEditorUI$LayeredEditorPane.getPreferredSize(NbEditorUI.java:454)
	at java.desktop/javax.swing.ScrollPaneLayout.layoutContainer(ScrollPaneLayout.java:799)
	at com.formdev.flatlaf.ui.FlatScrollPaneUI$FlatScrollPaneLayout.layoutContainer(FlatScrollPaneUI.java:563)
	at java.desktop/java.awt.Container.layout(Container.java:1541)
	at java.desktop/java.awt.Container.doLayout(Container.java:1530)
	at java.desktop/java.awt.Container.validateTree(Container.java:1725)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validate(Container.java:1660)
	at org.netbeans.core.windows.view.ui.DesktopImpl$LayeredLayout.layoutContainer(DesktopImpl.java:529)
	at java.desktop/java.awt.Container.layout(Container.java:1541)
	at java.desktop/java.awt.Container.doLayout(Container.java:1530)
	at java.desktop/java.awt.Container.validateTree(Container.java:1725)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validateTree(Container.java:1734)
	at java.desktop/java.awt.Container.validate(Container.java:1660)
	at java.desktop/javax.swing.RepaintManager$3.run(RepaintManager.java:757)
	at java.desktop/javax.swing.RepaintManager$3.run(RepaintManager.java:755)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
	at java.desktop/javax.swing.RepaintManager.validateInvalidComponents(RepaintManager.java:754)
	at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1896)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:136)
[catch] at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Language / Project Type / NetBeans Component

Gradle multi-project

How to reproduce

Copy the following content in the editor (*.toml) and delete the last brace. It wont get deleted because of an exception. Worse can happen if the you add or delete other braces.

[plugins]
jooq-codegen = { id = "org.jooq.jooq-codegen-gradle", version.ref="jooq" }

Did this work correctly in an earlier version?

No / Don't know

Operating System

Windows 10

JDK

Java 21

Apache NetBeans packaging

Apache NetBeans binary zip

Anything else

No response

Are you willing to submit a pull request?

No

@niabot niabot added kind:bug Bug report or fix needs:triage Requires attention from one of the committers labels Jan 20, 2025
@matthiasblaesing matthiasblaesing removed the needs:triage Requires attention from one of the committers label Jan 22, 2025
@matthiasblaesing
Copy link
Contributor

Reproducible, @lkishalmi @vieiro could you please have a look?

@lkishalmi lkishalmi self-assigned this Jan 22, 2025
@lkishalmi
Copy link
Contributor

Checking.

@lkishalmi
Copy link
Contributor

Could not reproduce. However there is something weird in the stacktrace above.

It has references of org.netbeans.modules.textmate.lexer.SyntaxHighlighting which should not be there.
Is it possibe that some TextMate grammar get registered in that mime-path?

@lkishalmi lkishalmi removed their assignment Jan 22, 2025
@vieiro vieiro changed the title Netbeans hangs when editing TOML files Netbeans cannot delete some text when editing TOML files Jan 23, 2025
@vieiro
Copy link
Contributor

vieiro commented Jan 23, 2025

Hi, I can see what @niabot says. In my case NetBeans does not "hang", but can't delete the last } in the given example.

I'll try to take a look at it later on.

For the record, here's the message I get in the IDE Log:

SEVERE [global]
java.lang.IllegalStateException: Lexer org.netbeans.modules.languages.toml.TomlLexer@419edac2
  returned null token but lexerInput.readLength()=2
  lexer-state: -1
  tokenStartOffset=85, readOffset=87, lookaheadOffset=88
  Chars: "\n\n" - these characters need to be tokenized.
Fix the lexer to not return null token in this state.
	at org.netbeans.lib.lexer.LexerInputOperation.checkLexerInputFinished(LexerInputOperation.java:435)
	at org.netbeans.lib.lexer.LexerInputOperation.nextToken(LexerInputOperation.java:193)
	at org.netbeans.lib.lexer.inc.TokenListUpdater.relex(TokenListUpdater.java:602)
	at org.netbeans.lib.lexer.inc.TokenListUpdater.updateRegular(TokenListUpdater.java:255)
	at org.netbeans.lib.lexer.inc.TokenHierarchyUpdate$UpdateItem.update(TokenHierarchyUpdate.java:325)
	at org.netbeans.lib.lexer.inc.TokenHierarchyUpdate.processLevelInfos(TokenHierarchyUpdate.java:200)
	at org.netbeans.lib.lexer.inc.TokenHierarchyUpdate.updateImpl(TokenHierarchyUpdate.java:171)
	at org.netbeans.lib.lexer.inc.TokenHierarchyUpdate.update(TokenHierarchyUpdate.java:109)
	at org.netbeans.lib.lexer.TokenHierarchyOperation.textModified(TokenHierarchyOperation.java:585)
	at org.netbeans.spi.lexer.TokenHierarchyControl.textModified(TokenHierarchyControl.java:71)
	at org.netbeans.lib.lexer.inc.DocumentInput.textModified(DocumentInput.java:128)
	at org.netbeans.lib.lexer.inc.DocumentInput.removeUpdate(DocumentInput.java:121)
	at org.netbeans.lib.editor.util.swing.PriorityDocumentListenerList.removeUpdate(PriorityDocumentListenerList.java:91)
	at java.desktop/javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:285)
	at org.netbeans.editor.BaseDocument.fireRemoveUpdate(BaseDocument.java:1656)
	at org.netbeans.editor.BaseDocument.handleRemove(BaseDocument.java:1026)
	at org.netbeans.editor.BaseDocument$FilterBypassImpl.remove(BaseDocument.java:2625)
	at java.desktop/javax.swing.text.DocumentFilter.remove(DocumentFilter.java:84)
	at org.openide.text.CloneableEditorSupport$DocFilter.remove(CloneableEditorSupport.java:2361)
	at org.netbeans.editor.BaseDocument.remove(BaseDocument.java:939)
	at org.netbeans.editor.BaseKit$DeleteCharAction$3.run(BaseKit.java:2184)
	at org.netbeans.editor.GuardedDocument.runAtomicAsUser(GuardedDocument.java:333)
	at org.netbeans.editor.BaseKit$DeleteCharAction.actionPerformed(BaseKit.java:2176)
	at org.netbeans.modules.csl.core.CslEditorKit$GsfDeleteCharAction.actionPerformed(CslEditorKit.java:375)
	at org.netbeans.editor.BaseAction.actionPerformed(BaseAction.java:324)
	at java.desktop/javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1810)
	at java.desktop/javax.swing.JComponent.processKeyBinding(JComponent.java:2956)
	at java.desktop/javax.swing.JComponent.processKeyBindings(JComponent.java:3004)
	at java.desktop/javax.swing.JComponent.processKeyEvent(JComponent.java:2918)
	at java.desktop/java.awt.Component.processEvent(Component.java:6398)
	at java.desktop/java.awt.Container.processEvent(Container.java:2266)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4996)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4828)
	at java.desktop/java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1952)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:883)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1146)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:1020)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:848)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4877)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4828)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:98)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:136)
[catch] at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
line 2:0 token recognition error at: '\n'
line 3:0 token recognition error at: '\n'

@vieiro
Copy link
Contributor

vieiro commented Jan 23, 2025

I think this may happen in any other antlr4 lexers. The bridge hiccups when the lexer returns null for a token (due to a lexer/parsing error).

This does not mean that the antlr4 grammar is wrong. The antlr4 [lexer] grammar works correctly for correct files, but can't handle a file with a missing }, for example. For antlr4 grammars to work correctly with the antlr editor bridge, the grammars must contemplate an "error" token and not just return null on incorrect files.

@vieiro vieiro self-assigned this Jan 23, 2025
@niabot
Copy link
Author

niabot commented Jan 24, 2025

@vieiro The simple example (deleting the last curly brace) did not "hang" Netbeans. But i also managed to get it stuck in an infinite loop by copying/cutting text. This was my workaround for not being able to type or delete a curly brace. This intial bug might have triggered another bug/effect down the line, but i have no stacktrace/exception of it.

@vieiro
Copy link
Contributor

vieiro commented Jan 24, 2025

Thanks, @niabot . Let us know of any other failures you may be seeing. Not sure if this may go to NB25, though. I think we're almost done with it.

@lkishalmi
Copy link
Contributor

Managed to reproduce. The issue is in the ANTLR Lexer for TOML

To reproduce just have the following toml:

a = {}

then delete the last curly from right with <backspace>.

The problem is that ANTLR sends an EOF token in this case, while still having some characters on the stream.

I can try to patch the bridge to handle this cases better, though it would be the best to fix the TOML Lexer grammar.

@lkishalmi
Copy link
Contributor

@vieiro I see this PR in your project. vieiro/toml-java#18

That could help. Also each mode shall have an rule at the end that matches everything, maps to INVALID_TYPE and/or pops from the mode.

@vieiro
Copy link
Contributor

vieiro commented Jan 24, 2025

Thanks @lkishalmi . I'll create a new PR that will help. Basically the lexer will have to return an "error" token whenever an invalid character is found. I'll explain during the weekend.

@vieiro
Copy link
Contributor

vieiro commented Jan 24, 2025

That'd be a requirement for all antlr4 grammars that we currently use. The rust grammar does indeed detect these error cases too, IIRC.

vieiro added a commit to vieiro/netbeans-cnd that referenced this issue Jan 25, 2025
@vieiro vieiro linked a pull request Jan 25, 2025 that will close this issue
@mbien mbien linked a pull request Jan 25, 2025 that will close this issue
@vieiro
Copy link
Contributor

vieiro commented Jan 25, 2025

Well, there we go this change

INLINE_TABLE_UNEXPECTED : . -> type(INVALID_VALUE), popMode;
INLINE_TABLE_EOF: EOF -> type(INVALID_VALUE), popMode;

We may want to update the antlr tutorial to explain that antlr4 lexers should contemplate error situation (such as this: a TOML inline table without an ending }) and return this "error token" (INVALID_VALUE in this case). That makes it easier for AntlrLexerBridge to map that token to an ERROR. Just throwing/capturing an exception in Antlr is not good enough for us.

@vieiro
Copy link
Contributor

vieiro commented Jan 25, 2025

@vieiro The simple example (deleting the last curly brace) did not "hang" Netbeans. But i also managed to get it stuck in an infinite loop by copying/cutting text. This was my workaround for not being able to type or delete a curly brace. This intial bug might have triggered another bug/effect down the line, but i have no stacktrace/exception of it.

Hi @niabot , the "hang" you are detecting may be due to your specific setup. As @lkishalmi explains you seem to have a texmate highlighing layer that may be interferring/blocking. Next time you can use jconsole or a jps + jstack combination to fetch an stack trace for us, and report again.

@matthiasblaesing
Copy link
Contributor

@vieiro @lkishalmi I don't think your assessment is correct, that the user did something special. Have a look here:

@MimeRegistration(service=HighlightsLayerFactory.class, mimeType="")
public static class FactoryImpl implements HighlightsLayerFactory {
@Override
public HighlightsLayer[] createLayers(Context ctx) {
Document doc = ctx.getDocument();
TokenHierarchy<Document> th = TokenHierarchy.get(doc);
if (th == null) {
return new HighlightsLayer[0];
}
//check the token hierarchy produces the TextmateTokens
return new HighlightsLayer[] {
HighlightsLayer.create(SyntaxHighlighting.class.getName(),
ZOrder.SYNTAX_RACK,
true,
new SyntaxHighlighting(doc))
};
}
}

My reading of this is, that the textmate syntax hightlighter will always run (registered on the empty mimetype). These problem show up at all the locations where the tokensquence is iterated, for the reporter that was syntax highlighting.

@vieiro
Copy link
Contributor

vieiro commented Jan 25, 2025

Yep, thanks @matthiasblaesing. We couldn't reproduce the hang with the stacktrace provides, if the fix does not solve the problem then we'll need to reopen with a stack trace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants