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

Poor experience with code assist #288

Closed
mauromol opened this issue May 4, 2017 · 13 comments
Closed

Poor experience with code assist #288

mauromol opened this issue May 4, 2017 · 13 comments
Assignees

Comments

@mauromol
Copy link

mauromol commented May 4, 2017

Inspired by a code snippet in the old GRECLIPSE-1797.

Consider the following code (you need JUnit 4 in the buildpath):

package a
import static org.junit.Assert.*
import org.junit.After;
import org.junit.Test

final class A {
	MyBean m = new MyBean()

	class MyBean {
		String doSomething(String a, Integer b) {
		}
	}

	@Test final void test() {
		assertNu|
	}
}

Place the cursor at "|" and invoke code assist. Accept assertNull as a completion. You'll get:

assertNull(

Now type "m." and expect to get "m.doSomething" suggested: you get nothing instead!
To get suggestions you absolutely need to add a closing bracket corresponding to the opened bracket of assertNull( invocation, which however was node added by the first completion, so you need to be in this situation:

assertNull(m.|)

Now, invoke code assist again and acceot "m.doSomething", the result is:

assertNull(m.|doSomething()

In other words, the closing bracket of the surrounding invocation of "assertNull" was swallowed.

So, I think there are three problems here (let me know if you prefer me to open separate issues for one or more of them):

  1. probably the first code completion should also add the closing bracket for the call to assertNull()
  2. in any case, in this and many other situations, I find it extremely annoying and unproductive that, if I'm missing the closing bracket for the sorrounding method invocation, I can't get a proper code assist on the argument I'm typing (m.doSomething() in this case). I know this might have something to do with the Groovy parser and its resilience to (temporary) syntax errors, but if Greclipse could handle this correctly it would be an GIANT improvement. (this was filed as the old GRECLIPSE-1796)
  3. when invoking code assist for the inner method invocation, the surrounding closing bracket gets swallowed
@eric-milles
Copy link
Member

eric-milles commented May 4, 2017 via email

@mauromol
Copy link
Author

mauromol commented May 5, 2017

Hi Eric. Yes, I have both suggestions, "assertNull(Object)" and "assertNull(String, Object)", and I choose the first one, just like you.

I had "Try to guess the most likely..." checked and what I get is "assertNull(", not "assertNull(local)". I don't know why I get a different result from yours... I'm using Eclipse Neon.3 (build M20170301-0400), Groovy-Eclipse feature 2.9.2.xx-201705040351-e46 and Groovy Compiler 2.4 2.9.2.xx-201705040351-e46

If I uncheck that checkbox, instead, I get exactly what you describe in point 1). In any case, as you realised already, having the caret after the closing bracket is quite uncomfortable.

Please note that unchecking "Do not use parens..." or checking "Use named arguments..." seems not to make any difference in this context (perhaps it's not clear to me what those options should do).

@eric-milles
Copy link
Member

eric-milles commented May 5, 2017 via email

@eric-milles
Copy link
Member

Can you try again with the latest snapshot? The focus and selection should have moved to the first argument. Not sure about the incomplete replacement issue, but am have found all the relevant code and can add some logging if it is still happening.

@mauromol
Copy link
Author

mauromol commented May 7, 2017

I'm trying on another Eclipse installation with Greclipse 2.9.2.xx-201705070120-e46.

  • assertNu| completion, with or without "Try to guess..." now works fine, thank you! :-)
  • assertNull(m.doSom|) also works fine and does not swallow the closing bracket! :-)
  • assertNull(m.doSom| (without the closing bracket) does not show any meaningful proposal; a couple of times it also gave errors like the following, but I could not find a way to reproduce such errors reliably:
eclipse.buildId=4.6.3.M20170301-0400
java.version=1.8.0_131
java.vendor=Oracle Corporation
BootLoader constants: OS=linux, ARCH=x86_64, WS=gtk, NL=it_IT
Command-line arguments:  -os linux -ws gtk -arch x86_64

org.eclipse.jdt.ui
Warning
Sun May 07 15:00:22 CEST 2017
The 'Groovy Code Completions' proposal computer from the 'org.codehaus.groovy.eclipse.codeassist.completion' plug-in did not complete normally. The extension has thrown a runtime exception.

java.lang.ArrayIndexOutOfBoundsException: 223
	at org.eclipse.jdt.groovy.core.util.CharArraySequence.charAt(CharArraySequence.java:31)
	at org.codehaus.groovy.eclipse.core.util.ExpressionFinder.findPreviousTypeNameToken(ExpressionFinder.java:238)
	at org.codehaus.groovy.eclipse.codeassist.processors.NewFieldCompletionProcessor.findCompletionTypeName(NewFieldCompletionProcessor.java:174)
	at org.codehaus.groovy.eclipse.codeassist.processors.NewFieldCompletionProcessor.generateProposals(NewFieldCompletionProcessor.java:142)
	at org.codehaus.groovy.eclipse.codeassist.requestor.GroovyCompletionProposalComputer.computeCompletionProposals(GroovyCompletionProposalComputer.java:210)
	at org.eclipse.jdt.internal.ui.text.java.CompletionProposalComputerDescriptor.computeCompletionProposals(CompletionProposalComputerDescriptor.java:333)
	at org.eclipse.jdt.internal.ui.text.java.CompletionProposalCategory.computeCompletionProposals(CompletionProposalCategory.java:337)
	at org.eclipse.jdt.internal.ui.text.java.ContentAssistProcessor.collectProposals(ContentAssistProcessor.java:331)
	at org.eclipse.jdt.internal.ui.text.java.ContentAssistProcessor.computeCompletionProposals(ContentAssistProcessor.java:288)
	at org.eclipse.jface.text.contentassist.ContentAssistant$3.run(ContentAssistant.java:1931)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.jface.text.contentassist.ContentAssistant.computeCompletionProposals(ContentAssistant.java:1928)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.computeProposals(CompletionProposalPopup.java:565)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.access$16(CompletionProposalPopup.java:560)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup$2.run(CompletionProposalPopup.java:494)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.showProposals(CompletionProposalPopup.java:487)
	at org.eclipse.jface.text.contentassist.ContentAssistant.showPossibleCompletions(ContentAssistant.java:1747)
	at org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor$AdaptedSourceViewer.doOperation(CompilationUnitEditor.java:184)
	at org.eclipse.ui.texteditor.ContentAssistAction$1.run(ContentAssistAction.java:84)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
	at org.eclipse.ui.texteditor.ContentAssistAction.run(ContentAssistAction.java:81)
	at org.eclipse.jface.action.Action.runWithEvent(Action.java:473)
	at org.eclipse.jface.commands.ActionHandler.execute(ActionHandler.java:118)
	at org.eclipse.ui.internal.handlers.E4HandlerProxy.execute(E4HandlerProxy.java:90)
	at sun.reflect.GeneratedMethodAccessor53.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:55)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invokeUsingClass(InjectorImpl.java:282)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invoke(InjectorImpl.java:264)
	at org.eclipse.e4.core.contexts.ContextInjectionFactory.invoke(ContextInjectionFactory.java:132)
	at org.eclipse.e4.core.commands.internal.HandlerServiceHandler.execute(HandlerServiceHandler.java:152)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:494)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:488)
	at org.eclipse.e4.core.commands.internal.HandlerServiceImpl.executeHandler(HandlerServiceImpl.java:210)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.executeCommand(KeyBindingDispatcher.java:286)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.press(KeyBindingDispatcher.java:507)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.processKeyEvent(KeyBindingDispatcher.java:558)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.filterKeySequenceBindings(KeyBindingDispatcher.java:378)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.access$0(KeyBindingDispatcher.java:324)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher$KeyDownFilter.handleEvent(KeyBindingDispatcher.java:86)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1605)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1339)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1366)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1349)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1378)
	at org.eclipse.swt.widgets.Widget.gtk_key_press_event(Widget.java:764)
	at org.eclipse.swt.widgets.Control.gtk_key_press_event(Control.java:3465)
	at org.eclipse.swt.widgets.Composite.gtk_key_press_event(Composite.java:801)
	at org.eclipse.swt.widgets.Widget.windowProc(Widget.java:2000)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:5827)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:5498)
	at org.eclipse.swt.internal.gtk.OS._gtk_main_do_event(Native Method)
	at org.eclipse.swt.internal.gtk.OS.gtk_main_do_event(OS.java:9545)
	at org.eclipse.swt.widgets.Display.eventProc(Display.java:1275)
	at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
	at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:2495)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4149)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:1121)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1022)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:150)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:693)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:610)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:148)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:138)
	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:388)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:243)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:673)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:610)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1519)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1492)

