diff --git a/ide-test/org.codehaus.groovy.alltests/src/org/codehaus/groovy/alltests/AllGroovyTests.groovy b/ide-test/org.codehaus.groovy.alltests/src/org/codehaus/groovy/alltests/AllGroovyTests.groovy index fb53cf1638..c2939feccf 100644 --- a/ide-test/org.codehaus.groovy.alltests/src/org/codehaus/groovy/alltests/AllGroovyTests.groovy +++ b/ide-test/org.codehaus.groovy.alltests/src/org/codehaus/groovy/alltests/AllGroovyTests.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2009-2019 the original author or authors. + * Copyright 2009-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -142,7 +142,6 @@ import org.junit.runners.Suite org.codehaus.groovy.eclipse.test.core.util.TokenStreamTests, org.codehaus.groovy.eclipse.test.debug.BreakpointLocationTests, org.codehaus.groovy.eclipse.test.debug.DebugBreakpointsTests, - org.codehaus.groovy.eclipse.test.launch.ConsoleLineTrackerTests, org.codehaus.groovy.eclipse.test.launch.GroovyScriptLaunchShortcutTests, org.codehaus.groovy.eclipse.test.search.FindOccurrencesTests, org.codehaus.groovy.eclipse.test.ui.BracketInserterTests, diff --git a/ide-test/org.codehaus.groovy.eclipse.tests/plugin.xml b/ide-test/org.codehaus.groovy.eclipse.tests/plugin.xml index d7d07fe0c7..b0e4e8d30c 100644 --- a/ide-test/org.codehaus.groovy.eclipse.tests/plugin.xml +++ b/ide-test/org.codehaus.groovy.eclipse.tests/plugin.xml @@ -47,11 +47,4 @@ - - - - diff --git a/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/launch/ConsoleLineTracker.java b/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/launch/ConsoleLineTracker.java deleted file mode 100644 index a00a5e2dba..0000000000 --- a/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/launch/ConsoleLineTracker.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2009-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.codehaus.groovy.eclipse.test.launch; - -import org.eclipse.debug.ui.console.IConsole; -import org.eclipse.debug.ui.console.IConsoleLineTrackerExtension; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; - -/** - * Simple console line tracker extension point that delegates messages - */ -public final class ConsoleLineTracker implements IConsoleLineTrackerExtension { - - /** - * Forwards messages to the delegate when not null - */ - private static IConsoleLineTrackerExtension fDelegate; - private static IConsole fConsole; - - /** - * Sets the delegate, possibly null - */ - public static void setDelegate(IConsoleLineTrackerExtension tracker) { - fDelegate = tracker; - fConsole = null; - } - - @Override - public void dispose() { - if (fDelegate != null) { - fDelegate.dispose(); - } - fConsole = null; - } - - @Override - public synchronized void init(IConsole console) { - fConsole = console; - if (fDelegate != null) { - fDelegate.init(console); - } - } - - /** - * Returns the document backing this console - */ - public static IDocument getDocument() { - return fConsole.getDocument(); - } - - @Override - public void lineAppended(IRegion line) { - if (fDelegate != null) { - fDelegate.lineAppended(line); - } - } - - @Override - public void consoleClosed() { - if (fDelegate != null && fConsole != null) { - fDelegate.consoleClosed(); - } - } -} diff --git a/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/launch/ConsoleLineTrackerTests.groovy b/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/launch/ConsoleLineTrackerTests.groovy deleted file mode 100644 index f608071d68..0000000000 --- a/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/launch/ConsoleLineTrackerTests.groovy +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2009-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.codehaus.groovy.eclipse.test.launch - -import groovy.transform.PackageScope - -import org.codehaus.groovy.eclipse.launchers.GroovyConsoleLineTracker -import org.codehaus.groovy.eclipse.launchers.GroovyConsoleLineTracker.AmbiguousFileLink -import org.codehaus.groovy.eclipse.test.GroovyEclipseTestSuite -import org.eclipse.core.resources.IFile -import org.eclipse.debug.core.model.IProcess -import org.eclipse.debug.core.model.IStreamMonitor -import org.eclipse.debug.core.model.IStreamsProxy -import org.eclipse.debug.ui.console.FileLink -import org.eclipse.debug.ui.console.IConsole -import org.eclipse.jdt.groovy.core.util.ReflectionUtils -import org.eclipse.jface.text.Document -import org.eclipse.jface.text.IDocument -import org.eclipse.jface.text.IRegion -import org.eclipse.jface.text.Region -import org.eclipse.ui.console.IHyperlink -import org.eclipse.ui.console.IOConsoleOutputStream -import org.eclipse.ui.console.IPatternMatchListener -import org.junit.Assert -import org.junit.Before -import org.junit.Test - -final class ConsoleLineTrackerTests extends GroovyEclipseTestSuite { - - GroovyConsoleLineTracker lineTracker - MockConsole console - IDocument doc - - @Before - void setUp() { - doc = new Document() - console = new MockConsole(doc) - lineTracker = new GroovyConsoleLineTracker() - lineTracker.init(console) - } - - @Test - void testNoLink() { - addGroovySource('', 'Bar', 'f') - String contents = 'ahdhjkfsfds' - doc.set(contents) - lineTracker.lineAppended(new Region(0, contents.length())) - Assert.assertNull('Should not have found any hyperlinks', console.lastLink) - } - - @Test - void testLink() { - addGroovySource('', 'Bar', 'f') - String contents = 'at f.Bar.run(Bar.groovy:2)' - doc.set(contents) - lineTracker.lineAppended(new Region(0, contents.length())) - Assert.assertNotNull('Should have found a hyperlink', console.lastLink) - FileLink link = (FileLink) console.lastLink - IFile file = ReflectionUtils.getPrivateField(FileLink, 'fFile', link) - Assert.assertTrue('File should exist', file.isAccessible()) - Assert.assertEquals('File name is wrong', 'Bar.groovy', file.name) - } - - @Test - void testAmbiguousLink() { - addGroovySource('', 'Baz', 'f') - addGroovySource('', 'Baz', 'f', addSourceFolder('other')) - String contents = 'at f.Baz.run(Baz.groovy:2)' - doc.set(contents) - lineTracker.lineAppended(new Region(0, contents.length())) - Assert.assertNotNull('Should have found a hyperlink', console.lastLink) - FileLink link = (FileLink) console.lastLink - Object file = ReflectionUtils.getPrivateField(FileLink, 'fFile', link) - Assert.assertNull('File should be null since the selection is ambiguous', file) - - IFile[] files = ReflectionUtils.getPrivateField(AmbiguousFileLink, 'files', link) - - Assert.assertEquals('Should have found 2 files', 2, files.length) - Assert.assertEquals('File name is wrong', 'Baz.groovy', files[0].name) - Assert.assertEquals('File name is wrong', 'Baz.groovy', files[1].name) - } -} - -@SuppressWarnings('deprecation') -@PackageScope class MockConsole implements IConsole { - - private Map regionLinkMap = [:] - private IHyperlink lastLink = null - - private IDocument doc - - MockConsole(IDocument doc) { - this.doc = doc - } - - @Override - void addLink(org.eclipse.debug.ui.console.IConsoleHyperlink link, int offset, int length) { - } - - @Override - void connect(IStreamsProxy streamsProxy) { - } - - @Override - void connect(IStreamMonitor streamMonitor, String streamIdentifer) { - } - - @Override - IDocument getDocument() { - return doc - } - - @Override - IProcess getProcess() { - return null - } - - @Override - IRegion getRegion(org.eclipse.debug.ui.console.IConsoleHyperlink link) { - return null - } - - @Override - void addLink(IHyperlink link, int offset, int length) { - regionLinkMap.put(link, new Region(offset, length)) - lastLink = link - } - - @Override - void addPatternMatchListener(IPatternMatchListener matchListener) { - } - - @Override - IRegion getRegion(IHyperlink link) { - return regionLinkMap.get(link) - } - - IHyperlink getLastLink() { - return lastLink - } - - @Override - IOConsoleOutputStream getStream(String streamIdentifier) { - return null - } - - @Override - void removePatternMatchListener(IPatternMatchListener matchListener) { - } -} diff --git a/ide/org.codehaus.groovy.eclipse.ui/plugin.xml b/ide/org.codehaus.groovy.eclipse.ui/plugin.xml index 758a65389c..ca8b577637 100644 --- a/ide/org.codehaus.groovy.eclipse.ui/plugin.xml +++ b/ide/org.codehaus.groovy.eclipse.ui/plugin.xml @@ -924,17 +924,20 @@ - - - - - + + + + + + + + + + + diff --git a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/launchers/GroovyConsoleLineTracker.java b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/launchers/GroovyConsoleLineTracker.java index 63fb87a4ff..f023471829 100644 --- a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/launchers/GroovyConsoleLineTracker.java +++ b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/launchers/GroovyConsoleLineTracker.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2019 the original author or authors. + * Copyright 2009-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,199 +15,45 @@ */ package org.codehaus.groovy.eclipse.launchers; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.codehaus.groovy.eclipse.GroovyPlugin; -import org.codehaus.groovy.eclipse.editor.GroovyEditor; -import org.codehaus.jdt.groovy.model.GroovyNature; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.Path; -import org.eclipse.debug.ui.console.FileLink; -import org.eclipse.debug.ui.console.IConsole; -import org.eclipse.debug.ui.console.IConsoleLineTracker; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.groovy.core.util.ReflectionUtils; -import org.eclipse.jdt.internal.core.JavaModelManager; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.window.Window; -import org.eclipse.ui.console.ConsolePlugin; +import org.eclipse.jdt.internal.debug.ui.console.JavaConsoleTracker; +import org.eclipse.jdt.internal.debug.ui.console.JavaStackTraceHyperlink; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.ui.console.IHyperlink; -import org.eclipse.ui.dialogs.ListDialog; -import org.eclipse.ui.model.WorkbenchLabelProvider; - -public class GroovyConsoleLineTracker implements IConsoleLineTracker { - - private static final Pattern LINE_PATTERN = Pattern.compile(".*\\((.*)\\.groovy(:(.*))?\\)"); - - private IConsole console; +import org.eclipse.ui.console.PatternMatchEvent; +import org.eclipse.ui.console.TextConsole; - @Override - public void init(IConsole console) { - this.console = console; - } +/** + * Adds links to consoles for each occurrence of "pack.Type.meth(File.groovy)". + *

+ * NOTE: "pack.Type.meth(File.groovy:line)" is handled by {@code JavaConsoleTracker}. + */ +public class GroovyConsoleLineTracker extends JavaConsoleTracker { - /** - * Hyperlink error lines to the editor. - */ @Override - public void lineAppended(IRegion line) { - if (console == null) return; - - int lineOffset = line.getOffset(); - int lineLength = line.getLength(); + public void matchFound(final PatternMatchEvent event) { + int offset = event.getOffset(); + int length = event.getLength() - 1; + TextConsole console = getConsole(); try { - String consoleLine = console.getDocument().get(lineOffset, lineLength); - GroovyPlugin.trace(consoleLine); - Matcher m = LINE_PATTERN.matcher(consoleLine); - String groovyFileName = null; - int lineNumber = -1; - int openParenIndexAt = -1; - int closeParenIndexAt = -1; - // match - if (m.matches()) { - consoleLine = m.group(0); - openParenIndexAt = consoleLine.indexOf("("); - if (openParenIndexAt >= 0) { - int end = consoleLine.indexOf(".groovy"); - if (end == -1 || (openParenIndexAt + 1) >= end) { - return; - } - String groovyClassName = consoleLine.substring(openParenIndexAt + 1, end); - int classIndex = consoleLine.indexOf(groovyClassName); - int start = 3; - if (classIndex < start || classIndex >= consoleLine.length()) { - return; - } - String groovyFilePath = consoleLine.substring(start, classIndex).trim().replace('.', '/'); - groovyFileName = groovyFilePath + groovyClassName + ".groovy"; - int colonIndex = consoleLine.indexOf(":"); - // get the line number in groovy class - closeParenIndexAt = consoleLine.lastIndexOf(")"); - if (colonIndex > 0) { - lineNumber = Integer.parseInt(consoleLine.substring(colonIndex + 1, closeParenIndexAt)); - } - GroovyPlugin.trace("groovyFile=" + groovyFileName + " lineNumber:" + lineNumber); - } - // hyperlink if we found something - if (groovyFileName != null) { - IFile[] file = searchForFileInLaunchConfig(groovyFileName); - if (file.length == 1) { - IHyperlink link = new FileLink(file[0], GroovyEditor.EDITOR_ID, -1, -1, lineNumber); - console.addLink(link, lineOffset + openParenIndexAt + 1, closeParenIndexAt - openParenIndexAt - 1); - } else if (file.length > 1) { - IHyperlink link = new AmbiguousFileLink(file, GroovyEditor.EDITOR_ID, -1, -1, lineNumber); - console.addLink(link, lineOffset + openParenIndexAt + 1, closeParenIndexAt - openParenIndexAt - 1); - } - } - } - } catch (Exception e) { - GroovyPlugin.getDefault().logError("unexpected error", e); - } - } - - private IFile[] searchForFileInLaunchConfig(String groovyFileName) throws JavaModelException { - List files = new LinkedList<>(); - IJavaProject[] projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects(); - for (IJavaProject javaProject : projects) { - if (GroovyNature.hasGroovyNature(javaProject.getProject())) { - for (IPackageFragmentRoot root : javaProject.getAllPackageFragmentRoots()) { - if (root.getKind() == IPackageFragmentRoot.K_SOURCE) { - IResource resource = root.getResource(); - if (resource.isAccessible() && resource.getType() != IResource.FILE) { - IFile file = ((IContainer) resource).getFile(new Path(groovyFileName)); - if (file.isAccessible()) { - files.add(file); - } - } - } - } - } - } - return files.toArray(new IFile[files.size()]); - } + String consoleExcerpt = console.getDocument().get(offset, length); - IFile chooseFile(final IFile[] files) { - final IFile[] result = new IFile[1]; - ConsolePlugin.getStandardDisplay().syncExec(() -> { - final ListDialog dialog = new ListDialog(ConsolePlugin.getStandardDisplay().getActiveShell()); - dialog.setLabelProvider(new WorkbenchLabelProvider() { + IHyperlink link = new JavaStackTraceHyperlink(console) { @Override - protected String decorateText(String input, Object element) { - return ((IFile) element).getFullPath().toPortableString(); + protected String getLinkText() { + return consoleExcerpt + ":1)"; } - }); - dialog.setTitle("Choose file to open"); - dialog.setInput(files); - dialog.setContentProvider(new FileContentProvider()); - dialog.setAddCancelButton(true); - dialog.setMessage("Select a file:"); - dialog.setBlockOnOpen(true); - int dialogResult = dialog.open(); - if (dialogResult == Window.OK && dialog.getResult().length > 0) { - result[0] = (IFile) dialog.getResult()[0]; - } - }); - return result[0]; - } - - @Override - public void dispose() { - console = null; - } - - //-------------------------------------------------------------------------- - - public class AmbiguousFileLink extends FileLink implements IHyperlink { - IFile[] files; - boolean fileChosen; - - public AmbiguousFileLink(IFile[] files, String editorId, int fileOffset, int fileLength, int fileLineNumber) { - super(null, editorId, fileOffset, fileLength, fileLineNumber); - this.files = files; - } - @Override - public void linkActivated() { - if (!fileChosen) { - IFile file = chooseFile(files); - if (file != null) { - fileChosen = true; - ReflectionUtils.setPrivateField(FileLink.class, "fFile", this, file); + @Override + protected String getTypeName(final String linkText) { + String typeName = linkText.substring(0, linkText.indexOf('(')); + typeName = typeName.substring(0, typeName.lastIndexOf('.')); + return typeName; } - } - if (fileChosen) { - super.linkActivated(); - } - } - } - - public static class FileContentProvider implements IStructuredContentProvider { - - @Override - public Object[] getElements(Object inputElement) { - IFile[] files = (IFile[]) inputElement; - Object[] out = new Object[files.length]; - for (int i = 0; i < out.length; i++) { - out[i] = files[i]; - } - return out; - } - - @Override - public void dispose() { - } + }; - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + int index = consoleExcerpt.indexOf('(') + 1; + console.addHyperlink(link, offset + index, length - index); + } catch (BadLocationException ignore) { } } }