or:

eclipse.buildId=4.6.3.M20170301-0400
java.version=1.8.0_131
java.vendor=Oracle Corporation
BootLoader constants: OS=linux, ARCH=x86_64, WS=gtk, NL=it_IT
Command-line arguments:  -os linux -ws gtk -arch x86_64

org.eclipse.jdt.groovy.core
Error
Sun May 07 15:01:55 CEST 2017
Groovy-Eclipse Type Inferencing: Error visiting types for A.groovy

java.lang.StringIndexOutOfBoundsException: String index out of range: 225
	at java.lang.String.substring(String.java:1963)
	at org.codehaus.groovy.eclipse.codebrowsing.requestor.CodeSelectRequestor.checkQualifiedType(CodeSelectRequestor.java:298)
	at org.codehaus.groovy.eclipse.codebrowsing.requestor.CodeSelectRequestor.handleMatch(CodeSelectRequestor.java:220)
	at org.codehaus.groovy.eclipse.codebrowsing.requestor.CodeSelectRequestor.acceptASTNode(CodeSelectRequestor.java:132)
	at org.eclipse.jdt.groovy.search.TypeInferencingVisitorWithRequestor.notifyRequestor(TypeInferencingVisitorWithRequestor.java:2297)
	at org.eclipse.jdt.groovy.search.TypeInferencingVisitorWithRequestor.visitClassReference(TypeInferencingVisitorWithRequestor.java:720)
	at org.eclipse.jdt.groovy.search.TypeInferencingVisitorWithRequestor.visitClassInternal(TypeInferencingVisitorWithRequestor.java:645)
	at org.eclipse.jdt.groovy.search.TypeInferencingVisitorWithRequestor.visitJDT(TypeInferencingVisitorWithRequestor.java:381)
	at org.eclipse.jdt.groovy.search.TypeInferencingVisitorWithRequestor.visitCompilationUnit(TypeInferencingVisitorWithRequestor.java:351)
	at org.codehaus.groovy.eclipse.codebrowsing.requestor.CodeSelectHelper.selectASTNode(CodeSelectHelper.java:114)
	at org.codehaus.groovy.eclipse.search.GroovyOccurrencesFinder.initialize(GroovyOccurrencesFinder.java:181)
	at org.codehaus.groovy.eclipse.search.GroovyOccurrencesFinder.findOccurrences(GroovyOccurrencesFinder.java:209)
	at org.codehaus.groovy.eclipse.editor.GroovyEditor.updateOccurrenceAnnotations(GroovyEditor.java:1430)
	at org.eclipse.jdt.internal.ui.javaeditor.JavaEditor$6.selectionChanged(JavaEditor.java:3364)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup.calculateASTandInform(SelectionListenerWithASTManager.java:182)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup$3.run(SelectionListenerWithASTManager.java:158)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

@mauromol
Copy link
Author

mauromol commented May 8, 2017

I'm very perplexed. Today I installed Greclipse 2.9.2.xx-201705080332-e46 at work, the system I used when I opened this issue, and, if the checkbox "Guess the most likely parameters for method calls" is checked, then the case assertNu| still completes to assertNull( (with no closing bracket and no guessed parameter name). Yesterday, at home, it completed correctly, as I wrote in my previous comment.

Both systems have a Eclipse Neon.3, at home I have a Linux Mint 17.3 (based on Ubuntu 14.04), here at work I have Windows 10. Here at work I may have some more plugins installed and probably different code formatting options, but I'm not sure what could cause this difference. Do you have any suspect?

@mauromol
Copy link
Author

mauromol commented May 8, 2017

Ok, I was able to find the steps to reproduce my issue!! If I start Eclipse at work on a brand new workspace, all works as expected. When I apply the preferences file I'm going to attach, I reproduce the issue with the incomplete completion I mentioned.
First of all, download and install the Darkest Eclipse Theme from the Marketplace: https://marketplace.eclipse.org/content/darkest-dark-theme
Then start Eclipse on an empty workspace, copy 'n' paste the above code snippet and try asserNu|
Then, import the preferences I'm attaching (decompress the ZIP file first), close the Groovy editor, reopen and type again assertNu|.

I hope you'll be able to reproduce now.

Eclipse preferences - issue.zip

@eric-milles
Copy link
Member

eric-milles commented May 8, 2017

I think I understand why you are seeing some odd behaviors like all the out-of-bounds exceptions. While editing and invoking content assist, the working copy in the editor is not always in sync with the compilation unit (the thing that is parsed and compiled to produce the AST and whatnot). I am using the latter to check things like fully-qualified names (completion on java.util.Map.En and so on).

Okay this probably sounds lame, but if you save the editor buffer before content assisting the reconciler will have a chance to sync up the working copy and the compilation unit. This may be a workaround for some of the oddities you experience while editing. (You should be able to tell that things are out of sync if the syntax highlighting looks funky.) Longer term, I need to find all the places used by content assist that read from the compilation unit and try to get from the working copy instead.

NOTE: The reconciler runs in the background to sync up the working copy and the compilation unit while you type. But there is a delay of a couple seconds that can be noticed while typing and content assisting quickly.

@mauromol
Copy link
Author

mauromol commented May 8, 2017

Yes, I confirm that, apart from the odd behaviour observed once I import the attached preferences, I get a lot of out-of-bounds exceptions and I often experience empty content assists until I save the editor and/or wait some time and then invoke code assist again. This fragility of the Groovy content assist brings a very bad user experience, because it makes the whole thing seem like "crappy" indeed.

It's not very elegant, especially because it would trigger the Eclipse UI freeze monitor, but I personally would prefer a lot if I had to wait a bit for suggestions to show up, but then the list of suggested options were consistent without the need to cycle through proposals multiple times and/or save the editor before retrying.

If you get to fix this, I think the whole user experience of Greclipse would be extremely improved!

@eric-milles
Copy link
Member

Is the dark theme plug-in required to recreate? If so, should this be a bug for them?

I get the expected completions even after importing your preferences.

@mauromol
Copy link
Author

mauromol commented May 9, 2017

I don't know. It would be strange if this problem were directly related to the Dark Theme. I will try to narrow down which is the actual preference that causes this. Maybe I will also understand if it's some other plugin fault.

Meanwhile, did you try to reproduce with that theme installed?

@mauromol
Copy link
Author

mauromol commented May 9, 2017

I tried to copy my Eclipse installation, remove the Darkest Dark Theme plugin, I still reproduce. So I'll try to narrow it down.

@mauromol
Copy link
Author

mauromol commented May 9, 2017

I found the actual cause of the incomplete completion. I'll open a new issue for this.

Do you prefer to keep this open for the content assist from compilation unit vs working copy or do you prefer to create a separate issue for it?

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

No branches or pull requests

2 participants