You can subscribe to this list here.
| 2005 |
Jan
|
Feb
|
Mar
(41) |
Apr
(9) |
May
|
Jun
|
Jul
(39) |
Aug
(38) |
Sep
(135) |
Oct
(220) |
Nov
(75) |
Dec
(74) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2006 |
Jan
(44) |
Feb
(160) |
Mar
(49) |
Apr
(69) |
May
(40) |
Jun
(52) |
Jul
(47) |
Aug
(51) |
Sep
(19) |
Oct
(22) |
Nov
(36) |
Dec
(76) |
| 2007 |
Jan
(154) |
Feb
(165) |
Mar
(186) |
Apr
(143) |
May
(175) |
Jun
(133) |
Jul
(203) |
Aug
(177) |
Sep
(136) |
Oct
|
Nov
|
Dec
|
|
From: <caw...@us...> - 2007-07-11 16:08:26
|
Revision: 2747
http://svn.sourceforge.net/rubyeclipse/?rev=2747&view=rev
Author: cawilliams
Date: 2007-07-11 09:08:23 -0700 (Wed, 11 Jul 2007)
Log Message:
-----------
try to improve test
Modified Paths:
--------------
trunk/org.rubypeople.rdt.launching.tests/src/org/rubypeople/rdt/internal/launching/TC_RubyRuntime.java
Modified: trunk/org.rubypeople.rdt.launching.tests/src/org/rubypeople/rdt/internal/launching/TC_RubyRuntime.java
===================================================================
--- trunk/org.rubypeople.rdt.launching.tests/src/org/rubypeople/rdt/internal/launching/TC_RubyRuntime.java 2007-07-11 15:36:48 UTC (rev 2746)
+++ trunk/org.rubypeople.rdt.launching.tests/src/org/rubypeople/rdt/internal/launching/TC_RubyRuntime.java 2007-07-11 16:08:23 UTC (rev 2747)
@@ -1,7 +1,11 @@
package org.rubypeople.rdt.internal.launching;
import java.io.File;
+import java.io.IOException;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
@@ -12,6 +16,7 @@
import org.rubypeople.rdt.launching.IVMInstallType;
import org.rubypeople.rdt.launching.RubyRuntime;
import org.rubypeople.rdt.launching.VMStandin;
+import org.w3c.dom.Document;
public class TC_RubyRuntime extends ModifyingResourceTest {
@@ -86,7 +91,7 @@
}
}
- public void testSetInstalledInterpreters() throws CoreException {
+ public void testSetInstalledInterpreters() throws Exception {
String vmOneName = "InterpreterOne";
String vmOneId = vmOneName;
String vmTwoName = "InterpreterTwo";
@@ -102,7 +107,7 @@
IPath vmOneLocation = folderOne.getLocation();
assertEquals(
"XML should indicate only one interpreter with it being the one selected.",
- Util.convertToIndependantLineDelimiter("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
+ Util.convertToIndependantLineDelimiter(getXMLHeader() +
"<vmSettings defaultVM=\"43,org.rubypeople.rdt.launching.StandardVMType14," + vmOneId + "\">\r\n" +
"<vmType id=\"org.rubypeople.rdt.launching.StandardVMType\">\r\n" +
vmToXML(vmOneId, vmOneName, vmOneLocation) +
@@ -118,7 +123,7 @@
assertEquals(2, vmType.getVMInstalls().length);
assertEquals(
"XML should indicate both interpreters with the first one being selected.",
- Util.convertToIndependantLineDelimiter("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
+ Util.convertToIndependantLineDelimiter(getXMLHeader() +
"<vmSettings defaultVM=\"43,org.rubypeople.rdt.launching.StandardVMType14," + vmOneId + "\">\r\n" +
"<vmType id=\"org.rubypeople.rdt.launching.StandardVMType\">\r\n" +
vmToXML(vmOneId, vmOneName, vmOneLocation) +
@@ -131,7 +136,7 @@
assertEquals(2, vmType.getVMInstalls().length);
assertEquals(
"XML should indicate both interpreters with the second one being selected.",
- Util.convertToIndependantLineDelimiter("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
+ Util.convertToIndependantLineDelimiter(getXMLHeader() +
"<vmSettings defaultVM=\"" + RubyRuntime.getCompositeIdFromVM(standin2) + "\">\r\n" +
"<vmType id=\"org.rubypeople.rdt.launching.StandardVMType\">\r\n" +
vmToXML(vmOneId, vmOneName, vmOneLocation) +
@@ -145,6 +150,11 @@
}
}
+ private String getXMLHeader() throws IOException, TransformerException, ParserConfigurationException {
+ Document doc = LaunchingPlugin.getDocument();
+ return LaunchingPlugin.serializeDocument(doc).trim() + "\r\n";
+ }
+
private String getVMsXML() {
return RubyRuntime.getPreferences().getString(RubyRuntime.PREF_VM_XML);
}
@@ -165,8 +175,8 @@
xml.append("<libraryLocation src=\"");
xml.append(location.toPortableString());
xml.append("/lib/ruby/1.8\"/>\r\n");
- File file = LaunchingPlugin.getFileInPlugin(new Path("ruby" + File.separator + id + File.separator + "lib"));
- if (file != null) {
+ File file = LaunchingPlugin.getDefault().getStateLocation().append(id).append("lib").toFile();
+ if (file != null && file.exists()) {
xml.append("<libraryLocation src=\"");
xml.append(Path.fromOSString(file.toString()).toPortableString());
xml.append("\"/>\r\n");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-11 15:36:49
|
Revision: 2746
http://svn.sourceforge.net/rubyeclipse/?rev=2746&view=rev
Author: cawilliams
Date: 2007-07-11 08:36:48 -0700 (Wed, 11 Jul 2007)
Log Message:
-----------
new method to grab irb (or irb.bat on win32), will be used by our script console stuff in RadRails
Modified Paths:
--------------
trunk/org.rubypeople.rdt.launching/src/org/rubypeople/rdt/launching/RubyRuntime.java
Modified: trunk/org.rubypeople.rdt.launching/src/org/rubypeople/rdt/launching/RubyRuntime.java
===================================================================
--- trunk/org.rubypeople.rdt.launching/src/org/rubypeople/rdt/launching/RubyRuntime.java 2007-07-11 15:24:59 UTC (rev 2745)
+++ trunk/org.rubypeople.rdt.launching/src/org/rubypeople/rdt/launching/RubyRuntime.java 2007-07-11 15:36:48 UTC (rev 2746)
@@ -1690,4 +1690,8 @@
}
return new File(path);
}
+
+ public static File getIRB() {
+ return getBinExecutable("irb");
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-11 15:25:00
|
Revision: 2745
http://svn.sourceforge.net/rubyeclipse/?rev=2745&view=rev
Author: cawilliams
Date: 2007-07-11 08:24:59 -0700 (Wed, 11 Jul 2007)
Log Message:
-----------
Modified Paths:
--------------
trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java
Modified: trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java
===================================================================
--- trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java 2007-07-11 15:24:15 UTC (rev 2744)
+++ trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java 2007-07-11 15:24:59 UTC (rev 2745)
@@ -106,7 +106,7 @@
private IFile workspaceFile;
public SourceElement(String aFilename, RubySourceLocator pSourceLocator) {
filename = aFilename;
- if (filename.startsWith("./")) {
+ if (filename.startsWith("./") && pSourceLocator.projectName != null && pSourceLocator.projectName.trim().length() > 0) {
filename = "/" + pSourceLocator.projectName + filename.substring(1);
}
workspaceFile = RdtDebugCorePlugin.getWorkspace().getRoot().getFileForLocation(new Path(filename));
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-11 15:24:20
|
Revision: 2744
http://svn.sourceforge.net/rubyeclipse/?rev=2744&view=rev
Author: cawilliams
Date: 2007-07-11 08:24:15 -0700 (Wed, 11 Jul 2007)
Log Message:
-----------
fix #5158 - Debugger doesn't open file of breakpoint reached
Modified Paths:
--------------
trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java
trunk/org.rubypeople.rdt.debug.ui.tests/src/org/rubypeople/rdt/internal/debug/ui/TC_RubySourceLocator.java
Modified: trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java
===================================================================
--- trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java 2007-07-10 21:27:04 UTC (rev 2743)
+++ trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java 2007-07-11 15:24:15 UTC (rev 2744)
@@ -25,9 +25,10 @@
* Window>Preferences>Java>Templates. To enable and disable the creation of
* type comments go to Window>Preferences>Java>Code Generation.
*/
-public class RubySourceLocator implements IPersistableSourceLocator, ISourcePresentation { // ISourcePresentation
- // {
+public class RubySourceLocator implements IPersistableSourceLocator, ISourcePresentation {
+
private String absoluteWorkingDirectory;
+ private String projectName;
public RubySourceLocator() {
@@ -54,6 +55,7 @@
*/
public void initializeDefaults(ILaunchConfiguration configuration) throws CoreException {
this.absoluteWorkingDirectory = configuration.getAttribute(IRubyLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, ""); //$NON-NLS-1$
+ this.projectName = configuration.getAttribute(IRubyLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
}
/**
@@ -104,6 +106,9 @@
private IFile workspaceFile;
public SourceElement(String aFilename, RubySourceLocator pSourceLocator) {
filename = aFilename;
+ if (filename.startsWith("./")) {
+ filename = "/" + pSourceLocator.projectName + filename.substring(1);
+ }
workspaceFile = RdtDebugCorePlugin.getWorkspace().getRoot().getFileForLocation(new Path(filename));
if (workspaceFile == null) {
try {
Modified: trunk/org.rubypeople.rdt.debug.ui.tests/src/org/rubypeople/rdt/internal/debug/ui/TC_RubySourceLocator.java
===================================================================
--- trunk/org.rubypeople.rdt.debug.ui.tests/src/org/rubypeople/rdt/internal/debug/ui/TC_RubySourceLocator.java 2007-07-10 21:27:04 UTC (rev 2743)
+++ trunk/org.rubypeople.rdt.debug.ui.tests/src/org/rubypeople/rdt/internal/debug/ui/TC_RubySourceLocator.java 2007-07-11 15:24:15 UTC (rev 2744)
@@ -10,7 +10,9 @@
import org.eclipse.core.internal.resources.Project;
import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -20,7 +22,9 @@
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.CreateFileAction;
import org.rubypeople.rdt.internal.debug.core.model.RubyStackFrame;
import org.rubypeople.rdt.internal.debug.ui.RdtDebugUiPlugin;
import org.rubypeople.rdt.internal.debug.ui.RubySourceLocator;
@@ -35,90 +39,110 @@
}
public void testWorkspaceInternalFile() throws Exception {
-
- Workspace workspace = (Workspace) RdtDebugUiPlugin.getWorkspace() ;
- // Create a project called 'SourceLocatorTest'
- Project p = new TestProject("/SourceLocatorTest", workspace) ; //$NON-NLS-1$
+ createProject("SourceLocatorTest") ; //$NON-NLS-1$
+ createEmptyFile("/SourceLocatorTest/test.rb"); //$NON-NLS-1$
- p.create(null) ;
- p.open(null) ;
- IPath filePath = new Path("/SourceLocatorTest/test.rb") ; //$NON-NLS-1$
- IFile file =RdtDebugUiPlugin.getWorkspace().getRoot().getFile(filePath) ;
- file.create(new ByteArrayInputStream(new byte[0]) ,true, null) ;
-
// using slashes for the workspace internal path is platform independent
- String fullPath = workspace.getRoot().getLocation().toOSString() + File.separator + "SourceLocatorTest/test.rb" ; //$NON-NLS-1$
+ String fullPath = getWorkspaceRoot().getLocation().toOSString() + File.separator + "SourceLocatorTest/test.rb"; //$NON-NLS-1$
- RubySourceLocator sourceLocator = new RubySourceLocator() ;
- RubyStackFrame rubyStackFrame = new RubyStackFrame(null,fullPath, 5, 1) ;
- Object sourceElement = sourceLocator.getSourceElement(rubyStackFrame) ;
- IEditorInput input = sourceLocator.getEditorInput(sourceElement) ;
- assertNotNull(input) ;
- assertTrue(input.exists()) ;
- PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(input, sourceLocator.getEditorId(input, sourceElement)) ;
-
+ RubyStackFrame rubyStackFrame = new RubyStackFrame(null,fullPath, 5, 1);
+ assertCanOpen(rubyStackFrame);
}
- public void testWorkspaceExternalFile() throws Exception {
-
+ public void testWorkspaceExternalFile() throws Exception {
// external File
File tmpFile = File.createTempFile("rubyfile", null) ; //$NON-NLS-1$
RubyStackFrame rubyStackFrame = new RubyStackFrame(null,tmpFile.getAbsolutePath(), 5, 1) ;
- RubySourceLocator sourceLocator = new RubySourceLocator() ;
- Object sourceElement = sourceLocator.getSourceElement(rubyStackFrame) ;
- IEditorInput input = sourceLocator.getEditorInput(sourceElement) ;
- assertNotNull(input) ;
- assertTrue(input.exists()) ;
+ assertCanOpen(rubyStackFrame);
- PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(input, sourceLocator.getEditorId(input, sourceElement)) ;
-
- // set Working Directory to a project location
- Workspace workspace = (Workspace) RdtDebugUiPlugin.getWorkspace() ;
- Project p = new TestProject("/WorkingDirIsProject", workspace) ; //$NON-NLS-1$
- p.create(null) ;
- p.open(null) ;
- sourceLocator.initializeDefaults(new LaunchConfiguration(workspace.getRoot().getLocation().toOSString() + File.separator + "WorkingDirIsProject")) ;
+ // set Working Directory to a project location
+ createProject("WorkingDirIsProject"); //$NON-NLS-1$
+ RubySourceLocator sourceLocator = new RubySourceLocator();
+ sourceLocator.initializeDefaults(new LaunchConfiguration(getWorkspaceRoot().getLocation().toOSString() + File.separator + "WorkingDirIsProject"));
+ assertCanOpen(sourceLocator, rubyStackFrame);
- sourceElement = sourceLocator.getSourceElement(rubyStackFrame) ;
- input = sourceLocator.getEditorInput(sourceElement) ;
- assertNotNull(input) ;
- assertTrue(input.exists()) ;
-
- PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(input, sourceLocator.getEditorId(input, sourceElement)) ;
-
// An External file which is relative to the working directory
// If an external file is found within an include path, ruby seems always to deliver an
// absolte file path. But if the file found relative to the working directory, ruby
// shows a relative path
- String workspacePath = workspace.getRoot().getLocation().toOSString() ;
- File externalFile = new File(workspacePath + File.separator + "externalRelativeRubyFile.rb") ;
- assertTrue(externalFile.createNewFile()) ;
+ String workspacePath = getWorkspaceRoot().getLocation().toOSString();
+ File externalFile = new File(workspacePath + File.separator + "externalRelativeRubyFile.rb");
+ assertTrue(externalFile.createNewFile());
// current directory = working dir = workspacePath/WorkingDirIsProject
- rubyStackFrame = new RubyStackFrame(null,"../externalRelativeRubyFile.rb", 5, 1) ;
-
- sourceElement = sourceLocator.getSourceElement(rubyStackFrame) ;
- input = sourceLocator.getEditorInput(sourceElement) ;
- assertNotNull(input) ;
- assertTrue(input.exists()) ;
-
- PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(input, sourceLocator.getEditorId(input, sourceElement)) ;
-
-
-
+ rubyStackFrame = new RubyStackFrame(null,"../externalRelativeRubyFile.rb", 5, 1);
+ assertCanOpen(sourceLocator, rubyStackFrame);
}
public void testNotExistingFile() throws Exception {
- RubyStackFrame rubyStackFrame = new RubyStackFrame(null,"/tmp/nonexistingtestfile", 5, 1) ; //$NON-NLS-1$
+ RubyStackFrame rubyStackFrame = new RubyStackFrame(null,"/tmp/nonexistingtestfile", 5, 1); //$NON-NLS-1$
+ assertCantOpen(rubyStackFrame);
+ }
+
+ /**
+ * http://aptana.com/trac/ticket/5158
+ * @throws Exception
+ */
+ public void testTracTicket5158() throws Exception {
+ final String projectName = "BugTest"; //$NON-NLS-1$
+ createProject(projectName);
+ createFolder("/" + projectName + "/script"); //$NON-NLS-1$ //$NON-NLS-2$
+ createFolder("/" + projectName + "/config"); //$NON-NLS-1$ //$NON-NLS-2$
+ createFolder("/" + projectName + "/app"); //$NON-NLS-1$ //$NON-NLS-2$
+ createFolder("/" + projectName + "/app/models"); //$NON-NLS-1$ //$NON-NLS-2$
+ createEmptyFile("/" + projectName + "/app/models/arsupport.rb"); //$NON-NLS-1$ //$NON-NLS-2$
- RubySourceLocator sourceLocator = new RubySourceLocator() ;
- Object sourceElement = sourceLocator.getSourceElement(rubyStackFrame) ;
- IEditorInput input = sourceLocator.getEditorInput(sourceElement) ;
- assertNull(input) ;
+ // using slashes for the workspace internal path is platform independent
+ String fullPath = "./script/../config/../app/models/arsupport.rb"; //$NON-NLS-1$
+ RubyStackFrame rubyStackFrame = new RubyStackFrame(null,fullPath, 5, 1);
+ RubySourceLocator sourceLocator = new RubySourceLocator();
+ sourceLocator.initializeDefaults(new LaunchConfiguration(projectName));
+ assertCanOpen(sourceLocator, rubyStackFrame);
}
+ private void assertCanOpen(RubyStackFrame rubyStackFrame) throws PartInitException {
+ assertCanOpen(new RubySourceLocator(), rubyStackFrame);
+ }
+
+ private void assertCanOpen(RubySourceLocator sourceLocator, RubyStackFrame rubyStackFrame) throws PartInitException {
+ Object sourceElement = sourceLocator.getSourceElement(rubyStackFrame);
+ IEditorInput input = sourceLocator.getEditorInput(sourceElement);
+ assertNotNull(input);
+ assertTrue(input.exists());
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(input, sourceLocator.getEditorId(input, sourceElement));
+ }
+
+ private void assertCantOpen(RubyStackFrame rubyStackFrame) {
+ RubySourceLocator sourceLocator = new RubySourceLocator();
+ Object sourceElement = sourceLocator.getSourceElement(rubyStackFrame);
+ IEditorInput input = sourceLocator.getEditorInput(sourceElement);
+ assertNull(input);
+ }
+ private IFile createEmptyFile(String path) throws CoreException {
+ IFile file = getWorkspaceRoot().getFile(new Path(path));
+ file.create(new ByteArrayInputStream(new byte[0]), true, null);
+ return file;
+ }
+
+ private IWorkspaceRoot getWorkspaceRoot() {
+ return RdtDebugUiPlugin.getWorkspace().getRoot();
+ }
+
+ private Project createProject(String name) throws CoreException {
+ Workspace workspace = (Workspace) RdtDebugUiPlugin.getWorkspace();
+ Project p = new TestProject("/" + name, workspace); //$NON-NLS-1$
+ p.create(null);
+ p.open(null);
+ return p;
+ }
+
+ private IFolder createFolder(String path) throws CoreException {
+ IFolder folder = getWorkspaceRoot().getFolder(new Path(path));
+ folder.create(true, true, null);
+ return folder;
+ }
public class TestProject extends Project {
public TestProject(String aName, Workspace aWorkspace) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 21:27:09
|
Revision: 2743
http://svn.sourceforge.net/rubyeclipse/?rev=2743&view=rev
Author: cawilliams
Date: 2007-07-10 14:27:04 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
close #4827 - Integrate docs into code completion proposals
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/CompletionProposal.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/ProposalInfo.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/RubyCompletionProcessor.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/RubyScriptCompletion.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/text/RubySourceViewerConfiguration.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/CompletionProposal.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/CompletionProposal.java 2007-07-10 18:38:06 UTC (rev 2742)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/CompletionProposal.java 2007-07-10 21:27:04 UTC (rev 2743)
@@ -90,6 +90,7 @@
private int flags;
private String type;
private String declaringType;
+ private IRubyElement element;
public CompletionProposal(int kind, String completion, int relevance) {
this.completionKind = kind;
@@ -226,4 +227,12 @@
public void setName(String newName) {
this.name = newName;
}
+
+ public void setElement(IRubyElement element) {
+ this.element = element;
+ }
+
+ public IRubyElement getElement() {
+ return element;
+ }
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-07-10 18:38:06 UTC (rev 2742)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-07-10 21:27:04 UTC (rev 2743)
@@ -1,914 +1,920 @@
-package org.rubypeople.rdt.internal.codeassist;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.jruby.ast.ClassNode;
-import org.jruby.ast.ClassVarAsgnNode;
-import org.jruby.ast.ClassVarDeclNode;
-import org.jruby.ast.ClassVarNode;
-import org.jruby.ast.Colon2Node;
-import org.jruby.ast.ConstDeclNode;
-import org.jruby.ast.ConstNode;
-import org.jruby.ast.DefnNode;
-import org.jruby.ast.DefsNode;
-import org.jruby.ast.InstAsgnNode;
-import org.jruby.ast.InstVarNode;
-import org.jruby.ast.MethodDefNode;
-import org.jruby.ast.ModuleNode;
-import org.jruby.ast.Node;
-import org.jruby.ast.RootNode;
-import org.jruby.lexer.yacc.SyntaxException;
-import org.jruby.parser.StaticScope;
-import org.rubypeople.rdt.core.CompletionProposal;
-import org.rubypeople.rdt.core.CompletionRequestor;
-import org.rubypeople.rdt.core.Flags;
-import org.rubypeople.rdt.core.IMember;
-import org.rubypeople.rdt.core.IMethod;
-import org.rubypeople.rdt.core.IOpenable;
-import org.rubypeople.rdt.core.IRubyElement;
-import org.rubypeople.rdt.core.IRubyModel;
-import org.rubypeople.rdt.core.IRubyProject;
-import org.rubypeople.rdt.core.IRubyScript;
-import org.rubypeople.rdt.core.ISourceRange;
-import org.rubypeople.rdt.core.IType;
-import org.rubypeople.rdt.core.RubyCore;
-import org.rubypeople.rdt.core.RubyModelException;
-import org.rubypeople.rdt.core.search.IRubySearchConstants;
-import org.rubypeople.rdt.core.search.IRubySearchScope;
-import org.rubypeople.rdt.core.search.SearchMatch;
-import org.rubypeople.rdt.core.search.SearchParticipant;
-import org.rubypeople.rdt.core.search.SearchPattern;
-import org.rubypeople.rdt.internal.core.RubyElement;
-import org.rubypeople.rdt.internal.core.RubyType;
-import org.rubypeople.rdt.internal.core.parser.RubyParser;
-import org.rubypeople.rdt.internal.core.search.BasicSearchEngine;
-import org.rubypeople.rdt.internal.core.search.CollectingSearchRequestor;
-import org.rubypeople.rdt.internal.core.util.ASTUtil;
-import org.rubypeople.rdt.internal.core.util.Util;
-import org.rubypeople.rdt.internal.ti.BasicTypeGuess;
-import org.rubypeople.rdt.internal.ti.DefaultTypeInferrer;
-import org.rubypeople.rdt.internal.ti.ITypeGuess;
-import org.rubypeople.rdt.internal.ti.ITypeInferrer;
-import org.rubypeople.rdt.internal.ti.util.AttributeLocator;
-import org.rubypeople.rdt.internal.ti.util.ClosestSpanningNodeLocator;
-import org.rubypeople.rdt.internal.ti.util.INodeAcceptor;
-import org.rubypeople.rdt.internal.ti.util.ScopedNodeLocator;
-
-public class CompletionEngine {
- private static final String OBJECT = "Object";
- private static final String CONSTRUCTOR_INVOKE_NAME = "new";
- private static final String CONSTRUCTOR_DEFINITION_NAME = "initialize";
-
- private CompletionRequestor fRequestor;
- private CompletionContext fContext;
- private Set<IType> fVisitedTypes;
- /**
- * temporary place to hold the original type we're completing for. Used to determine if we should be showing private methods.
- */
- private IType fOriginalType;
-
- public CompletionEngine(CompletionRequestor requestor) {
- this.fRequestor = requestor;
- }
-
- public void complete(IRubyScript script, int offset) throws RubyModelException {
- this.fRequestor.beginReporting();
- fContext = new CompletionContext(script, offset);
- if (fContext.emptyPrefix()) { // no prefix, so we could suggest anything
- suggestMethodsForEnclosingType(script);
- getDocumentsRubyElementsInScope();
- } else {
- if (fContext.isDoubleSemiColon()) {
- String prefix = fContext.getFullPrefix();
- String typeName = prefix.substring(0, prefix.lastIndexOf("::"));
- RubyElementRequestor requestor = new RubyElementRequestor(script);
- IType[] types = requestor.findType(typeName);
- Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
- for (int i = 0; i < types.length; i++) {
- IType type = types[i];
- proposals.putAll(suggestTypesConstants(type));
- // Suggest nested types
- proposals.putAll(suggestNestedTypes(type));
- // Suggest class level methods
- proposals.putAll(suggestMethods(100, type, false));
- }
- List<CompletionProposal> list = new ArrayList<CompletionProposal>(proposals.values());
- Collections.sort(list, new CompletionProposalComparator());
- for (CompletionProposal proposal : list) {
- if (proposal.getCompletion().startsWith(fContext.getPartialPrefix()))
- fRequestor.accept(proposal);
- }
- }
- if (fContext.isConstant()) { // type or constant
- suggestTypeNames();
- suggestConstantNames();
- return;
- }
- if (fContext.isExplicitMethodInvokation()) {
- ITypeInferrer inferrer = new DefaultTypeInferrer();
- List<ITypeGuess> guesses = inferrer.infer(fContext.getCorrectedSource(), fContext.getOffset());
- if (guesses.isEmpty()) {
- guesses.add(new BasicTypeGuess(OBJECT, 100));
- }
- List<CompletionProposal> list = new ArrayList<CompletionProposal>();
- RubyElementRequestor requestor = new RubyElementRequestor(script);
- for (ITypeGuess guess : guesses) {
- final String name = guess.getType();
- if (fContext.isBroken()) {
- Node rootNode = fContext.getRootNode();
- List<Node> typeNodes = ScopedNodeLocator.Instance().findNodesInScope(rootNode, new INodeAcceptor() {
-
- public boolean doesAccept(Node node) {
- if ((node instanceof ClassNode) || (node instanceof ModuleNode)) {
- return ASTUtil.getNameReflectively(node).equals(name);
- }
- return false;
- }
-
- });
- for (Node typeNode : typeNodes) {
- list.addAll(addASTMethodsInScope(typeNode, name));
- }
- }
- IType[] types = requestor.findType(name);
- for (int i = 0; i < types.length; i++) {
- Map<String, CompletionProposal> map = suggestMethods(guess.getConfidence(), types[i], true);
- list.addAll(map.values());
- }
- }
- list.addAll(suggestAllMethodsMatchingPrefix(script));
- Collections.sort(list, new CompletionProposalComparator());
- for (CompletionProposal proposal : list) {
- fRequestor.accept(proposal);
- }
- } else {
- // FIXME If we're invoked on the class declaration (it's super class) don't do this!
- // FIXME Traverse the IRubyElement model, not nodes (and don't reparse)?
- if (fContext.isMethodInvokationOrLocal()) {
- suggestMethodsForEnclosingType(script);
- }
- getDocumentsRubyElementsInScope();
- }
- if (fContext.isGlobal()) { // looks like a global
- suggestGlobals();
- }
- }
- this.fRequestor.endReporting();
- fContext = null;
- }
-
- private Collection<CompletionProposal> addASTMethodsInScope(Node typeNode, String name) {
- List<CompletionProposal> list = new ArrayList<CompletionProposal>();
- if (typeNode == null) return list;
- List<Node> methods = ScopedNodeLocator.Instance().findNodesInScope(typeNode, new INodeAcceptor() {
-
- public boolean doesAccept(Node node) {
- return (node instanceof DefnNode) || (node instanceof DefsNode);
- }
-
- });
- for (Node methodNode : methods) {
- Node scoping = findNearestScope(typeNode, methodNode.getPosition().getStartOffset() - 1);
- if (!scoping.equals(typeNode)) continue;
- MethodDefNode methodDef = (MethodDefNode) methodNode;
- NodeMethod method = new NodeMethod(methodDef);
- CompletionProposal proposal = suggestMethod(method, name, 100);
- if (proposal == null) continue;
- list.add(proposal);
- }
- return list;
- }
-
- private Map<String, CompletionProposal> suggestTypesConstants(IType type) throws RubyModelException {
- Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
- SearchPattern pattern = SearchPattern.createPattern(IRubyElement.CONSTANT, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
- IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {type});
- List<SearchMatch> results = search(pattern, scope);
- for (SearchMatch match: results) {
- IRubyElement element = (IRubyElement) match.getElement();
- if (element.getElementType() != IRubyElement.CONSTANT) continue; // XXX we shouldn't have to do this
- // Add proposal
- CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, element.getElementName());
- proposal.setType(type.getFullyQualifiedName());
- proposal.setName(element.getElementName());
- proposals.put(element.getElementName(), proposal);
- }
- return proposals;
- }
-
- private Map<String, CompletionProposal> suggestNestedTypes(IType type) throws RubyModelException {
- Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
- SearchPattern pattern = SearchPattern.createPattern(IRubyElement.TYPE, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
- IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {type});
- List<SearchMatch> results = search(pattern, scope);
- for (SearchMatch match: results) {
- IType aType = (IType) match.getElement();
- String fullname = aType.getFullyQualifiedName();
- if (fullname.equals(type.getFullyQualifiedName())) continue; // don't return exact match to prefix
- if (!fullname.startsWith(type.getFullyQualifiedName())) continue; // only return those nested underneath prefix
- String[] parts = Util.getTypeNameParts(fullname);
-// Don't add if it's not the directly nested child (and is instead the grandchild)
- if (parts.length != Util.getTypeNameParts(type.getFullyQualifiedName()).length + 1) continue;
- // Add proposal
- CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.TYPE_REF, aType.getElementName());
- proposal.setType(aType.getFullyQualifiedName());
- proposal.setName(aType.getElementName());
- proposals.put(aType.getElementName(), proposal);
- }
- return proposals;
- }
-
- private List<CompletionProposal> suggestAllMethodsMatchingPrefix(IRubyScript script) {
- List< CompletionProposal> list = new ArrayList<CompletionProposal>();
- if (fContext.getPartialPrefix() == null || fContext.getPartialPrefix().trim().length() == 0) return list;
- IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {script.getRubyProject()});
- SearchParticipant participant = BasicSearchEngine.getDefaultSearchParticipant();
- CollectingSearchRequestor searchRequestor = new CollectingSearchRequestor();
- SearchPattern pattern = SearchPattern.createPattern(IRubyElement.METHOD, fContext.getPartialPrefix(), IRubySearchConstants.DECLARATIONS, SearchPattern.R_PREFIX_MATCH);
- try {
- new BasicSearchEngine().search(pattern, new SearchParticipant[] {participant}, scope, searchRequestor, null);
- } catch (CoreException e) {
- RubyCore.log(e);
- }
- List<SearchMatch> matches = searchRequestor.getResults();
- for (SearchMatch match : matches) {
- IMethod element = (IMethod) match.getElement();
- IType type = element.getDeclaringType();
- String typeName = "";
- if (type != null)
- typeName = type.getElementName();
- CompletionProposal proposal = suggestMethod(element, typeName, 100); // TODO Base confidence on accuracy in match?
- if (proposal != null) {
- list.add(proposal);
- }
- }
- return list;
- }
-
- private void suggestMethodsForEnclosingType(IRubyScript script) throws RubyModelException {
- IMember element = (IMember) script.getElementAt(fContext.getOffset());
- boolean includeInstance = !fContext.inTypeDefinition();
- IType[] types;
- if (element == null) {
- // We're in the top level, so we're in "Object"
- RubyElementRequestor requestor = new RubyElementRequestor(script);
- IType[] tmpTypes = requestor.findType(OBJECT);
- List<IType> filtered = new ArrayList<IType>();
- for (int i = 0; i < tmpTypes.length; i++) {
- // FIXME We shouldn't be getting these types with bad fully qualified names anyhow, should we?
- if (!tmpTypes[i].getFullyQualifiedName().equals(OBJECT)) continue;
- filtered.add(tmpTypes[i]);
- }
- types = filtered.toArray(new IType[filtered.size()]);
- includeInstance = false;
- } else if (element instanceof IType) {
- types = new IType[] {(IType) element};
- } else {
- types = new IType[] {element.getDeclaringType()};
- }
- if (types == null || types.length < 1) return;
- Map<String, CompletionProposal> map = new HashMap<String, CompletionProposal>();
- for (int i = 0; i < types.length; i++) {
- map.putAll(suggestMethods(100, types[i], includeInstance));
- }
- List<CompletionProposal> list = sort(map);
- for (CompletionProposal proposal : list) {
- fRequestor.accept(proposal);
- }
- }
-
- /**
- * Wrap beginning of recursion to suggest methods for a type. We keep track of types visited so that we can avoid inifnite loops.
- *
- * @param confidence
- * @param type
- * @param includeInstanceMethods
- * @return
- * @throws RubyModelException
- */
- private Map<String, CompletionProposal> suggestMethods(int confidence, IType type, boolean includeInstanceMethods) throws RubyModelException {
- if (fVisitedTypes == null) fVisitedTypes = new HashSet<IType>();
- fOriginalType = type;
- Map<String, CompletionProposal> list = doSuggestMethods(100, type, includeInstanceMethods);
- fVisitedTypes.clear();
- fOriginalType = null;
- return list;
- }
-
- private List<CompletionProposal> sort(Map<String, CompletionProposal> proposals) {
- List<CompletionProposal> list = new ArrayList<CompletionProposal>(proposals.values());
- Collections.sort(list, new CompletionProposalComparator());
- return list;
- }
-
- private void suggestGlobals() {
- SearchPattern pattern = SearchPattern.createPattern(IRubyElement.GLOBAL, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
- IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript().getRubyProject()});
- List<SearchMatch> results = search(pattern, scope);
- for (SearchMatch match: results) {
- IRubyElement element = (IRubyElement) match.getElement();
- String name = element.getElementName();
- if (!fContext.prefixStartsWith(name))
- continue;
- CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, name);
- proposal.setType(name);
- fRequestor.accept(proposal);
- }
- }
-
- private void suggestTypeNames() {
- SearchPattern pattern = SearchPattern.createPattern(IRubyElement.TYPE, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
- IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript().getRubyProject()});
- List<SearchMatch> results = search(pattern, scope);
- for (SearchMatch match: results) {
- IRubyElement element = (IRubyElement) match.getElement();
- String name = element.getElementName();
- if (!fContext.prefixStartsWith(name))
- continue;
- CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.TYPE_REF, name);
- proposal.setType(name);
- fRequestor.accept(proposal);
- }
- }
-
- private List<SearchMatch> search(SearchPattern pattern, IRubySearchScope scope) {
- BasicSearchEngine engine = new BasicSearchEngine();
- SearchParticipant[] participants = new SearchParticipant[] { BasicSearchEngine.getDefaultSearchParticipant() };
- CollectingSearchRequestor requestor = new CollectingSearchRequestor();
- try {
- engine.search(pattern, participants, scope, requestor, null);
- } catch (CoreException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return requestor.getResults();
- }
-
- private CompletionProposal createProposal(int replaceStart, int type, String name) {
- CompletionProposal proposal = new CompletionProposal(type, name, 100);
- proposal.setReplaceRange(replaceStart, replaceStart + name.length());
- return proposal;
- }
-
- private void suggestConstantNames() {
- SearchPattern pattern = SearchPattern.createPattern(IRubyElement.CONSTANT, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
- IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript()});
- List<SearchMatch> results = search(pattern, scope);
- for (SearchMatch match: results) {
- IRubyElement element = (IRubyElement) match.getElement();
- String name = element.getElementName();
- if (!fContext.prefixStartsWith(name))
- continue;
- CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, name);
- proposal.setType(name);
- fRequestor.accept(proposal);
- }
- }
-
- private Map<String, CompletionProposal> doSuggestMethods(int confidence, IType type, boolean includeInstanceMethods) throws RubyModelException {
- Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
- if (type == null)
- return proposals;
- if (fVisitedTypes.contains(type)) return proposals;
- fVisitedTypes.add(type);
- IMethod[] methods = type.getMethods();
- if (methods != null) {
- for (int k = 0; k < methods.length; k++) {
- if (methods[k] == null) continue;
- if (!includeInstanceMethods && !methods[k].isSingleton()) {
- continue;
- }
- CompletionProposal proposal = suggestMethod(methods[k], type.getElementName(), confidence);
- if (proposal != null && !proposals.containsKey(proposal.getName())) {
- proposals.put(proposal.getName(), proposal); // If a method name matches an existing suggestion (i.e. its overriden in the subclass), don't suggest it again!
- }
- }
- }
- proposals.putAll(addModuleMethods(confidence - 1, type)); // Decrement confidence by one as a hack to make sure as we move up the inheritance chain we suggest "closer" parents methods first
- if (!type.isModule()) proposals.putAll(addSuperClassMethods(confidence - 1, type, includeInstanceMethods));
- return proposals;
- }
-
- private Map<String, CompletionProposal> addModuleMethods(int confidence, IType type) {
- Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
- String[] modules = null;
- try {
- modules = type.getIncludedModuleNames();
- } catch (RubyModelException e) {
- // ignore
- }
- if (modules == null || modules.length == 0) return proposals;
- RubyElementRequestor requestor = new RubyElementRequestor(type.getRubyScript());
- for (int i = 0; i < modules.length; i++) {
- IType[] moduleTypes = requestor.findType(modules[i]);
- for (int j = 0; j < moduleTypes.length; j++) {
- try {
- IType moduleType = moduleTypes[j];
- proposals.putAll(doSuggestMethods(confidence, moduleType, true));
- } catch (RubyModelException e) {
- // ignore
- }
- }
- }
- return proposals;
- }
-
- private Map<String, CompletionProposal> addSuperClassMethods(int confidence, IType type, boolean includeInstanceMethods) throws RubyModelException {
- Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
- String superClass = type.getSuperclassName();
- if (superClass == null) return proposals;
- RubyElementRequestor requestor = new RubyElementRequestor(type.getRubyScript());
- IType[] supers = requestor.findType(superClass);
- for (int i = 0; i < supers.length; i++) {
- IType superType = supers[i];
- proposals.putAll(doSuggestMethods(confidence, superType, includeInstanceMethods));
- }
- return proposals;
- }
-
- private CompletionProposal suggestMethod(IMethod method, String typeName, int confidence) {
- int start = fContext.getReplaceStart();
- String name = method.getElementName();
- int flags = Flags.AccDefault;
- if (method.isSingleton()) {
- flags |= Flags.AccStatic;
- if (method.isConstructor())
- name = CONSTRUCTOR_INVOKE_NAME;
- else {
- if (name.startsWith(typeName)) {
- name = name.substring(typeName.length() + 1);
- }
- }
- } else {
- // Don't show instance methods if the thing we're working on is a class' name!
- // FIXME We do want to show if it is a constant, but not a class name
- if (fContext.fullPrefixIsConstant()) return null;
- }
- if (!fContext.prefixStartsWith(name))
- return null;
-
- try {
- switch (method.getVisibility()) {
- case IMethod.PRIVATE:
- flags |= Flags.AccPrivate;
- if (!fOriginalType.getElementName().equals(typeName)) return null; // FIXME We should do a comparison of types, not names
- if (fContext.hasReceiver()) return null; // can't invoke a private method on a receiver
- break;
- case IMethod.PUBLIC:
- flags |= Flags.AccPublic; // FIXME Check if receiver is of same class as method's declaring type, if not, skip this method. (so we can invoke with no receiver inside same class, with explicit self as receiver, or with receiver who has same class).
- break;
- case IMethod.PROTECTED:
- flags |= Flags.AccProtected;
- break;
- default:
- break;
- }
- } catch (RubyModelException e) {
- RubyCore.log(e);
- flags |= Flags.AccPublic;
- }
- CompletionProposal proposal = new CompletionProposal(CompletionProposal.METHOD_REF, name, confidence);
- proposal.setReplaceRange(start, start + name.length());
- proposal.setFlags(flags);
- proposal.setName(name);
- IType declaringType = method.getDeclaringType();
- String declaringName = typeName;
- if (declaringType != null)
- declaringName = declaringType.getFullyQualifiedName();
- proposal.setDeclaringType(declaringName);
- return proposal;
- }
-
- /**
- * Gets all the distinct elements in the current RubyScript
- *
- * @param offset
- * @param replaceStart
- *
- * @return a List of the names of all the elements in the current RubyScript
- */
- private void getDocumentsRubyElementsInScope() {
- try {
- // FIXME Try to stop all the multiple re-parsing of the source! Can
- // we parse once and pass the root node around?
- // Parse
- Node rootNode = fContext.getRootNode();
- if (rootNode == null) {
- return;
- }
-
- // Grab enclosing scope
- Node enclosingNode = findNearestScope(rootNode, fContext.getOffset());
- if (enclosingNode == null) enclosingNode = rootNode;
- // Add variables in this scope
- Collection<String> variables = addVariablesinScope(getScope(enclosingNode));
- for (String variable : variables) {
- int type = CompletionProposal.LOCAL_VARIABLE_REF;
- if (variable.startsWith("$")) {
- type = CompletionProposal.GLOBAL_REF;
- }
- CompletionProposal proposal = new CompletionProposal(type, variable, 100);
- proposal.setReplaceRange(fContext.getReplaceStart(), fContext.getReplaceStart() + variable.length());
- fRequestor.accept(proposal);
- }
-
- // Add methods in this scope
- Node enclosingTypeNode = ClosestSpanningNodeLocator.Instance().findClosestSpanner(rootNode, fContext.getOffset(), new INodeAcceptor() {
- public boolean doesAccept(Node node) {
- return (node instanceof ClassNode || node instanceof ModuleNode || node instanceof RootNode);
- }
- });
- if (enclosingTypeNode == null) enclosingTypeNode = rootNode;
- Collection<CompletionProposal> methodProposals = addASTMethodsInScope(enclosingTypeNode, "");
- for (CompletionProposal proposal : methodProposals) {
- if (proposal == null) continue;
- fRequestor.accept(proposal);
- }
-
- // Find the enclosing type (class or module) to get instance and
- // classvars from
- enclosingTypeNode = ClosestSpanningNodeLocator.Instance().findClosestSpanner(rootNode, fContext.getOffset(), new INodeAcceptor() {
- public boolean doesAccept(Node node) {
- return (node instanceof ClassNode || node instanceof ModuleNode);
- }
- });
-
- // Add members from enclosing type
- if (enclosingTypeNode != null) {
- getMembersAvailableInsideType(enclosingTypeNode);
- }
- } catch (RubyModelException rme) {
- RubyCore.log(rme);
- RubyCore.log("RubyModelException in CompletionEngine::getElementsInScope()");
- } catch (SyntaxException se) {
- RubyCore.log(se);
- RubyCore.log("SyntaxError in CompletionEngine::getElementsInScope()");
- }
- }
-
- private Node findNearestScope(Node scopeNode, int offset) {
- return ClosestSpanningNodeLocator.Instance().findClosestSpanner(scopeNode, offset, new INodeAcceptor() {
- public boolean doesAccept(Node node) {
- return (node instanceof DefnNode || node instanceof DefsNode || node instanceof ClassNode || node instanceof ModuleNode || node instanceof RootNode);
- }
- });
- }
-
- private Set<String> addVariablesinScope(StaticScope scope) {
- Set<String> matches = new HashSet<String>();
- if (scope == null) return matches;
- String[] variables = scope.getVariables();
- for(int i = 0; i < variables.length; i++) {
- String local = variables[i];
- if (!fContext.prefixStartsWith(local))
- continue;
- matches.add(local);
- }
- matches.addAll(addVariablesinScope(scope.getEnclosingScope()));
- return matches;
- }
-
- private StaticScope getScope(Node enclosingNode) {
- if (enclosingNode == null) return ((RootNode)fContext.getRootNode()).getStaticScope();
- if (enclosingNode instanceof RootNode) {
- RootNode root = (RootNode) enclosingNode;
- return root.getStaticScope();
- }
- try {
- Method getScopeMethod = enclosingNode.getClass().getMethod("getScope", new Class[] {});
- Object scope = getScopeMethod.invoke(enclosingNode, new Object[0]);
- return (StaticScope) scope;
- } catch (Exception e) {
- return null;
- }
- }
-
- /**
- * Gets the members available inside a type node (ModuleNode, ClassNode): -
- * Instance variables - Class variables - Methods
- *
- * @param typeNode
- * @return
- */
- private void getMembersAvailableInsideType(Node typeNode) throws RubyModelException {
- if (typeNode == null) {
- return;
- }
-
- String typeName = getTypeName(typeNode);
- if (typeName == null) {
- return;
- }
-
- // Get superclass and add its public members
- List<Node> superclassNodes = getSuperclassNodes(typeNode);
- for (Node superclassNode : superclassNodes) {
- getMembersAvailableInsideType(superclassNode);
- }
-
- // Get public members of mixins
- List<String> mixinNames = getIncludedMixinNames(typeName);
- for (String mixinName : mixinNames) {
- List<Node> mixinDeclarations = getTypeDeclarationNodes(mixinName);
- for (Node mixinDeclaration : mixinDeclarations) {
- getMembersAvailableInsideType(mixinDeclaration);
- }
- }
-
- // Get method names defined by DefnNodes and DefsNodes
- List<Node> methodDefinitions = ScopedNodeLocator.Instance().findNodesInScope(typeNode, new INodeAcceptor() {
- public boolean doesAccept(Node node) {
- return (node instanceof DefnNode) || (node instanceof DefsNode);
- }
- });
- for (Node methodDefinition : methodDefinitions) {
- String name = null;
- if (methodDefinition instanceof DefnNode) {
- name = ((DefnNode) methodDefinition).getName();
- }
- if (methodDefinition instanceof DefsNode) {
- name = ((DefsNode) methodDefinition).getName();
- }
- if (!fContext.prefixStartsWith(name))
- continue;
- NodeMethod method = new NodeMethod((MethodDefNode)methodDefinition);
- suggestMethod(method, typeName, 100);
- }
- addTypesVariables(typeNode);
- }
-
- private String getTypeName(Node typeNode) {
- // Get type name
- String typeName = null;
- if (typeNode instanceof ClassNode) {
- typeName = ((Colon2Node) ((ClassNode) typeNode).getCPath()).getName();
- }
- if (typeNode instanceof ModuleNode) {
- typeName = ((Colon2Node) ((ModuleNode) typeNode).getCPath()).getName();
- }
- return typeName;
- }
-
- private void addTypesVariables(Node typeNode) {
- // Get instance and class variables available in the enclosing type
- List<Node> instanceAndClassVars = ScopedNodeLocator.Instance().findNodesInScope(typeNode, new INodeAcceptor() {
- public boolean doesAccept(Node node) {
- return (node instanceof ConstDeclNode || node instanceof InstVarNode || node instanceof InstAsgnNode || node instanceof ClassVarNode || node instanceof ClassVarDeclNode || node instanceof ClassVarAsgnNode);
- }
- });
- Set<String> fields = new HashSet<String>();
- if (instanceAndClassVars != null) {
- // Get the unique names of instance and class variables
- for (Node varNode : instanceAndClassVars) {
- String name = ASTUtil.getNameReflectively(varNode);
- if (!fContext.prefixStartsWith(name))
- continue;
- fields.add(name);
- }
- }
- // Get instance and class vars defined by [c]attr_* calls
- List<String> attrs = AttributeLocator.Instance().findInstanceAttributesInScope(typeNode);
- for (Iterator iter = attrs.iterator(); iter.hasNext();) {
- String attr = (String) iter.next();
- if (!fContext.prefixStartsWith(attr))
- continue;
- fields.add(attr);
- }
- for (String field : fields) {
- CompletionProposal proposal = new CompletionProposal(CompletionProposal.CONSTANT_REF, field, 100);
- proposal.setReplaceRange(fContext.getReplaceStart(), fContext.getReplaceStart() + field.length());
- fRequestor.accept(proposal);
- }
- }
-
- /**
- * Finds all nodes that declare a type that is a superclass of the specified
- * node. Example:
- *
- * """ class Klass;def meth_1;1;end;end class Klass;def meth_2;2;end;end
- *
- * class SubKlass < Klass;end """
- *
- * Issuing getSuperClassNodes() on the ClassNode declaring SubKlass would
- * return two ClassNodes; one for each definition of Klass.
- *
- * @param typeNode
- * Node to find superclass nodes of
- * @return List of ClassNode or ModuleNode
- */
- private List<Node> getSuperclassNodes(Node typeNode) {
- if (typeNode instanceof ClassNode) {
- Node superNode = ((ClassNode) typeNode).getSuperNode();
- if (superNode instanceof ConstNode) {
- String superclassName = ((ConstNode) superNode).getName();
- return getTypeDeclarationNodes(superclassName);
- }
- }
- return new ArrayList<Node>();
- }
-
- /** Lookup type declaration nodes */
- private List<Node> getTypeDeclarationNodes(String typeName) {
- // Find the named type
- RubyElementRequestor requestor = new RubyElementRequestor(fContext.getScript());
- IType[] types = requestor.findType(typeName);
- if (types == null || types.length == 0) return new ArrayList<Node>(0);
- IType type = types[0];
-
- try {
- if (type instanceof RubyType) {
-
- // FIXME This feels a little hacky and backwards -
- // RubyType.getSource() and then parse... consider reworking the
- // clients to this method to accept RubyTypes or something
- // similar?
- // Find source and parse
- RubyType rubyType = (RubyType) type;
- String source = rubyType.getSource();
- if (source == null) return new ArrayList<Node>(0);
-
- // FIXME Why does the parser balk on \r chars?
- source = source.replace('\r', ' ');
- Node rootNode = (new RubyParser()).parse(source);
-
- // Bail if the parse fails
- if (rootNode == null) {
- return new ArrayList<Node>();
- }
-
- // Return any type declaration nodes in included source
- return ScopedNodeLocator.Instance().findNodesInScope(rootNode, new INodeAcceptor() {
- public boolean doesAccept(Node node) {
- return (node instanceof ClassNode) || (node instanceof ModuleNode);
- }
- });
- }
-
- } catch (RubyModelException rme) {
- rme.printStackTrace();
- }
-
- return new ArrayList<Node>(0);
- }
-
- private List<String> getIncludedMixinNames(String typeName) {
- IType rubyType = new RubyType((RubyElement)fContext.getScript(), typeName);
-
- try {
- String[] includedModuleNames = rubyType.getIncludedModuleNames();
- if (includedModuleNames != null) {
- return Arrays.asList(rubyType.getIncludedModuleNames());
- }
- return new ArrayList<String>(0);
- } catch (RubyModelException e) {
- return new ArrayList<String>(0);
- }
- }
-
- private class NodeMethod implements IMethod {
- private MethodDefNode node;
-
- public NodeMethod(MethodDefNode methodDefinition) {
- this.node = methodDefinition;
- }
-
- public String[] getParameterNames() throws RubyModelException {
- return ASTUtil.getArgs(node.getArgsNode(), node.getScope());
- }
-
- public int getNumberOfParameters() throws RubyModelException {
- return getParameterNames().length;
- }
-
- public int getVisibility() throws RubyModelException {
- return IMethod.PUBLIC;
- }
-
- public boolean isConstructor() {
- return node.getName().equals(CONSTRUCTOR_DEFINITION_NAME);
- }
-
- public boolean isSingleton() {
- return isConstructor() || node instanceof DefsNode;
- }
-
- public boolean exists() {
- return false;
- }
-
- public IRubyElement getAncestor(int ancestorType) {
- return null;
- }
-
- public IResource getCorrespondingResource() throws RubyModelException {
- return null;
- }
-
- public String getElementName() {
- return node.getName();
- }
-
- public int getElementType() {
- return IRubyElement.METHOD;
- }
-
- public IOpenable getOpenable() {
- return null;
- }
-
- public IRubyElement getParent() {
- return null;
- }
-
- public IPath getPath() {
- return null;
- }
-
- public IRubyElement getPrimaryElement() {
- return null;
- }
-
- public IResource getResource() {
- return null;
- }
-
- public IRubyModel getRubyModel() {
- return null;
- }
-
- public IRubyProject getRubyProject() {
- return null;
- }
-
- public IResource getUnderlyingResource() throws RubyModelException {
- return null;
- }
-
- public boolean isReadOnly() {
- return false;
- }
-
- public boolean isStructureKnown() throws RubyModelException {
- return false;
- }
-
- public boolean isType(int type) {
- return type == IRubyElement.METHOD;
- }
-
- public Object getAdapter(Class adapter) {
- return null;
- }
-
- public IType getDeclaringType() {
- return null;
- }
-
- public ISourceRange getNameRange() throws RubyModelException {
- return null;
- }
-
- public IRubyScript getRubyScript() {
- return null;
- }
-
- public IType getType(String name, int occurrenceCount) {
- return null;
- }
-
- public String getSource() throws RubyModelException {
- return null;
- }
-
- public ISourceRange getSourceRange() throws RubyModelException {
- return null;
- }
-
- public IRubyElement[] getChildren() throws RubyModelException {
- return null;
- }
-
- public boolean hasChildren() throws RubyModelException {
- return false;
- }
-
- public String getHandleIdentifier() {
- // TODO Auto-generated method stub
- return null;
- }
-
- }
-}
+package org.rubypeople.rdt.internal.codeassist;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.jruby.ast.ClassNode;
+import org.jruby.ast.ClassVarAsgnNode;
+import org.jruby.ast.ClassVarDeclNode;
+import org.jruby.ast.ClassVarNode;
+import org.jruby.ast.Colon2Node;
+import org.jruby.ast.ConstDeclNode;
+import org.jruby.ast.ConstNode;
+import org.jruby.ast.DefnNode;
+import org.jruby.ast.DefsNode;
+import org.jruby.ast.InstAsgnNode;
+import org.jruby.ast.InstVarNode;
+import org.jruby.ast.MethodDefNode;
+import org.jruby.ast.ModuleNode;
+import org.jruby.ast.Node;
+import org.jruby.ast.RootNode;
+import org.jruby.lexer.yacc.SyntaxException;
+import org.jruby.parser.StaticScope;
+import org.rubypeople.rdt.core.CompletionProposal;
+import org.rubypeople.rdt.core.CompletionRequestor;
+import org.rubypeople.rdt.core.Flags;
+import org.rubypeople.rdt.core.IMember;
+import org.rubypeople.rdt.core.IMethod;
+import org.rubypeople.rdt.core.IOpenable;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.IRubyModel;
+import org.rubypeople.rdt.core.IRubyProject;
+import org.rubypeople.rdt.core.IRubyScript;
+import org.rubypeople.rdt.core.ISourceRange;
+import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.RubyCore;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.core.search.IRubySearchConstants;
+import org.rubypeople.rdt.core.search.IRubySearchScope;
+import org.rubypeople.rdt.core.search.SearchMatch;
+import org.rubypeople.rdt.core.search.SearchParticipant;
+import org.rubypeople.rdt.core.search.SearchPattern;
+import org.rubypeople.rdt.internal.core.RubyElement;
+import org.rubypeople.rdt.internal.core.RubyScript;
+import org.rubypeople.rdt.internal.core.RubyType;
+import org.rubypeople.rdt.internal.core.parser.RubyParser;
+import org.rubypeople.rdt.internal.core.search.BasicSearchEngine;
+import org.rubypeople.rdt.internal.core.search.CollectingSearchRequestor;
+import org.rubypeople.rdt.internal.core.util.ASTUtil;
+import org.rubypeople.rdt.internal.core.util.Util;
+import org.rubypeople.rdt.internal.ti.BasicTypeGuess;
+import org.rubypeople.rdt.internal.ti.DefaultTypeInferrer;
+import org.rubypeople.rdt.internal.ti.ITypeGuess;
+import org.rubypeople.rdt.internal.ti.ITypeInferrer;
+import org.rubypeople.rdt.internal.ti.util.AttributeLocator;
+import org.rubypeople.rdt.internal.ti.util.ClosestSpanningNodeLocator;
+import org.rubypeople.rdt.internal.ti.util.INodeAcceptor;
+import org.rubypeople.rdt.internal.ti.util.ScopedNodeLocator;
+
+public class CompletionEngine {
+ private static final String OBJECT = "Object";
+ private static final String CONSTRUCTOR_INVOKE_NAME = "new";
+ private static final String CONSTRUCTOR_DEFINITION_NAME = "initialize";
+
+ private CompletionRequestor fRequestor;
+ private CompletionContext fContext;
+ private Set<IType> fVisitedTypes;
+ /**
+ * temporary place to hold the original type we're completing for. Used to determine if we should be showing private methods.
+ */
+ private IType fOriginalType;
+
+ public CompletionEngine(CompletionRequestor requestor) {
+ this.fRequestor = requestor;
+ }
+
+ public void complete(IRubyScript script, int offset) throws RubyModelException {
+ this.fRequestor.beginReporting();
+ fContext = new CompletionContext(script, offset);
+ if (fContext.emptyPrefix()) { // no prefix, so we could suggest anything
+ suggestMethodsForEnclosingType(script);
+ getDocumentsRubyElementsInScope();
+ } else {
+ if (fContext.isDoubleSemiColon()) {
+ String prefix = fContext.getFullPrefix();
+ String typeName = prefix.substring(0, prefix.lastIndexOf("::"));
+ RubyElementRequestor requestor = new RubyElementRequestor(script);
+ IType[] types = requestor.findType(typeName);
+ Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
+ for (int i = 0; i < types.length; i++) {
+ IType type = types[i];
+ proposals.putAll(suggestTypesConstants(type));
+ // Suggest nested types
+ proposals.putAll(suggestNestedTypes(type));
+ // Suggest class level methods
+ proposals.putAll(suggestMethods(100, type, false));
+ }
+ List<CompletionProposal> list = new ArrayList<CompletionProposal>(proposals.values());
+ Collections.sort(list, new CompletionProposalComparator());
+ for (CompletionProposal proposal : list) {
+ if (proposal.getCompletion().startsWith(fContext.getPartialPrefix()))
+ fRequestor.accept(proposal);
+ }
+ }
+ if (fContext.isConstant()) { // type or constant
+ suggestTypeNames();
+ suggestConstantNames();
+ return;
+ }
+ if (fContext.isExplicitMethodInvokation()) {
+ ITypeInferrer inferrer = new DefaultTypeInferrer();
+ List<ITypeGuess> guesses = inferrer.infer(fContext.getCorrectedSource(), fContext.getOffset());
+ if (guesses.isEmpty()) {
+ guesses.add(new BasicTypeGuess(OBJECT, 100));
+ }
+ List<CompletionProposal> list = new ArrayList<CompletionProposal>();
+ RubyElementRequestor requestor = new RubyElementRequestor(script);
+ for (ITypeGuess guess : guesses) {
+ final String name = guess.getType();
+ if (fContext.isBroken()) {
+ Node rootNode = fContext.getRootNode();
+ List<Node> typeNodes = ScopedNodeLocator.Instance().findNodesInScope(rootNode, new INodeAcceptor() {
+
+ public boolean doesAccept(Node node) {
+ if ((node instanceof ClassNode) || (node instanceof ModuleNode)) {
+ return ASTUtil.getNameReflectively(node).equals(name);
+ }
+ return false;
+ }
+
+ });
+ for (Node typeNode : typeNodes) {
+ list.addAll(addASTMethodsInScope(typeNode, name));
+ }
+ }
+ IType[] types = requestor.findType(name);
+ for (int i = 0; i < types.length; i++) {
+ Map<String, CompletionProposal> map = suggestMethods(guess.getConfidence(), types[i], true);
+ list.addAll(map.values());
+ }
+ }
+ list.addAll(suggestAllMethodsMatchingPrefix(script));
+ Collections.sort(list, new CompletionProposalComparator());
+ for (CompletionProposal proposal : list) {
+ fRequestor.accept(proposal);
+ }
+ } else {
+ // FIXME If we're invoked on the class declaration (it's super class) don't do this!
+ // FIXME Traverse the IRubyElement model, not nodes (and don't reparse)?
+ if (fContext.isMethodInvokationOrLocal()) {
+ suggestMethodsForEnclosingType(script);
+ }
+ getDocumentsRubyElementsInScope();
+ }
+ if (fContext.isGlobal()) { // looks like a global
+ suggestGlobals();
+ }
+ }
+ this.fRequestor.endReporting();
+ fContext = null;
+ }
+
+ private Collection<CompletionProposal> addASTMethodsInScope(Node typeNode, String name) {
+ List<CompletionProposal> list = new ArrayList<CompletionProposal>();
+ if (typeNode == null) return list;
+ List<Node> methods = ScopedNodeLocator.Instance().findNodesInScope(typeNode, new INodeAcceptor() {
+
+ public boolean doesAccept(Node node) {
+ return (node instanceof DefnNode) || (node instanceof DefsNode);
+ }
+
+ });
+ for (Node methodNode : methods) {
+ Node scoping = findNearestScope(typeNode, methodNode.getPosition().getStartOffset() - 1);
+ if (!scoping.equals(typeNode)) continue;
+ MethodDefNode methodDef = (MethodDefNode) methodNode;
+ NodeMethod method = new NodeMethod(methodDef);
+ CompletionProposal proposal = suggestMethod(method, name, 100);
+ if (proposal == null) continue;
+ list.add(proposal);
+ }
+ return list;
+ }
+
+ private Map<String, CompletionProposal> suggestTypesConstants(IType type) throws RubyModelException {
+ Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.CONSTANT, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
+ IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {type});
+ List<SearchMatch> results = search(pattern, scope);
+ for (SearchMatch match: results) {
+ IRubyElement element = (IRubyElement) match.getElement();
+ if (element.getElementType() != IRubyElement.CONSTANT) continue; // XXX we shouldn't have to do this
+ // Add proposal
+ CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, element.getElementName(), element);
+ proposal.setType(type.getFullyQualifiedName());
+ proposal.setName(element.getElementName());
+ proposals.put(element.getElementName(), proposal);
+ }
+ return proposals;
+ }
+
+ private Map<String, CompletionProposal> suggestNestedTypes(IType type) throws RubyModelException {
+ Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.TYPE, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
+ IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {type});
+ List<SearchMatch> results = search(pattern, scope);
+ for (SearchMatch match: results) {
+ IType aType = (IType) match.getElement();
+ String fullname = aType.getFullyQualifiedName();
+ if (fullname.equals(type.getFullyQualifiedName())) continue; // don't return exact match to prefix
+ if (!fullname.startsWith(type.getFullyQualifiedName())) continue; // only return those nested underneath prefix
+ String[] parts = Util.getTypeNameParts(fullname);
+// Don't add if it's not the directly nested child (and is instead the grandchild)
+ if (parts.length != Util.getTypeNameParts(type.getFullyQualifiedName()).length + 1) continue;
+ // Add proposal
+ CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.TYPE_REF, aType.getElementName());
+ proposal.setType(aType.getFullyQualifiedName());
+ proposal.setName(aType.getElementName());
+ proposals.put(aType.getElementName(), proposal);
+ }
+ return proposals;
+ }
+
+ private List<CompletionProposal> suggestAllMethodsMatchingPrefix(IRubyScript script) {
+ List< CompletionProposal> list = new ArrayList<CompletionProposal>();
+ if (fContext.getPartialPrefix() == null || fContext.getPartialPrefix().trim().length() == 0) return list;
+ IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {script.getRubyProject()});
+ SearchParticipant participant = BasicSearchEngine.getDefaultSearchParticipant();
+ CollectingSearchRequestor searchRequestor = new CollectingSearchRequestor();
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.METHOD, fContext.getPartialPrefix(), IRubySearchConstants.DECLARATIONS, SearchPattern.R_PREFIX_MATCH);
+ try {
+ new BasicSearchEngine().search(pattern, new SearchParticipant[] {participant}, scope, searchRequestor, null);
+ } catch (CoreException e) {
+ RubyCore.log(e);
+ }
+ List<SearchMatch> matches = searchRequestor.getResults();
+ for (SearchMatch match : matches) {
+ IMethod element = (IMethod) match.getElement();
+ IType type = element.getDeclaringType();
+ String typeName = "";
+ if (type != null)
+ typeName = type.getElementName();
+ CompletionProposal proposal = suggestMethod(element, typeName, 100); // TODO Base confidence on accuracy in match?
+ if (proposal != null) {
+ list.add(proposal);
+ }
+ }
+ return list;
+ }
+
+ private void suggestMethodsForEnclosingType(IRubyScript script) throws RubyModelException {
+ IMember element = (IMember) script.getElementAt(fContext.getOffset());
+ boolean includeInstance = !fContext.inTypeDefinition();
+ IType[] types;
+ if (element == null) {
+ // We're in the top level, so we're in "Object"
+ RubyElementRequestor requestor = new RubyElementRequestor(script);
+ IType[] tmpTypes = requestor.findType(OBJECT);
+ List<IType> filtered = new ArrayList<IType>();
+ for (int i = 0; i < tmpTypes.length; i++) {
+ // FIXME We shouldn't be getting these types with bad fully qualified names anyhow, should we?
+ if (!tmpTypes[i].getFullyQualifiedName().equals(OBJECT)) continue;
+ filtered.add(tmpTypes[i]);
+ }
+ types = filtered.toArray(new IType[filtered.size()]);
+ includeInstance = false;
+ } else if (element instanceof IType) {
+ types = new IType[] {(IType) element};
+ } else {
+ types = new IType[] {element.getDeclaringType()};
+ }
+ if (types == null || types.length < 1) return;
+ Map<String, CompletionProposal> map = new HashMap<String, CompletionProposal>();
+ for (int i = 0; i < types.length; i++) {
+ map.putAll(suggestMethods(100, types[i], includeInstance));
+ }
+ List<CompletionProposal> list = sort(map);
+ for (CompletionProposal proposal : list) {
+ fRequestor.accept(proposal);
+ }
+ }
+
+ /**
+ * Wrap beginning of recursion to suggest methods for a type. We keep track of types visited so that we can avoid inifnite loops.
+ *
+ * @param confidence
+ * @param type
+ * @param includeInstanceMethods
+ * @return
+ * @throws RubyModelException
+ */
+ private Map<String, CompletionProposal> suggestMethods(int confidence, IType type, boolean includeInstanceMethods) throws RubyModelException {
+ if (fVisitedTypes == null) fVisitedTypes = new HashSet<IType>();
+ fOriginalType = type;
+ Map<String, CompletionProposal> list = doSuggestMethods(100, type, includeInstanceMethods);
+ fVisitedTypes.clear();
+ fOriginalType = null;
+ return list;
+ }
+
+ private List<CompletionProposal> sort(Map<String, CompletionProposal> proposals) {
+ List<CompletionProposal> list = new ArrayList<CompletionProposal>(proposals.values());
+ Collections.sort(list, new CompletionProposalComparator());
+ return list;
+ }
+
+ private void suggestGlobals() {
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.GLOBAL, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
+ IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript().getRubyProject()});
+ List<SearchMatch> results = search(pattern, scope);
+ for (SearchMatch match: results) {
+ IRubyElement element = (IRubyElement) match.getElement();
+ String name = element.getElementName();
+ if (!fContext.prefixStartsWith(name))
+ continue;
+ CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, name, element);
+ proposal.setType(name);
+ fRequestor.accept(proposal);
+ }
+ }
+
+ private void suggestTypeNames() {
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.TYPE, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
+ IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript().getRubyProject()});
+ List<SearchMatch> results = search(pattern, scope);
+ for (SearchMatch match: results) {
+ IRubyElement element = (IRubyElement) match.getElement();
+ String name = element.getElementName();
+ if (!fContext.prefixStartsWith(name))
+ continue;
+ CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.TYPE_REF, name, element);
+ proposal.setType(name);
+ fRequestor.accept(proposal);
+ }
+ }
+
+ private List<SearchMatch> search(SearchPattern pattern, IRubySearchScope scope) {
+ BasicSearchEngine engine = new BasicSearchEngine();
+ SearchParticipant[] participants = new SearchParticipant[] { BasicSearchEngine.getDefaultSearchParticipant() };
+ CollectingSearchRequestor requestor = new CollectingSearchRequestor();
+ try {
+ engine.search(pattern, participants, scope, requestor, null);
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return requestor.getResults();
+ }
+
+ private CompletionProposal createProposal(int replaceStart, int type, String name) {
+ return createProposal(replaceStart, type, name, 100, null);
+ }
+ private CompletionProposal createProposal(int replaceStart, int type, String name, IRubyElement element) {
+ return createProposal(replaceStart, type, name, 100, element);
+ }
+ private CompletionProposal createProposal(int replaceStart, int type, String name, int confidence, IRubyElement element) {
+ CompletionProposal proposal = new CompletionProposal(type, name, 100);
+ proposal.setReplaceRange(replaceStart, replaceStart + name.length());
+ proposal.setElement(element);
+ return proposal;
+ }
+
+ private void suggestConstantNames() {
+ SearchPattern pattern = SearchPattern.createPattern(IRubyElement.CONSTANT, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
+ IRubySearchScope scope = BasicSearchEngine.createRubySearchScope(new IRubyElement[] {fContext.getScript()});
+ List<SearchMatch> results = search(pattern, scope);
+ for (SearchMatch match: results) {
+ IRubyElement element = (IRubyElement) match.getElement();
+ String name = element.getElementName();
+ if (!fContext.prefixStartsWith(name))
+ continue;
+ CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, name, element);
+ proposal.setType(name);
+ fRequestor.accept(proposal);
+ }
+ }
+
+ private Map<String, CompletionProposal> doSuggestMethods(int confidence, IType type, boolean includeInstanceMethods) throws RubyModelException {
+ Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
+ if (type == null)
+ return proposals;
+ if (fVisitedTypes.contains(type)) return proposals;
+ fVisitedTypes.add(type);
+ IMethod[] methods = type.getMethods();
+ if (methods != null) {
+ for (int k = 0; k < methods.length; k++) {
+ if (methods[k] == null) continue;
+ if (!includeInstanceMethods && !methods[k].isSingleton()) {
+ continue;
+ }
+ CompletionProposal proposal = suggestMethod(methods[k], type.getElementName(), confidence);
+ if (proposal != null && !proposals.containsKey(proposal.getName())) {
+ proposals.put(proposal.getName(), proposal); // If a method name matches an existing suggestion (i.e. its overriden in the subclass), don't suggest it again!
+ }
+ }
+ }
+ proposals.putAll(addModuleMethods(confidence - 1, type)); // Decrement confidence by one as a hack to make sure as we move up the inheritance chain we suggest "closer" parents methods first
+ if (!type.isModule()) proposals.putAll(addSuperClassMethods(confidence - 1, type, includeInstanceMethods));
+ return proposals;
+ }
+
+ private Map<String, CompletionProposal> addModuleMethods(int confidence, IType type) {
+ Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
+ String[] modules = null;
+ try {
+ modules = type.getIncludedModuleNames();
+ } catch (RubyModelException e) {
+ // ignore
+ }
+ if (modules == null || modules.length == 0) return proposals;
+ RubyElementRequestor requestor = new RubyElementRequestor(type.getRubyScript());
+ for (int i = 0; i < modules.length; i++) {
+ IType[] moduleTypes = requestor.findType(modules[i]);
+ for (int j = 0; j < moduleTypes.length; j++) {
+ try {
+ IType moduleType = moduleTypes[j];
+ proposals.putAll(doSuggestMethods(confidence, moduleType, true));
+ } catch (RubyModelException e) {
+ // ignore
+ }
+ }
+ }
+ return proposals;
+ }
+
+ private Map<String, CompletionProposal> addSuperClassMethods(int confidence, IType type, boolean includeInstanceMethods) throws RubyModelException {
+ Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
+ String superClass = type.getSuperclassName();
+ if (superClass == null) return proposals;
+ RubyElementRequestor requestor = new RubyElementRequestor(type.getRubyScript());
+ IType[] supers = requestor.findType(superClass);
+ for (int i = 0; i < supers.length; i++) {
+ IType superType = supers[i];
+ proposals.putAll(doSuggestMethods(confidence, superType, includeInstanceMethods));
+ }
+ return proposals;
+ }
+
+ private CompletionProposal suggestMethod(IMethod method, String typeName, int confidence) {
+ int start = fContext.getReplaceStart();
+ String name = method.getElementName();
+ int flags = Flags.AccDefault;
+ if (method.isSingleton()) {
+ flags |= Flags.AccStatic;
+ if (method.isConstructor())
+ name = CONSTRUCTOR_INVOKE_NAME;
+ else {
+ if (name.startsWith(typeName)) {
+ name = name.substring(typeName.length() + 1);
+ }
+ }
+ } else {
+ // Don't show instance methods if the thing we're working on is a class' name!
+ // FIXME We do want to show if it is a constant, but not a class name
+ if (fContext.fullPrefixIsConstant()) return null;
+ }
+ if (!fContext.prefixStartsWith(name))
+ return null;
+
+ try {
+ switch (method.getVisibility()) {
+ case IMethod.PRIVATE:
+ flags |= Flags.AccPrivate;
+ if (!fOriginalType.getElementName().equals(typeName)) return null; // FIXME We should do a comparison of types, not names
+ if (fContext.hasReceiver()) return null; // can't invoke a private method on a receiver
+ break;
+ case IMethod.PUBLIC:
+ flags |= Flags.AccPublic; // FIXME Check if receiver is of same class as method's declaring type, if not, skip this method. (so we can invoke with no receiver inside same class, with explicit self as receiver, or with receiver who has same class).
+ break;
+ case IMethod.PROTECTED:
+ flags |= Flags.AccProtected;
+ break;
+ default:
+ break;
+ }
+ } catch (RubyModelException e) {
+ RubyCore.log(e);
+ flags |= Flags.AccPublic;
+ }
+ CompletionProposal proposal = createProposal(start, CompletionProposal.METHOD_REF, name, confidence, method);
+ proposal.setReplaceRange(start, start + name.length());
+ proposal.setFlags(flags);
+ proposal.setName(name);
+ IType declaringType = method.getDeclaringType();
+ String declaringName = typeName;
+ if (declaringType != null)
+ declaringName = declaringType.getFullyQualifiedName();
+ proposal.setDeclaringType(declaringName);
+ return proposal;
+ }
+
+ /**
+ * Gets all the distinct elements in the current RubyScript
+ *
+ * @param offset
+ * @param replaceStart
+ *
+ * @return a List of the names of all the elements in the current RubyScript
+ */
+ private void getDocumentsRubyElementsInScope() {
+ try {
+ // FIXME Try to stop all the multiple re-parsing of the source! Can
+ // we parse once and pass the root node around?
+ // Parse
+ Node rootNode = fContext.getRootNode();
+ if (rootNode == null) {
+ return;
+ }
+
+ // Grab enclosing scope
+ Node enclosingNode = findNearestScope(rootNode, fContext.getOffset());
+ if (enclosingNode == null) enclosingNode = rootNode;
+ // Add variables in this scope
+ Collection<String> variables = addVariablesinScope(getScope(enclosingNode));
+ for (String variable : variables) {
+ int type = CompletionProposal.LOCAL_VARIABLE_REF;
+ if (variable.startsWith("$")) {
+ type = Completion...
[truncated message content] |
|
From: <caw...@us...> - 2007-07-10 19:44:59
|
Revision: 2742
http://svn.sourceforge.net/rubyeclipse/?rev=2742&view=rev
Author: cawilliams
Date: 2007-07-10 11:38:06 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
fix #5141 - Generated class stub from Ruby ClassWizard has odd spacing
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/wizards/NewTypeWizardPage.java
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/wizards/NewTypeWizardPage.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/wizards/NewTypeWizardPage.java 2007-07-10 18:32:09 UTC (rev 2741)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/wizards/NewTypeWizardPage.java 2007-07-10 18:38:06 UTC (rev 2742)
@@ -662,14 +662,15 @@
RubyModelUtil.reconcile(cu);
- ISourceRange range= createdType.getSourceRange();
-
+ ISourceRange range= createdType.getSourceRange(); // FIXME The source range seems to be off by one... We have a workaround here, but need to fix it in IType
+ int length = range.getLength();
+ if (lineDelimiter.length() > 1) length++;
IBuffer buf= cu.getBuffer();
- String originalContent= buf.getText(range.getOffset(), range.getLength());
+ String originalContent= buf.getText(range.getOffset(), length);
String formattedContent= CodeFormatterUtil.format(CodeFormatter.K_CLASS_BODY_DECLARATIONS, originalContent, indent, null, lineDelimiter, pack.getRubyProject());
// formattedContent= Strings.trimLeadingTabsAndSpaces(formattedContent);
- buf.replace(range.getOffset(), range.getLength(), formattedContent);
+ buf.replace(range.getOffset(), length, formattedContent);
fCreatedType= createdType;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 19:44:45
|
Revision: 2741
http://svn.sourceforge.net/rubyeclipse/?rev=2741&view=rev
Author: cawilliams
Date: 2007-07-10 11:32:09 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
fix #5033 - Folder field ignored in Ruby Class wizard
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/wizards/NewTypeWizardPage.java
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/wizards/NewTypeWizardPage.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/wizards/NewTypeWizardPage.java 2007-07-10 17:14:42 UTC (rev 2740)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/wizards/NewTypeWizardPage.java 2007-07-10 18:32:09 UTC (rev 2741)
@@ -94,6 +94,8 @@
private final static String PAGE_NAME= "NewTypeWizardPage"; //$NON-NLS-1$
+ /** Field ID of the package input field. */
+ protected final static String PACKAGE= PAGE_NAME + ".package"; //$NON-NLS-1$
/** Field ID of the enclosing type input field. */
protected final static String ENCLOSING= PAGE_NAME + ".enclosing"; //$NON-NLS-1$
/** Field ID of the enclosing type checkbox. */
@@ -608,7 +610,8 @@
ISourceFolderRoot root = getSourceFolderRoot();
ISourceFolder pack= getSourceFolder();
if (pack == null) {
- pack= root.getSourceFolder(new String[] {}); }
+ pack= root.getSourceFolder(new String[] {});
+ }
if (!pack.exists()) {
String packName= pack.getElementName();
@@ -807,8 +810,14 @@
*/
private void typePageDialogFieldChanged(DialogField field) {
String fieldName= null;
- if (field == fTypeNameDialogField) {
+ if (field == fPackageDialogField) {
+ /*fPackageStatus=*/ packageChanged();
+// updatePackageStatusLabel();
fTypeNameStatus= typeNameChanged();
+ fSuperClassStatus= superClassChanged();
+ fieldName= PACKAGE;
+ } else if (field == fTypeNameDialogField) {
+ fTypeNameStatus= typeNameChanged();
fieldName= TYPENAME;
} else if (field == fSuperClassDialogField) {
fSuperClassStatus= superClassChanged();
@@ -905,7 +914,13 @@
*/
protected void handleFieldChanged(String fieldName) {
super.handleFieldChanged(fieldName);
-
+ if (fieldName == CONTAINER) {
+ /*fPackageStatus=*/ packageChanged();
+// fEnclosingTypeStatus= enclosingTypeChanged();
+ fTypeNameStatus= typeNameChanged();
+ fSuperClassStatus= superClassChanged();
+ fSuperModulesStatus= superInterfacesChanged();
+ }
doStatusUpdate();
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 17:15:36
|
Revision: 2740
http://svn.sourceforge.net/rubyeclipse/?rev=2740&view=rev
Author: cawilliams
Date: 2007-07-10 10:14:42 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java 2007-07-10 17:11:46 UTC (rev 2739)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java 2007-07-10 17:14:42 UTC (rev 2740)
@@ -64,7 +64,7 @@
public String[] getIncludedModuleNames() throws RubyModelException {
RubyTypeElementInfo info = (RubyTypeElementInfo) getElementInfo();
String[] modules = info.getIncludedModuleNames();
- if (modules == null || modules.length == 0 && getFullyQualifiedName().equals("Object")) {
+ if ((modules == null || modules.length == 0) && getFullyQualifiedName().equals("Object")) {
return new String[] {"Kernel"};
}
return modules;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 17:11:48
|
Revision: 2739
http://svn.sourceforge.net/rubyeclipse/?rev=2739&view=rev
Author: cawilliams
Date: 2007-07-10 10:11:46 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
improve code completion at top-level
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/CompletionProposal.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/preferences/MembersOrderPreferencePage.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/CompletionProposalLabelProvider.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/RubyScriptCompletion.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/viewsupport/RubyElementImageProvider.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/CompletionProposal.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/CompletionProposal.java 2007-07-10 16:22:43 UTC (rev 2738)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/CompletionProposal.java 2007-07-10 17:11:46 UTC (rev 2739)
@@ -2,17 +2,20 @@
public class CompletionProposal {
- public static final int FIELD_REF = 2;
+ public static final int GLOBAL_REF = 1;
+ public static final int CONSTANT_REF = 2;
public static final int KEYWORD = 3;
+ public static final int INSTANCE_VARIABLE_REF = 4;
public static final int LOCAL_VARIABLE_REF = 5;
public static final int METHOD_REF = 6;
public static final int METHOD_DECLARATION = 7;
+ public static final int CLASS_VARIABLE_REF = 8;
public static final int TYPE_REF = 9;
public static final int VARIABLE_DECLARATION = 10;
public static final int POTENTIAL_METHOD_DECLARATION = 11;
public static final int METHOD_NAME_REFERENCE = 12;
- protected static final int FIRST_KIND = FIELD_REF;
+ protected static final int FIRST_KIND = GLOBAL_REF;
protected static final int LAST_KIND = METHOD_NAME_REFERENCE;
/**
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-07-10 16:22:43 UTC (rev 2738)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-07-10 17:11:46 UTC (rev 2739)
@@ -140,18 +140,7 @@
});
for (Node typeNode : typeNodes) {
- List<Node> methods = ScopedNodeLocator.Instance().findNodesInScope(typeNode, new INodeAcceptor() {
-
- public boolean doesAccept(Node node) {
- return (node instanceof DefnNode) || (node instanceof DefsNode);
- }
-
- });
- for (Node methodNode : methods) {
- MethodDefNode methodDef = (MethodDefNode) methodNode;
- NodeMethod method = new NodeMethod(methodDef);
- list.add(suggestMethod(method, name, 100));
- }
+ list.addAll(addASTMethodsInScope(typeNode, name));
}
}
IType[] types = requestor.findType(name);
@@ -181,6 +170,28 @@
fContext = null;
}
+ private Collection<CompletionProposal> addASTMethodsInScope(Node typeNode, String name) {
+ List<CompletionProposal> list = new ArrayList<CompletionProposal>();
+ if (typeNode == null) return list;
+ List<Node> methods = ScopedNodeLocator.Instance().findNodesInScope(typeNode, new INodeAcceptor() {
+
+ public boolean doesAccept(Node node) {
+ return (node instanceof DefnNode) || (node instanceof DefsNode);
+ }
+
+ });
+ for (Node methodNode : methods) {
+ Node scoping = findNearestScope(typeNode, methodNode.getPosition().getStartOffset() - 1);
+ if (!scoping.equals(typeNode)) continue;
+ MethodDefNode methodDef = (MethodDefNode) methodNode;
+ NodeMethod method = new NodeMethod(methodDef);
+ CompletionProposal proposal = suggestMethod(method, name, 100);
+ if (proposal == null) continue;
+ list.add(proposal);
+ }
+ return list;
+ }
+
private Map<String, CompletionProposal> suggestTypesConstants(IType type) throws RubyModelException {
Map<String, CompletionProposal> proposals = new HashMap<String, CompletionProposal>();
SearchPattern pattern = SearchPattern.createPattern(IRubyElement.CONSTANT, "*", IRubySearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH);
@@ -190,7 +201,7 @@
IRubyElement element = (IRubyElement) match.getElement();
if (element.getElementType() != IRubyElement.CONSTANT) continue; // XXX we shouldn't have to do this
// Add proposal
- CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.FIELD_REF, element.getElementName());
+ CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, element.getElementName());
proposal.setType(type.getFullyQualifiedName());
proposal.setName(element.getElementName());
proposals.put(element.getElementName(), proposal);
@@ -249,19 +260,31 @@
private void suggestMethodsForEnclosingType(IRubyScript script) throws RubyModelException {
IMember element = (IMember) script.getElementAt(fContext.getOffset());
- IType type = null;
+ boolean includeInstance = !fContext.inTypeDefinition();
+ IType[] types;
if (element == null) {
// We're in the top level, so we're in "Object"
RubyElementRequestor requestor = new RubyElementRequestor(script);
- IType[] types = requestor.findType(OBJECT);
- if (types != null && types.length > 0) type = types[0];
+ IType[] tmpTypes = requestor.findType(OBJECT);
+ List<IType> filtered = new ArrayList<IType>();
+ for (int i = 0; i < tmpTypes.length; i++) {
+ // FIXME We shouldn't be getting these types with bad fully qualified names anyhow, should we?
+ if (!tmpTypes[i].getFullyQualifiedName().equals(OBJECT)) continue;
+ filtered.add(tmpTypes[i]);
+ }
+ types = filtered.toArray(new IType[filtered.size()]);
+ includeInstance = false;
} else if (element instanceof IType) {
- type = (IType) element;
+ types = new IType[] {(IType) element};
} else {
- type = element.getDeclaringType();
+ types = new IType[] {element.getDeclaringType()};
}
- if (type == null) return;
- List<CompletionProposal> list = sort(suggestMethods(100, type, !fContext.inTypeDefinition()));
+ if (types == null || types.length < 1) return;
+ Map<String, CompletionProposal> map = new HashMap<String, CompletionProposal>();
+ for (int i = 0; i < types.length; i++) {
+ map.putAll(suggestMethods(100, types[i], includeInstance));
+ }
+ List<CompletionProposal> list = sort(map);
for (CompletionProposal proposal : list) {
fRequestor.accept(proposal);
}
@@ -300,7 +323,7 @@
String name = element.getElementName();
if (!fContext.prefixStartsWith(name))
continue;
- CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.FIELD_REF, name);
+ CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, name);
proposal.setType(name);
fRequestor.accept(proposal);
}
@@ -349,7 +372,7 @@
String name = element.getElementName();
if (!fContext.prefixStartsWith(name))
continue;
- CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.FIELD_REF, name);
+ CompletionProposal proposal = createProposal(fContext.getReplaceStart(), CompletionProposal.CONSTANT_REF, name);
proposal.setType(name);
fRequestor.accept(proposal);
}
@@ -487,24 +510,37 @@
return;
}
- // XXX Just find enclosing scope and grab variables?
- Node enclosingNode = ClosestSpanningNodeLocator.Instance().findClosestSpanner(rootNode, fContext.getOffset(), new INodeAcceptor() {
- public boolean doesAccept(Node node) {
- return (node instanceof DefnNode || node instanceof DefsNode || node instanceof ClassNode || node instanceof ModuleNode || node instanceof RootNode);
- }
- });
-
+ // Grab enclosing scope
+ Node enclosingNode = findNearestScope(rootNode, fContext.getOffset());
+ if (enclosingNode == null) enclosingNode = rootNode;
+ // Add variables in this scope
Collection<String> variables = addVariablesinScope(getScope(enclosingNode));
for (String variable : variables) {
- CompletionProposal proposal = new CompletionProposal(CompletionProposal.LOCAL_VARIABLE_REF, variable, 100);
+ int type = CompletionProposal.LOCAL_VARIABLE_REF;
+ if (variable.startsWith("$")) {
+ type = CompletionProposal.GLOBAL_REF;
+ }
+ CompletionProposal proposal = new CompletionProposal(type, variable, 100);
proposal.setReplaceRange(fContext.getReplaceStart(), fContext.getReplaceStart() + variable.length());
fRequestor.accept(proposal);
}
+ // Add methods in this scope
+ Node enclosingTypeNode = ClosestSpanningNodeLocator.Instance().findClosestSpanner(rootNode, fContext.getOffset(), new INodeAcceptor() {
+ public boolean doesAccept(Node node) {
+ return (node instanceof ClassNode || node instanceof ModuleNode || node instanceof RootNode);
+ }
+ });
+ if (enclosingTypeNode == null) enclosingTypeNode = rootNode;
+ Collection<CompletionProposal> methodProposals = addASTMethodsInScope(enclosingTypeNode, "");
+ for (CompletionProposal proposal : methodProposals) {
+ if (proposal == null) continue;
+ fRequestor.accept(proposal);
+ }
// Find the enclosing type (class or module) to get instance and
// classvars from
- Node enclosingTypeNode = ClosestSpanningNodeLocator.Instance().findClosestSpanner(rootNode, fContext.getOffset(), new INodeAcceptor() {
+ enclosingTypeNode = ClosestSpanningNodeLocator.Instance().findClosestSpanner(rootNode, fContext.getOffset(), new INodeAcceptor() {
public boolean doesAccept(Node node) {
return (node instanceof ClassNode || node instanceof ModuleNode);
}
@@ -523,6 +559,14 @@
}
}
+ private Node findNearestScope(Node scopeNode, int offset) {
+ return ClosestSpanningNodeLocator.Instance().findClosestSpanner(scopeNode, offset, new INodeAcceptor() {
+ public boolean doesAccept(Node node) {
+ return (node instanceof DefnNode || node instanceof DefsNode || node instanceof ClassNode || node instanceof ModuleNode || node instanceof RootNode);
+ }
+ });
+ }
+
private Set<String> addVariablesinScope(StaticScope scope) {
Set<String> matches = new HashSet<String>();
if (scope == null) return matches;
@@ -538,6 +582,7 @@
}
private StaticScope getScope(Node enclosingNode) {
+ if (enclosingNode == null) return ((RootNode)fContext.getRootNode()).getStaticScope();
if (enclosingNode instanceof RootNode) {
RootNode root = (RootNode) enclosingNode;
return root.getStaticScope();
@@ -643,7 +688,7 @@
fields.add(attr);
}
for (String field : fields) {
- CompletionProposal proposal = new CompletionProposal(CompletionProposal.FIELD_REF, field, 100);
+ CompletionProposal proposal = new CompletionProposal(CompletionProposal.CONSTANT_REF, field, 100);
proposal.setReplaceRange(fContext.getReplaceStart(), fContext.getReplaceStart() + field.length());
fRequestor.accept(proposal);
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java 2007-07-10 16:22:43 UTC (rev 2738)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java 2007-07-10 17:11:46 UTC (rev 2739)
@@ -61,9 +61,13 @@
/**
* @see IType
*/
- public String[] getIncludedModuleNames() throws RubyModelException {
+ public String[] getIncludedModuleNames() throws RubyModelException {
RubyTypeElementInfo info = (RubyTypeElementInfo) getElementInfo();
- return info.getIncludedModuleNames();
+ String[] modules = info.getIncludedModuleNames();
+ if (modules == null || modules.length == 0 && getFullyQualifiedName().equals("Object")) {
+ return new String[] {"Kernel"};
+ }
+ return modules;
}
/**
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/preferences/MembersOrderPreferencePage.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/preferences/MembersOrderPreferencePage.java 2007-07-10 16:22:43 UTC (rev 2738)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/preferences/MembersOrderPreferencePage.java 2007-07-10 17:11:46 UTC (rev 2739)
@@ -281,7 +281,7 @@
String s= (String) element;
if (s.equals(FIELDS)) {
//0 will give the default field image
- descriptor= RubyElementImageProvider.getFieldImageDescriptor();
+ descriptor= RubyElementImageProvider.getConstantImageDescriptor();
} else if (s.equals(CONSTRUCTORS)) {
descriptor= RubyElementImageProvider.getMethodImageDescriptor(visibility);
//add a constructor adornment to the image descriptor
@@ -289,7 +289,7 @@
} else if (s.equals(METHODS)) {
descriptor= RubyElementImageProvider.getMethodImageDescriptor(visibility);
} else if (s.equals(STATIC_FIELDS)) {
- descriptor= RubyElementImageProvider.getFieldImageDescriptor();
+ descriptor= RubyElementImageProvider.getConstantImageDescriptor();
//add a static fields adornment to the image descriptor
descriptor= new RubyElementImageDescriptor(descriptor, RubyElementImageDescriptor.STATIC, RubyElementImageProvider.SMALL_SIZE);
} else if (s.equals(STATIC_METHODS)) {
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/CompletionProposalLabelProvider.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/CompletionProposalLabelProvider.java 2007-07-10 16:22:43 UTC (rev 2738)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/CompletionProposalLabelProvider.java 2007-07-10 17:11:46 UTC (rev 2739)
@@ -53,9 +53,18 @@
descriptor = RubyElementImageProvider.getTypeImageDescriptor(
false, false, false);
break;
- case CompletionProposal.FIELD_REF:
- descriptor = RubyElementImageProvider.getFieldImageDescriptor();
+ case CompletionProposal.CONSTANT_REF:
+ descriptor = RubyElementImageProvider.getConstantImageDescriptor();
break;
+ case CompletionProposal.GLOBAL_REF:
+ descriptor = RubyElementImageProvider.getGlobalVariableImageDescriptor();
+ break;
+ case CompletionProposal.INSTANCE_VARIABLE_REF:
+ descriptor = RubyElementImageProvider.getInstanceVariableImageDescriptor();
+ break;
+ case CompletionProposal.CLASS_VARIABLE_REF:
+ descriptor = RubyElementImageProvider.getClassVariableImageDescriptor();
+ break;
case CompletionProposal.LOCAL_VARIABLE_REF:
case CompletionProposal.VARIABLE_DECLARATION:
descriptor = RubyPluginImages.DESC_OBJS_LOCAL_VAR;
@@ -87,7 +96,7 @@
int flags= proposal.getFlags();
int kind= proposal.getKind();
- if (kind == CompletionProposal.FIELD_REF || kind == CompletionProposal.METHOD_DECLARATION || kind == CompletionProposal.METHOD_DECLARATION || kind == CompletionProposal.METHOD_NAME_REFERENCE || kind == CompletionProposal.METHOD_REF)
+ if (kind == CompletionProposal.CONSTANT_REF || kind == CompletionProposal.METHOD_DECLARATION || kind == CompletionProposal.METHOD_DECLARATION || kind == CompletionProposal.METHOD_NAME_REFERENCE || kind == CompletionProposal.METHOD_REF)
if (Flags.isStatic(flags))
adornments |= RubyElementImageDescriptor.STATIC;
@@ -104,7 +113,10 @@
// return createOverrideMethodProposalLabel(proposal);
case CompletionProposal.TYPE_REF:
return createTypeProposalLabel(proposal);
- case CompletionProposal.FIELD_REF:
+ case CompletionProposal.CONSTANT_REF:
+ case CompletionProposal.CLASS_VARIABLE_REF:
+ case CompletionProposal.INSTANCE_VARIABLE_REF:
+ case CompletionProposal.GLOBAL_REF:
case CompletionProposal.LOCAL_VARIABLE_REF:
case CompletionProposal.VARIABLE_DECLARATION:
case CompletionProposal.METHOD_DECLARATION:
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/RubyScriptCompletion.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/RubyScriptCompletion.java 2007-07-10 16:22:43 UTC (rev 2738)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/ruby/RubyScriptCompletion.java 2007-07-10 17:11:46 UTC (rev 2739)
@@ -131,7 +131,9 @@
return baseRelevance + 4;
case CompletionProposal.POTENTIAL_METHOD_DECLARATION:
return baseRelevance + 4 /* + 99 */;
- case CompletionProposal.FIELD_REF:
+ case CompletionProposal.CONSTANT_REF:
+ case CompletionProposal.CLASS_VARIABLE_REF:
+ case CompletionProposal.INSTANCE_VARIABLE_REF:
return baseRelevance + 5;
case CompletionProposal.LOCAL_VARIABLE_REF:
case CompletionProposal.VARIABLE_DECLARATION:
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/viewsupport/RubyElementImageProvider.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/viewsupport/RubyElementImageProvider.java 2007-07-10 16:22:43 UTC (rev 2738)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/viewsupport/RubyElementImageProvider.java 2007-07-10 17:11:46 UTC (rev 2739)
@@ -301,8 +301,19 @@
return RubyPluginImages.DESC_OBJS_MODULE;
}
- public static ImageDescriptor getFieldImageDescriptor() {
- // TODO What about other types of fields!
+ public static ImageDescriptor getConstantImageDescriptor() {
+ return RubyPluginImages.DESC_OBJS_CONSTANT;
+ }
+
+ public static ImageDescriptor getClassVariableImageDescriptor() {
return RubyPluginImages.DESC_OBJS_CLASS_VAR;
}
+
+ public static ImageDescriptor getInstanceVariableImageDescriptor() {
+ return RubyPluginImages.DESC_OBJS_INSTANCE_VAR;
+ }
+
+ public static ImageDescriptor getGlobalVariableImageDescriptor() {
+ return RubyPluginImages.DESC_OBJS_GLOBAL;
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 16:23:36
|
Revision: 2738
http://svn.sourceforge.net/rubyeclipse/?rev=2738&view=rev
Author: cawilliams
Date: 2007-07-10 09:22:43 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
fix #5055 - Missing english names in Refactor menus
Modified Paths:
--------------
trunk/org.rubypeople.rdt.refactoring/plugin.properties
Modified: trunk/org.rubypeople.rdt.refactoring/plugin.properties
===================================================================
--- trunk/org.rubypeople.rdt.refactoring/plugin.properties 2007-07-10 16:20:18 UTC (rev 2737)
+++ trunk/org.rubypeople.rdt.refactoring/plugin.properties 2007-07-10 16:22:43 UTC (rev 2738)
@@ -8,6 +8,7 @@
rubyRefactoring.ConvertTempToFieldLabel=Convert Local Variable to Field...
rubyRefactoring.EncapsulateField=Encapsulate Field...
rubyRefactoring.ExtractMethodLabel=Extract Method...
+rubyRefactoring.ExtractConstantLabel=Extract Constant...
rubyRefactoring.FormatSourceLabel=Format Source...
rubyRefactoring.GenerateAccessorLabel=Generate Accessors...
rubyRefactoring.GenerateConstructorLabel=Generate Constructor Using Field...
@@ -19,6 +20,7 @@
rubyRefactoring.MoveFieldLabel=Move Field...
rubyRefactoring.OverrideMethodLabel=Override Method...
rubyRefactoring.PushDownLabel=Push Down...
+rubyRefactoring.PullUpLabel=Pull Up...
rubyRefactoring.RenameFieldLabel=Rename Field...
rubyRefactoring.RenameClassLabel=Rename Class...
rubyRefactoring.RenameMethodLabel=Rename Method...
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 16:21:46
|
Revision: 2737
http://svn.sourceforge.net/rubyeclipse/?rev=2737&view=rev
Author: cawilliams
Date: 2007-07-10 09:20:18 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
fix #4939 - Change text in Ruby Search Dialog. make some of the labels more "Ruby-like"
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/SearchMessages.properties
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/SearchMessages.properties
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/SearchMessages.properties 2007-07-10 16:15:14 UTC (rev 2736)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/SearchMessages.properties 2007-07-10 16:20:18 UTC (rev 2737)
@@ -11,13 +11,13 @@
# Aptana, Inc. - Chris Williams - initial API and implementation
###############################################################################
SearchPage_searchFor_label= Search For
-SearchPage_searchFor_type= &Type
+SearchPage_searchFor_type= &Classes and Modules
SearchPage_searchFor_method= &Method
-SearchPage_searchFor_field= &Field
+SearchPage_searchFor_field= &Variables and Constants
SearchPage_searchFor_constructor= Co&nstructor
SearchPage_limitTo_label= Limit To
-SearchPage_limitTo_declarations= Dec&larations
+SearchPage_limitTo_declarations= &Definitions
SearchPage_limitTo_references= &References
SearchPage_limitTo_allOccurrences= All &occurrences
SearchPage_limitTo_readReferences= Read a&ccesses
@@ -33,8 +33,8 @@
RubySearchResultPage_groupby_project=Project
RubySearchResultPage_groupby_project_tooltip=Group by Project
-RubySearchResultPage_groupby_package=Package
-RubySearchResultPage_groupby_package_tooltip=Group by Package
+RubySearchResultPage_groupby_package=Namespace
+RubySearchResultPage_groupby_package_tooltip=Group by Namespace
RubySearchResultPage_filteredWithCount_message={0} ({1} matches filtered from view)
RubySearchResultPage_groupby_file=File
RubySearchResultPage_groupby_file_tooltip=Group by File
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 16:15:17
|
Revision: 2736
http://svn.sourceforge.net/rubyeclipse/?rev=2736&view=rev
Author: cawilliams
Date: 2007-07-10 09:15:14 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
fix #5129 - Duplicate Search menu appears in Ruby editor right-click popup menu
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java 2007-07-10 16:15:01 UTC (rev 2735)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java 2007-07-10 16:15:14 UTC (rev 2736)
@@ -751,8 +751,6 @@
protected void editorContextMenuAboutToShow(IMenuManager menu) {
super.editorContextMenuAboutToShow(menu);
- fActionGroups.fillContextMenu(menu) ;
-
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint extensionPoint = registry
.getExtensionPoint("org.rubypeople.rdt.ui.editorPopupExtender");
@@ -794,9 +792,10 @@
fContextMenuGroup.setContext(null);
// Quick views
- // TODO Add show outline action!
-// IAction action= getAction(IRubyEditorActionDefinitionIds.SHOW_OUTLINE);
-// menu.appendToGroup(IContextMenuConstants.GROUP_OPEN, action);
+ IAction action= getAction(IRubyEditorActionDefinitionIds.SHOW_OUTLINE);
+ menu.appendToGroup(IContextMenuConstants.GROUP_OPEN, action);
+// action= getAction(IRubyEditorActionDefinitionIds.OPEN_HIERARCHY);
+// menu.appendToGroup(IContextMenuConstants.GROUP_OPEN, action);
}
protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 16:15:03
|
Revision: 2735
http://svn.sourceforge.net/rubyeclipse/?rev=2735&view=rev
Author: cawilliams
Date: 2007-07-10 09:15:01 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/actions/RubySearchActionGroup.java
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/actions/RubySearchActionGroup.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/actions/RubySearchActionGroup.java 2007-07-10 14:55:48 UTC (rev 2734)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/actions/RubySearchActionGroup.java 2007-07-10 16:15:01 UTC (rev 2735)
@@ -126,7 +126,7 @@
public void fillContextMenu(IMenuManager menu) {
super.fillContextMenu(menu);
- if(PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.SEARCH_USE_REDUCED_MENU)) {
+ if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.SEARCH_USE_REDUCED_MENU)) {
fReferencesGroup.fillContextMenu(menu);
fDeclarationsGroup.fillContextMenu(menu);
@@ -152,7 +152,7 @@
fWriteAccessGroup.fillContextMenu(target);
if (searchSubMenu != null) {
- fOccurrencesGroup.fillContextMenu(target);
+ fOccurrencesGroup.fillContextMenu(target);
searchSubMenu.add(new Separator());
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-10 14:55:50
|
Revision: 2734
http://svn.sourceforge.net/rubyeclipse/?rev=2734&view=rev
Author: cawilliams
Date: 2007-07-10 07:55:48 -0700 (Tue, 10 Jul 2007)
Log Message:
-----------
move all code for getting root node into Completion Context. Make it smater, so it will cache the root node, and also so it will try to auto fix or drop back the the last good AST
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionContext.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionContext.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionContext.java 2007-07-09 21:39:14 UTC (rev 2733)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionContext.java 2007-07-10 14:55:48 UTC (rev 2734)
@@ -7,6 +7,7 @@
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.internal.core.RubyScript;
+import org.rubypeople.rdt.internal.core.parser.RubyParser;
import org.rubypeople.rdt.internal.ti.util.ClosestSpanningNodeLocator;
import org.rubypeople.rdt.internal.ti.util.INodeAcceptor;
@@ -20,6 +21,7 @@
private String fullPrefix;
private int replaceStart;
private boolean isAfterDoubleSemiColon = false;
+ private Node fRootNode;
public CompletionContext(IRubyScript script, int offset) throws RubyModelException {
this.script = script;
@@ -207,7 +209,26 @@
}
Node getRootNode() {
- return ((RubyScript) getScript()).lastGoodAST;
+ if (fRootNode != null) return fRootNode;
+ RubyParser parser = new RubyParser();
+ if (!isBroken()) {
+ try {
+ fRootNode = parser.parse(getSource());
+ } catch (RuntimeException e) {
+ // ignore
+ }
+ }
+ if (fRootNode == null) {
+ try {
+ fRootNode = parser.parse(getCorrectedSource());
+ } catch (RuntimeException e) {
+ // ignore
+ }
+ }
+ if (fRootNode == null) {
+ fRootNode = ((RubyScript) getScript()).lastGoodAST;
+ }
+ return fRootNode;
}
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-07-09 21:39:14 UTC (rev 2733)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-07-10 14:55:48 UTC (rev 2734)
@@ -128,7 +128,7 @@
for (ITypeGuess guess : guesses) {
final String name = guess.getType();
if (fContext.isBroken()) {
- Node rootNode = new RubyParser().parse(fContext.getCorrectedSource());
+ Node rootNode = fContext.getRootNode();
List<Node> typeNodes = ScopedNodeLocator.Instance().findNodesInScope(rootNode, new INodeAcceptor() {
public boolean doesAccept(Node node) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-09 21:39:15
|
Revision: 2733
http://svn.sourceforge.net/rubyeclipse/?rev=2733&view=rev
Author: cawilliams
Date: 2007-07-09 14:39:14 -0700 (Mon, 09 Jul 2007)
Log Message:
-----------
remove unused import
Modified Paths:
--------------
trunk/com.aptana.rdt/src/com/aptana/rdt/ui/gems/GemsView.java
Modified: trunk/com.aptana.rdt/src/com/aptana/rdt/ui/gems/GemsView.java
===================================================================
--- trunk/com.aptana.rdt/src/com/aptana/rdt/ui/gems/GemsView.java 2007-07-09 21:39:04 UTC (rev 2732)
+++ trunk/com.aptana.rdt/src/com/aptana/rdt/ui/gems/GemsView.java 2007-07-09 21:39:14 UTC (rev 2733)
@@ -26,7 +26,6 @@
import com.aptana.rdt.AptanaRDTPlugin;
import com.aptana.rdt.core.gems.Gem;
import com.aptana.rdt.core.gems.GemListener;
-import com.aptana.rdt.internal.core.gems.GemManager;
public class GemsView extends ViewPart implements GemListener {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-09 21:39:07
|
Revision: 2732
http://svn.sourceforge.net/rubyeclipse/?rev=2732&view=rev
Author: cawilliams
Date: 2007-07-09 14:39:04 -0700 (Mon, 09 Jul 2007)
Log Message:
-----------
add copyright
Modified Paths:
--------------
trunk/com.aptana.rdt/src/com/aptana/rdt/ui/gems/GemsMessages.properties
Modified: trunk/com.aptana.rdt/src/com/aptana/rdt/ui/gems/GemsMessages.properties
===================================================================
--- trunk/com.aptana.rdt/src/com/aptana/rdt/ui/gems/GemsMessages.properties 2007-07-09 18:36:47 UTC (rev 2731)
+++ trunk/com.aptana.rdt/src/com/aptana/rdt/ui/gems/GemsMessages.properties 2007-07-09 21:39:04 UTC (rev 2732)
@@ -1,3 +1,16 @@
+###############################################################################
+# Copyright (c) 2007 Aptana, Inc.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html. If redistributing this code,
+# this entire header must remain intact.
+###############################################################################
+# messages.properties
+# contains externalized strings for com.aptana.rdt
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# This file should be translated.
GemsView_NameColumn_label=Name
GemsView_VersionColumn_label=Version
GemsView_DescriptionColumn_label=Description
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-09 18:37:09
|
Revision: 2731
http://svn.sourceforge.net/rubyeclipse/?rev=2731&view=rev
Author: cawilliams
Date: 2007-07-09 11:36:47 -0700 (Mon, 09 Jul 2007)
Log Message:
-----------
fix #4933 - Hitting Ctrl-H brings up bad search text
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/PatternStrings.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/RubySearchPage.java
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/PatternStrings.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/PatternStrings.java 2007-07-09 14:17:15 UTC (rev 2730)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/PatternStrings.java 2007-07-09 18:36:47 UTC (rev 2731)
@@ -35,27 +35,30 @@
}
public static String getMethodSignature(IMethod method) {
+
StringBuffer buffer= new StringBuffer();
- buffer.append(RubyElementLabels.getElementLabel(
- method.getDeclaringType(),
- RubyElementLabels.T_FULLY_QUALIFIED | RubyElementLabels.USE_RESOLVED));
- boolean isConstructor= method.getElementName().equals(method.getDeclaringType().getElementName());
- if (!isConstructor) {
+ if (method.isSingleton() || method.isConstructor()) {
+ buffer.append(RubyElementLabels.getElementLabel(method.getDeclaringType(), RubyElementLabels.USE_RESOLVED));
buffer.append('.');
}
- buffer.append(getUnqualifiedMethodSignature(method, !isConstructor));
-
+ boolean isConstructor= method.isConstructor();
+ if (!isConstructor) {
+ buffer.append(getUnqualifiedMethodSignature(method, !isConstructor));
+ } else {
+ buffer.append("new");
+ }
+
return buffer.toString();
}
- private static String getUnqualifiedMethodSignature(IMethod method, boolean includeName) {
+ private static String getUnqualifiedMethodSignature(IMethod method, boolean isNotConstructor) {
StringBuffer buffer= new StringBuffer();
- if (includeName) {
+ if (isNotConstructor) {
buffer.append(method.getElementName());
}
- buffer.append('(');
+// buffer.append('(');
// TODO Add parameter names, or arity?
- buffer.append(')');
+// buffer.append(')');
return buffer.toString();
}
@@ -65,11 +68,10 @@
}
public static String getTypeSignature(IType field) {
- return RubyElementLabels.getElementLabel(field,
- RubyElementLabels.T_FULLY_QUALIFIED | RubyElementLabels.USE_RESOLVED);
+ return RubyElementLabels.getElementLabel(field, RubyElementLabels.USE_RESOLVED);
}
public static String getFieldSignature(IField field) {
- return RubyElementLabels.getElementLabel(field, RubyElementLabels.F_FULLY_QUALIFIED);
+ return RubyElementLabels.getElementLabel(field, 0);
}
}
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/RubySearchPage.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/RubySearchPage.java 2007-07-09 14:17:15 UTC (rev 2730)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/search/RubySearchPage.java 2007-07-09 18:36:47 UTC (rev 2731)
@@ -486,7 +486,7 @@
selectParticipants.setLayoutData(gd);
selectParticipants.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
- PreferencePageSupport.showPreferencePage(getShell(), "org.eclipse.jdt.ui.preferences.SearchParticipantsExtensionPoint", new SearchParticipantsExtensionPoint()); //$NON-NLS-1$
+ PreferencePageSupport.showPreferencePage(getShell(), "org.rubypeople.rdt.ui.preferences.SearchParticipantsExtensionPoint", new SearchParticipantsExtensionPoint()); //$NON-NLS-1$
}
});
@@ -775,6 +775,11 @@
break;
}
case IRubyElement.FIELD:
+ case IRubyElement.INSTANCE_VAR:
+ case IRubyElement.LOCAL_VARIABLE:
+ case IRubyElement.CLASS_VAR:
+ case IRubyElement.GLOBAL:
+ case IRubyElement.CONSTANT:
return new SearchPatternData(FIELD, REFERENCES, true, PatternStrings.getFieldSignature((IField) element), element, isInsideJRE);
case IRubyElement.METHOD:
IMethod method= (IMethod) element;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-09 14:17:17
|
Revision: 2730
http://svn.sourceforge.net/rubyeclipse/?rev=2730&view=rev
Author: cawilliams
Date: 2007-07-09 07:17:15 -0700 (Mon, 09 Jul 2007)
Log Message:
-----------
fix #5057 - Hide local types doesn't seem to work
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/actions/ActionMessages.properties
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/viewsupport/MemberFilter.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/PreferenceConstants.java
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/actions/ActionMessages.properties
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/actions/ActionMessages.properties 2007-07-09 13:54:27 UTC (rev 2729)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/actions/ActionMessages.properties 2007-07-09 14:17:15 UTC (rev 2730)
@@ -33,17 +33,17 @@
MemberFilterActionGroup_hide_fields_tooltip=Hide Fields
MemberFilterActionGroup_hide_fields_description=Toggles the visibility of fields
-MemberFilterActionGroup_hide_static_label=Hide &Static Fields and Methods
-MemberFilterActionGroup_hide_static_tooltip=Hide Static Fields and Methods
-MemberFilterActionGroup_hide_static_description=Toggles the visibility of static fields and methods
+MemberFilterActionGroup_hide_static_label=Hide Class-level Fields and Methods
+MemberFilterActionGroup_hide_static_tooltip=Hide Class-level Fields and Methods
+MemberFilterActionGroup_hide_static_description=Toggles the visibility of class-level fields and methods
MemberFilterActionGroup_hide_nonpublic_label=Hide Non-&Public Members
MemberFilterActionGroup_hide_nonpublic_tooltip=Hide Non-Public Members
MemberFilterActionGroup_hide_nonpublic_description=Toggles the visibility of non-public members
-MemberFilterActionGroup_hide_localtypes_label=Hide Local &Types
-MemberFilterActionGroup_hide_localtypes_tooltip=Hide Local Types
-MemberFilterActionGroup_hide_localtypes_description=Toggles the visibility of local types
+MemberFilterActionGroup_hide_localtypes_label=Hide Local Variables
+MemberFilterActionGroup_hide_localtypes_tooltip=Hide Local Variables
+MemberFilterActionGroup_hide_localtypes_description=Toggles the visibility of local and dynamic variables
ToggleLinkingAction_label=Lin&k With Editor
ToggleLinkingAction_tooltip=Link with Editor
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/viewsupport/MemberFilter.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/viewsupport/MemberFilter.java 2007-07-09 13:54:27 UTC (rev 2729)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/viewsupport/MemberFilter.java 2007-07-09 14:17:15 UTC (rev 2730)
@@ -16,7 +16,6 @@
import org.rubypeople.rdt.core.IMember;
import org.rubypeople.rdt.core.IMethod;
import org.rubypeople.rdt.core.IRubyElement;
-import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.RubyModelException;
/**
@@ -84,25 +83,9 @@
}
if (hasFilter(FILTER_STATIC) && method.isSingleton()) { return false; }
}
- if (hasFilter(FILTER_LOCALTYPES) && memberType == IRubyElement.TYPE
- && isLocalType((IType) member)) { return false; }
-
- if (member.getElementName().startsWith("<")) { // filter out
- // <clinit>
- // //$NON-NLS-1$
- return false;
- }
+ if (hasFilter(FILTER_LOCALTYPES) &&
+ (memberType == IRubyElement.LOCAL_VARIABLE || memberType == IRubyElement.DYNAMIC_VAR)) { return false; }
}
return true;
}
-
- private boolean isLocalType(IType type) {
- IRubyElement parent = type.getParent();
- return parent instanceof IMember && !(parent instanceof IType);
- }
-
- private boolean isTopLevelType(IMember member) {
- IType parent = member.getDeclaringType();
- return parent == null;
- }
}
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/PreferenceConstants.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/PreferenceConstants.java 2007-07-09 13:54:27 UTC (rev 2729)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/PreferenceConstants.java 2007-07-09 14:17:15 UTC (rev 2730)
@@ -818,6 +818,8 @@
store.setDefault(PreferenceConstants.APPEARANCE_MEMBER_SORT_ORDER, "T,SF,SM,F,C,M"); //$NON-NLS-1$
store.setDefault(PreferenceConstants.APPEARANCE_VISIBILITY_SORT_ORDER, "B,V,R"); //$NON-NLS-1$
store.setDefault(PreferenceConstants.APPEARANCE_ENABLE_VISIBILITY_SORT_ORDER, false);
+
+ store.setDefault("MemberFilterActionGroup.org.rubypeople.rdt.ui.RubyOutlinePage.4", true);
// AppearancePreferencePage
store.setDefault(PreferenceConstants.APPEARANCE_COMPRESS_PACKAGE_NAMES, false);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-09 13:54:29
|
Revision: 2729
http://svn.sourceforge.net/rubyeclipse/?rev=2729&view=rev
Author: cawilliams
Date: 2007-07-09 06:54:27 -0700 (Mon, 09 Jul 2007)
Log Message:
-----------
fix #4959 - Ctrl+Space inside a class definition autocompletes not only class methods but instance methods
Only show class methods, and don't show private class methods from types up the hierarchy
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionContext.java
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionContext.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionContext.java 2007-07-09 12:47:18 UTC (rev 2728)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionContext.java 2007-07-09 13:54:27 UTC (rev 2729)
@@ -1,7 +1,14 @@
package org.rubypeople.rdt.internal.codeassist;
+import org.jruby.ast.ClassNode;
+import org.jruby.ast.MethodDefNode;
+import org.jruby.ast.ModuleNode;
+import org.jruby.ast.Node;
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.internal.core.RubyScript;
+import org.rubypeople.rdt.internal.ti.util.ClosestSpanningNodeLocator;
+import org.rubypeople.rdt.internal.ti.util.INodeAcceptor;
public class CompletionContext {
@@ -184,4 +191,23 @@
return Character.isUpperCase(getFullPrefix().charAt(0));
}
+ /**
+ * Returns whether we're inside a type definition and not inside a method definition (used to determine if we should only show class level methods)
+ * @return
+ */
+ public boolean inTypeDefinition() {
+ Node spanner = ClosestSpanningNodeLocator.Instance().findClosestSpanner(getRootNode(), getOffset(), new INodeAcceptor() {
+
+ public boolean doesAccept(Node node) {
+ return node instanceof MethodDefNode || node instanceof ClassNode || node instanceof ModuleNode;
+ }
+
+ });
+ return spanner instanceof ClassNode || spanner instanceof ModuleNode;
+ }
+
+ Node getRootNode() {
+ return ((RubyScript) getScript()).lastGoodAST;
+ }
+
}
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-07-09 12:47:18 UTC (rev 2728)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/codeassist/CompletionEngine.java 2007-07-09 13:54:27 UTC (rev 2729)
@@ -52,7 +52,6 @@
import org.rubypeople.rdt.core.search.SearchParticipant;
import org.rubypeople.rdt.core.search.SearchPattern;
import org.rubypeople.rdt.internal.core.RubyElement;
-import org.rubypeople.rdt.internal.core.RubyScript;
import org.rubypeople.rdt.internal.core.RubyType;
import org.rubypeople.rdt.internal.core.parser.RubyParser;
import org.rubypeople.rdt.internal.core.search.BasicSearchEngine;
@@ -76,10 +75,14 @@
private CompletionRequestor fRequestor;
private CompletionContext fContext;
private Set<IType> fVisitedTypes;
+ /**
+ * temporary place to hold the original type we're completing for. Used to determine if we should be showing private methods.
+ */
+ private IType fOriginalType;
public CompletionEngine(CompletionRequestor requestor) {
this.fRequestor = requestor;
- }
+ }
public void complete(IRubyScript script, int offset) throws RubyModelException {
this.fRequestor.beginReporting();
@@ -258,7 +261,7 @@
type = element.getDeclaringType();
}
if (type == null) return;
- List<CompletionProposal> list = sort(suggestMethods(100, type, true));
+ List<CompletionProposal> list = sort(suggestMethods(100, type, !fContext.inTypeDefinition()));
for (CompletionProposal proposal : list) {
fRequestor.accept(proposal);
}
@@ -275,8 +278,10 @@
*/
private Map<String, CompletionProposal> suggestMethods(int confidence, IType type, boolean includeInstanceMethods) throws RubyModelException {
if (fVisitedTypes == null) fVisitedTypes = new HashSet<IType>();
- Map<String, CompletionProposal> list = doSuggestMethods(100, type, true);
+ fOriginalType = type;
+ Map<String, CompletionProposal> list = doSuggestMethods(100, type, includeInstanceMethods);
fVisitedTypes.clear();
+ fOriginalType = null;
return list;
}
@@ -357,17 +362,18 @@
if (fVisitedTypes.contains(type)) return proposals;
fVisitedTypes.add(type);
IMethod[] methods = type.getMethods();
- if (methods == null) return proposals;
- for (int k = 0; k < methods.length; k++) {
- if (methods[k] == null) continue;
- if (!includeInstanceMethods && !methods[k].isSingleton()) {
- continue;
- }
- CompletionProposal proposal = suggestMethod(methods[k], type.getElementName(), confidence);
- if (proposal != null && !proposals.containsKey(proposal.getName())) {
- proposals.put(proposal.getName(), proposal); // If a method name matches an existing suggestion (i.e. its overriden in the subclass), don't suggest it again!
- }
- }
+ if (methods != null) {
+ for (int k = 0; k < methods.length; k++) {
+ if (methods[k] == null) continue;
+ if (!includeInstanceMethods && !methods[k].isSingleton()) {
+ continue;
+ }
+ CompletionProposal proposal = suggestMethod(methods[k], type.getElementName(), confidence);
+ if (proposal != null && !proposals.containsKey(proposal.getName())) {
+ proposals.put(proposal.getName(), proposal); // If a method name matches an existing suggestion (i.e. its overriden in the subclass), don't suggest it again!
+ }
+ }
+ }
proposals.putAll(addModuleMethods(confidence - 1, type)); // Decrement confidence by one as a hack to make sure as we move up the inheritance chain we suggest "closer" parents methods first
if (!type.isModule()) proposals.putAll(addSuperClassMethods(confidence - 1, type, includeInstanceMethods));
return proposals;
@@ -435,6 +441,7 @@
switch (method.getVisibility()) {
case IMethod.PRIVATE:
flags |= Flags.AccPrivate;
+ if (!fOriginalType.getElementName().equals(typeName)) return null; // FIXME We should do a comparison of types, not names
if (fContext.hasReceiver()) return null; // can't invoke a private method on a receiver
break;
case IMethod.PUBLIC:
@@ -475,7 +482,7 @@
// FIXME Try to stop all the multiple re-parsing of the source! Can
// we parse once and pass the root node around?
// Parse
- Node rootNode = ((RubyScript) fContext.getScript()).lastGoodAST;
+ Node rootNode = fContext.getRootNode();
if (rootNode == null) {
return;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-09 12:47:23
|
Revision: 2728
http://svn.sourceforge.net/rubyeclipse/?rev=2728&view=rev
Author: cawilliams
Date: 2007-07-09 05:47:18 -0700 (Mon, 09 Jul 2007)
Log Message:
-----------
fix #5114 - catch RuntimeExceptions when trying to resolve file.
Modified Paths:
--------------
trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java
Modified: trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java
===================================================================
--- trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java 2007-07-07 01:04:48 UTC (rev 2727)
+++ trunk/org.rubypeople.rdt.debug.ui/src/org/rubypeople/rdt/internal/debug/ui/RubySourceLocator.java 2007-07-09 12:47:18 UTC (rev 2728)
@@ -106,7 +106,11 @@
filename = aFilename;
workspaceFile = RdtDebugCorePlugin.getWorkspace().getRoot().getFileForLocation(new Path(filename));
if (workspaceFile == null) {
- workspaceFile = RdtDebugCorePlugin.getWorkspace().getRoot().getFile(new Path(filename));
+ try {
+ workspaceFile = RdtDebugCorePlugin.getWorkspace().getRoot().getFile(new Path(filename));
+ } catch (RuntimeException e) {
+ workspaceFile = null;
+ }
if (workspaceFile != null && !workspaceFile.exists()) {
workspaceFile = null;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-07 01:04:52
|
Revision: 2727
http://svn.sourceforge.net/rubyeclipse/?rev=2727&view=rev
Author: cawilliams
Date: 2007-07-06 18:04:48 -0700 (Fri, 06 Jul 2007)
Log Message:
-----------
also add open structure command (not sure how it differs from quick outline)
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/plugin.xml
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java
Modified: trunk/org.rubypeople.rdt.ui/plugin.xml
===================================================================
--- trunk/org.rubypeople.rdt.ui/plugin.xml 2007-07-07 00:59:07 UTC (rev 2726)
+++ trunk/org.rubypeople.rdt.ui/plugin.xml 2007-07-07 01:04:48 UTC (rev 2727)
@@ -461,7 +461,7 @@
sequence="M1+SPACE">
</key>
<key
- commandId="org.rubypeople.rdt.ui.edit.text.ruby.content.assist.proposals "
+ commandId="org.rubypeople.rdt.ui.edit.text.ruby.content.assist.proposals"
contextId="org.rubypeople.rdt.ui.rubyEditorScope"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="CTRL+SPACE"
@@ -470,7 +470,7 @@
<key
sequence="M1+M2+P"
contextId="org.rubypeople.rdt.ui.rubyEditorScope"
- commandId="org.rubypeople.rdt.ui.edit.text.ruby.goto.matching.bracket "
+ commandId="org.rubypeople.rdt.ui.edit.text.ruby.goto.matching.bracket"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
<key
sequence="F3"
@@ -487,6 +487,11 @@
contextId="org.rubypeople.rdt.ui.rubyEditorScope"
commandId="org.rubypeople.rdt.ui.edit.text.ruby.show.outline"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
+ <key
+ sequence="M1+F3"
+ contextId="org.rubypeople.rdt.ui.rubyEditorScope"
+ commandId="org.rubypeople.rdt.ui.navigate.ruby.open.structure"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
</extension>
<extension point="org.eclipse.ui.commands">
<category
@@ -583,6 +588,12 @@
id="org.rubypeople.rdt.ui.edit.text.ruby.show.outline">
</command>
<command
+ name="%ActionDefinition.open.structure.name"
+ description="%ActionDefinition.open.structure.description"
+ categoryId="org.eclipse.ui.category.navigate"
+ id="org.rubypeople.rdt.ui.navigate.ruby.open.structure">
+ </command>
+ <command
name="%ActionDefinition.toggleComment.name"
description="%ActionDefinition.toggleComment.description"
categoryId="org.rubypeople.rdt.ui.category.source"
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java 2007-07-07 00:59:07 UTC (rev 2726)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java 2007-07-07 01:04:48 UTC (rev 2727)
@@ -257,6 +257,11 @@
action.setActionDefinitionId(IRubyEditorActionDefinitionIds.SHOW_OUTLINE);
setAction(IRubyEditorActionDefinitionIds.SHOW_OUTLINE, action);
PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IRubyHelpContextIds.SHOW_OUTLINE_ACTION);
+
+ action= new TextOperationAction(RubyEditorMessages.getBundleForConstructedKeys(),"OpenStructure.", this, RubySourceViewer.OPEN_STRUCTURE, true); //$NON-NLS-1$
+ action.setActionDefinitionId(IRubyEditorActionDefinitionIds.OPEN_STRUCTURE);
+ setAction(IRubyEditorActionDefinitionIds.OPEN_STRUCTURE, action);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IRubyHelpContextIds.OPEN_STRUCTURE_ACTION);
action = new FormatAction(RubyPlugin.getDefault().getPluginProperties(), "FormatAction.", this);
action.setActionDefinitionId(IRubyEditorActionDefinitionIds.FORMAT);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-07 00:59:17
|
Revision: 2726
http://svn.sourceforge.net/rubyeclipse/?rev=2726&view=rev
Author: cawilliams
Date: 2007-07-06 17:59:07 -0700 (Fri, 06 Jul 2007)
Log Message:
-----------
First cut at Quick Outline
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/plugin.xml
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/RubyUIMessages.properties
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditorActionContributor.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubySourceViewer.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/text/RubySourceViewerConfiguration.java
Added Paths:
-----------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyOutlineInformationControl.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/TextMessages.properties
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/OverrideIndicatorLabelDecorator.java
Modified: trunk/org.rubypeople.rdt.ui/plugin.xml
===================================================================
--- trunk/org.rubypeople.rdt.ui/plugin.xml 2007-07-07 00:29:33 UTC (rev 2725)
+++ trunk/org.rubypeople.rdt.ui/plugin.xml 2007-07-07 00:59:07 UTC (rev 2726)
@@ -482,6 +482,11 @@
contextId="org.rubypeople.rdt.ui.rubyEditorScope"
commandId="org.rubypeople.rdt.ui.edit.text.ruby.open.type"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
+ <key
+ sequence="M1+O"
+ contextId="org.rubypeople.rdt.ui.rubyEditorScope"
+ commandId="org.rubypeople.rdt.ui.edit.text.ruby.show.outline"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
</extension>
<extension point="org.eclipse.ui.commands">
<category
@@ -571,6 +576,12 @@
id="org.rubypeople.rdt.ui.edit.text.ruby.open.type"
name="%OpenTypeAction.label">
</command>
+ <command
+ name="%ActionDefinition.show.outline.name"
+ description="%ActionDefinition.show.outline.description"
+ categoryId="org.eclipse.ui.category.navigate"
+ id="org.rubypeople.rdt.ui.edit.text.ruby.show.outline">
+ </command>
<command
name="%ActionDefinition.toggleComment.name"
description="%ActionDefinition.toggleComment.description"
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/RubyUIMessages.properties
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/RubyUIMessages.properties 2007-07-07 00:29:33 UTC (rev 2725)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/RubyUIMessages.properties 2007-07-07 00:59:07 UTC (rev 2726)
@@ -130,6 +130,9 @@
HTMLTextPresenter_ellipsis=...
HTML2TextReader_listItemPrefix=\t-
+RubyOutlineControl_statusFieldText_hideInheritedMembers= Press ''{0}'' to hide inherited members
+RubyOutlineControl_statusFieldText_showInheritedMembers= Press ''{0}'' to show inherited members
+
RDocPathErrorTitle=RDoc path error
RDocPathError=The input path for RDoc is blank or incorrect. Use preferences to enter a valid RDoc path.
ErrorRunningRdocTitle=Error running RDoc
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java 2007-07-07 00:29:33 UTC (rev 2725)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditor.java 2007-07-07 00:59:07 UTC (rev 2726)
@@ -92,6 +92,7 @@
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.SelectionEnabler;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.actions.ActionGroup;
@@ -251,6 +252,11 @@
action= new GotoMatchingBracketAction(this);
action.setActionDefinitionId(IRubyEditorActionDefinitionIds.GOTO_MATCHING_BRACKET);
setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action);
+
+ action= new TextOperationAction(RubyEditorMessages.getBundleForConstructedKeys(),"ShowOutline.", this, RubySourceViewer.SHOW_OUTLINE, true); //$NON-NLS-1$
+ action.setActionDefinitionId(IRubyEditorActionDefinitionIds.SHOW_OUTLINE);
+ setAction(IRubyEditorActionDefinitionIds.SHOW_OUTLINE, action);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IRubyHelpContextIds.SHOW_OUTLINE_ACTION);
action = new FormatAction(RubyPlugin.getDefault().getPluginProperties(), "FormatAction.", this);
action.setActionDefinitionId(IRubyEditorActionDefinitionIds.FORMAT);
@@ -272,7 +278,7 @@
resAction= new InformationDispatchAction(RubyEditorMessages.getBundleForConstructedKeys(), "ShowRDoc.", (TextOperationAction) resAction); //$NON-NLS-1$
resAction.setActionDefinitionId(IRubyEditorActionDefinitionIds.SHOW_RDOC);
setAction("ShowRDoc", resAction); //$NON-NLS-1$
-// PlatformUI.getWorkbench().getHelpSystem().setHelp(resAction, IRubyHelpContextIds.SHOW_JAVADOC_ACTION);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(resAction, IRubyHelpContextIds.SHOW_JAVADOC_ACTION);
SurroundWithBeginRescueAction beginRescueAction = new SurroundWithBeginRescueAction(this);
beginRescueAction.setActionDefinitionId(IRubyEditorActionDefinitionIds.SURROUND_WITH_BEGIN_RESCUE);
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditorActionContributor.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditorActionContributor.java 2007-07-07 00:29:33 UTC (rev 2725)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubyEditorActionContributor.java 2007-07-07 00:59:07 UTC (rev 2726)
@@ -31,6 +31,7 @@
protected RetargetTextEditorAction contentAssistProposal;
private RetargetTextEditorAction fGotoMatchingBracket;
+ private RetargetTextEditorAction fShowOutline;
private RetargetTextEditorAction fQuickAssistAction;
private RetargetAction fRetargetShowRubyDoc;
@@ -44,6 +45,9 @@
fRetargetShowRubyDoc.setActionDefinitionId(IRubyEditorActionDefinitionIds.SHOW_RDOC);
markAsPartListener(fRetargetShowRubyDoc);
+ fShowOutline= new RetargetTextEditorAction(RubyEditorMessages.getBundleForConstructedKeys(), "ShowOutline."); //$NON-NLS-1$
+ fShowOutline.setActionDefinitionId(IRubyEditorActionDefinitionIds.SHOW_OUTLINE);
+
contentAssistProposal = new RetargetTextEditorAction(RubyUIMessages.getResourceBundle(),
"ContentAssistProposal.");
fGotoMatchingBracket = new RetargetTextEditorAction(b, "GotoMatchingBracket."); //$NON-NLS-1$
@@ -61,15 +65,20 @@
fPartListeners.add(action);
}
- public void contributeToMenu(IMenuManager menuManager) {
- IMenuManager editMenu = menuManager.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT);
+ public void contributeToMenu(IMenuManager menu) {
+ IMenuManager editMenu = menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT);
if (editMenu != null) {
editMenu.add(new Separator());
editMenu.add(contentAssistProposal);
editMenu.add(fQuickAssistAction);
}
- IMenuManager gotoMenu= menuManager.findMenuUsingPath("navigate/goTo"); //$NON-NLS-1$
+ IMenuManager navigateMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_NAVIGATE);
+ if (navigateMenu != null) {
+ navigateMenu.appendToGroup(IWorkbenchActionConstants.SHOW_EXT, fShowOutline);
+ }
+
+ IMenuManager gotoMenu= menu.findMenuUsingPath("navigate/goTo"); //$NON-NLS-1$
if (gotoMenu != null) {
gotoMenu.add(new Separator("additions2")); //$NON-NLS-1$
gotoMenu.appendToGroup("additions2", fGotoMatchingBracket); //$NON-NLS-1$
@@ -88,7 +97,8 @@
fGotoMatchingBracket.setAction(getAction(textEditor,
GotoMatchingBracketAction.GOTO_MATCHING_BRACKET));
fQuickAssistAction.setAction(getAction(textEditor, ITextEditorActionConstants.QUICK_ASSIST));
-
+ fShowOutline.setAction(getAction(textEditor, IRubyEditorActionDefinitionIds.SHOW_OUTLINE));
+ fShowRubyDoc.setAction(getAction(textEditor, "ShowRDoc")); //$NON-NLS-1$
if (part instanceof RubyEditor) {
RubyEditor javaEditor= (RubyEditor) part;
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubySourceViewer.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubySourceViewer.java 2007-07-07 00:29:33 UTC (rev 2725)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/rubyeditor/RubySourceViewer.java 2007-07-07 00:59:07 UTC (rev 2726)
@@ -21,6 +21,7 @@
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IPositionUpdater;
+import org.eclipse.jface.text.information.IInformationPresenter;
import org.eclipse.jface.text.link.ILinkedModeListener;
import org.eclipse.jface.text.link.InclusivePositionUpdater;
import org.eclipse.jface.text.link.LinkedModeModel;
@@ -42,14 +43,33 @@
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
import org.eclipse.ui.texteditor.AbstractTextEditor;
+import org.rubypeople.rdt.ui.text.RubySourceViewerConfiguration;
public class RubySourceViewer extends ProjectionViewer implements IPropertyChangeListener {
+ /**
+ * Text operation code for requesting the outline for the current input.
+ */
+ public static final int SHOW_OUTLINE= 51;
+
+ /**
+ * Text operation code for requesting the outline for the element at the current position.
+ */
+ public static final int OPEN_STRUCTURE= 52;
+
+ /**
+ * Text operation code for requesting the hierarchy for the current input.
+ */
+ public static final int SHOW_HIERARCHY= 53;
+
private boolean fIgnoreTextConverters = false;
/** The linked position list for code auto edit */
protected final LinkedList fPositionList = new LinkedList();
+ private IInformationPresenter fOutlinePresenter;
+ private IInformationPresenter fStructurePresenter;
+
/**
* This viewer's foreground color.
* @since 0.8.0
@@ -190,7 +210,22 @@
}
super.configure(configuration);
+ if (configuration instanceof RubySourceViewerConfiguration) {
+ RubySourceViewerConfiguration javaSVCconfiguration= (RubySourceViewerConfiguration)configuration;
+ fOutlinePresenter= javaSVCconfiguration.getOutlinePresenter(this, false);
+ if (fOutlinePresenter != null)
+ fOutlinePresenter.install(this);
+ fStructurePresenter= javaSVCconfiguration.getOutlinePresenter(this, true);
+ if (fStructurePresenter != null)
+ fStructurePresenter.install(this);
+
+// fHierarchyPresenter= javaSVCconfiguration.getHierarchyPresenter(this, true);
+// if (fHierarchyPresenter != null)
+// fHierarchyPresenter.install(this);
+
+ }
+
if (fPreferenceStore != null) {
fPreferenceStore.addPropertyChangeListener(this);
initializeViewerColors();
@@ -204,21 +239,33 @@
* @since 0.8.0
*/
public void unconfigure() {
- if (fForegroundColor != null) {
- fForegroundColor.dispose();
- fForegroundColor= null;
- }
- if (fBackgroundColor != null) {
- fBackgroundColor.dispose();
- fBackgroundColor= null;
- }
+ if (fOutlinePresenter != null) {
+ fOutlinePresenter.uninstall();
+ fOutlinePresenter= null;
+ }
+ if (fStructurePresenter != null) {
+ fStructurePresenter.uninstall();
+ fStructurePresenter= null;
+ }
+// if (fHierarchyPresenter != null) {
+// fHierarchyPresenter.uninstall();
+// fHierarchyPresenter= null;
+// }
+ if (fForegroundColor != null) {
+ fForegroundColor.dispose();
+ fForegroundColor= null;
+ }
+ if (fBackgroundColor != null) {
+ fBackgroundColor.dispose();
+ fBackgroundColor= null;
+ }
- if (fPreferenceStore != null)
- fPreferenceStore.removePropertyChangeListener(this);
+ if (fPreferenceStore != null)
+ fPreferenceStore.removePropertyChangeListener(this);
- super.unconfigure();
+ super.unconfigure();
- fIsConfigured= false;
+ fIsConfigured= false;
}
/*
@@ -266,10 +313,41 @@
return null;
}
+
+ /*
+ * @see ITextOperationTarget#canDoOperation(int)
+ */
+ public boolean canDoOperation(int operation) {
+ if (operation == SHOW_OUTLINE)
+ return fOutlinePresenter != null;
+ if (operation == OPEN_STRUCTURE)
+ return fStructurePresenter != null;
+// if (operation == SHOW_HIERARCHY)
+// return fHierarchyPresenter != null;
+ return super.canDoOperation(operation);
+ }
+
public void doOperation(int operation) {
- if (getTextWidget() == null || !redraws()) { return; }
- super.doOperation(operation);
+ if (getTextWidget() == null)
+ return;
+
+ switch (operation) {
+ case SHOW_OUTLINE:
+ if (fOutlinePresenter != null)
+ fOutlinePresenter.showInformation();
+ return;
+ case OPEN_STRUCTURE:
+ if (fStructurePresenter != null)
+ fStructurePresenter.showInformation();
+ return;
+// case SHOW_HIERARCHY:
+// if (fHierarchyPresenter != null)
+// fHierarchyPresenter.showInformation();
+// return;
+ }
+
+ super.doOperation(operation);
}
/*
Added: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyOutlineInformationControl.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyOutlineInformationControl.java (rev 0)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyOutlineInformationControl.java 2007-07-07 00:59:07 UTC (rev 2726)
@@ -0,0 +1,713 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.rubypeople.rdt.internal.ui.text;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.IDecoratorManager;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.keys.KeySequence;
+import org.eclipse.ui.keys.SWTKeySupport;
+import org.rubypeople.rdt.core.IMember;
+import org.rubypeople.rdt.core.IMethod;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.IRubyScript;
+import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.ITypeHierarchy;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.internal.corext.util.Messages;
+import org.rubypeople.rdt.internal.corext.util.MethodOverrideTester;
+import org.rubypeople.rdt.internal.corext.util.SuperTypeHierarchyCache;
+import org.rubypeople.rdt.internal.ui.IRubyHelpContextIds;
+import org.rubypeople.rdt.internal.ui.RubyPlugin;
+import org.rubypeople.rdt.internal.ui.RubyPluginImages;
+import org.rubypeople.rdt.internal.ui.RubyUIMessages;
+import org.rubypeople.rdt.internal.ui.typehierarchy.AbstractHierarchyViewerSorter;
+import org.rubypeople.rdt.internal.ui.util.StringMatcher;
+import org.rubypeople.rdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
+import org.rubypeople.rdt.internal.ui.viewsupport.MemberFilter;
+import org.rubypeople.rdt.ui.OverrideIndicatorLabelDecorator;
+import org.rubypeople.rdt.ui.ProblemsLabelDecorator;
+import org.rubypeople.rdt.ui.RubyElementLabels;
+import org.rubypeople.rdt.ui.StandardRubyElementContentProvider;
+
+/**
+ * Show outline in light-weight control.
+ *
+ * @since 2.1
+ */
+public class RubyOutlineInformationControl extends AbstractInformationControl {
+
+ private KeyAdapter fKeyAdapter;
+ private OutlineContentProvider fOutlineContentProvider;
+ private IRubyElement fInput= null;
+
+ private OutlineSorter fOutlineSorter;
+
+ private OutlineLabelProvider fInnerLabelProvider;
+ protected Color fForegroundColor;
+
+ private boolean fShowOnlyMainType;
+ private LexicalSortingAction fLexicalSortingAction;
+ private SortByDefiningTypeAction fSortByDefiningTypeAction;
+ private ShowOnlyMainTypeAction fShowOnlyMainTypeAction;
+ private Map fTypeHierarchies= new HashMap();
+
+ private String fPattern;
+
+ private class OutlineLabelProvider extends AppearanceAwareLabelProvider {
+
+ private boolean fShowDefiningType;
+
+ private OutlineLabelProvider() {
+ super(AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS, AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS);
+ }
+
+ /*
+ * @see ILabelProvider#getText
+ */
+ public String getText(Object element) {
+ String text= super.getText(element);
+ if (fShowDefiningType) {
+ try {
+ IType type= getDefiningType(element);
+ if (type != null) {
+ StringBuffer buf= new StringBuffer(super.getText(type));
+ buf.append(RubyElementLabels.CONCAT_STRING);
+ buf.append(text);
+ return buf.toString();
+ }
+ } catch (RubyModelException e) {
+ }
+ }
+ return text;
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.viewsupport.RubyUILabelProvider#getForeground(java.lang.Object)
+ */
+ public Color getForeground(Object element) {
+ if (fOutlineContentProvider.isShowingInheritedMembers()) {
+ if (element instanceof IRubyElement) {
+ IRubyElement je= (IRubyElement)element;
+ je= je.getAncestor(IRubyElement.SCRIPT);
+ if (fInput.equals(je)) {
+ return null;
+ }
+ }
+ return fForegroundColor;
+ }
+ return null;
+ }
+
+ public void setShowDefiningType(boolean showDefiningType) {
+ fShowDefiningType= showDefiningType;
+ }
+
+ public boolean isShowDefiningType() {
+ return fShowDefiningType;
+ }
+
+ private IType getDefiningType(Object element) throws RubyModelException {
+ int kind= ((IRubyElement) element).getElementType();
+
+ if (kind != IRubyElement.METHOD && kind != IRubyElement.FIELD) {
+ return null;
+ }
+ IType declaringType= ((IMember) element).getDeclaringType();
+ if (kind != IRubyElement.METHOD) {
+ return declaringType;
+ }
+ ITypeHierarchy hierarchy= getSuperTypeHierarchy(declaringType);
+ if (hierarchy == null) {
+ return declaringType;
+ }
+ IMethod method= (IMethod) element;
+ MethodOverrideTester tester= new MethodOverrideTester(declaringType, hierarchy);
+ IMethod res= tester.findDeclaringMethod(method, true);
+ if (res == null || method.equals(res)) {
+ return declaringType;
+ }
+ return res.getDeclaringType();
+ }
+ }
+
+
+ private class OutlineTreeViewer extends TreeViewer {
+
+ private boolean fIsFiltering= false;
+
+ private OutlineTreeViewer(Tree tree) {
+ super(tree);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected Object[] getFilteredChildren(Object parent) {
+ Object[] result = getRawChildren(parent);
+ int unfilteredChildren= result.length;
+ ViewerFilter[] filters = getFilters();
+ if (filters != null) {
+ for (int i= 0; i < filters.length; i++)
+ result = filters[i].filter(this, parent, result);
+ }
+ fIsFiltering= unfilteredChildren != result.length;
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void internalExpandToLevel(Widget node, int level) {
+ if (!fIsFiltering && node instanceof Item) {
+ Item i= (Item) node;
+ if (i.getData() instanceof IRubyElement) {
+ IRubyElement je= (IRubyElement) i.getData();
+ if (je.getElementType() == IRubyElement.IMPORT_CONTAINER || isInnerType(je)) {
+ setExpanded(i, false);
+ return;
+ }
+ }
+ }
+ super.internalExpandToLevel(node, level);
+ }
+
+ private boolean isInnerType(IRubyElement element) {
+ if (element != null && element.getElementType() == IRubyElement.TYPE) {
+ IType type= (IType)element;
+ try {
+ return type.isMember();
+ } catch (RubyModelException e) {
+ IRubyElement parent= type.getParent();
+ if (parent != null) {
+ int parentElementType= parent.getElementType();
+ return (parentElementType != IRubyElement.SCRIPT);
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+
+ private class OutlineContentProvider extends StandardRubyElementContentProvider {
+
+ private boolean fShowInheritedMembers;
+
+ /**
+ * Creates a new Outline content provider.
+ *
+ * @param showInheritedMembers <code>true</code> iff inherited members are shown
+ */
+ private OutlineContentProvider(boolean showInheritedMembers) {
+ super(true);
+ fShowInheritedMembers= showInheritedMembers;
+ }
+
+ public boolean isShowingInheritedMembers() {
+ return fShowInheritedMembers;
+ }
+
+ public void toggleShowInheritedMembers() {
+ Tree tree= getTreeViewer().getTree();
+
+ tree.setRedraw(false);
+ fShowInheritedMembers= !fShowInheritedMembers;
+ getTreeViewer().refresh();
+ getTreeViewer().expandToLevel(2);
+
+ // reveal selection
+ Object selectedElement= getSelectedElement();
+ if (selectedElement != null)
+ getTreeViewer().reveal(selectedElement);
+
+ tree.setRedraw(true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object[] getChildren(Object element) {
+ if (fShowOnlyMainType) {
+ if (element instanceof IRubyScript) {
+ element= getMainType((IRubyScript)element);
+ }
+
+ if (element == null)
+ return NO_CHILDREN;
+ }
+
+ if (fShowInheritedMembers && element instanceof IType) {
+ IType type= (IType)element;
+ if (type.getDeclaringType() == null) {
+ ITypeHierarchy th= getSuperTypeHierarchy(type);
+ if (th != null) {
+ List children= new ArrayList();
+ IType[] superClasses= th.getAllSupertypes(type);
+ children.addAll(Arrays.asList(super.getChildren(type)));
+ for (int i= 0, scLength= superClasses.length; i < scLength; i++)
+ children.addAll(Arrays.asList(super.getChildren(superClasses[i])));
+ return children.toArray();
+ }
+ }
+ }
+ return super.getChildren(element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ super.inputChanged(viewer, oldInput, newInput);
+ fTypeHierarchies.clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void dispose() {
+ super.dispose();
+ fTypeHierarchies.clear();
+ }
+ }
+
+
+ private class ShowOnlyMainTypeAction extends Action {
+
+ private static final String STORE_GO_INTO_TOP_LEVEL_TYPE_CHECKED= "GoIntoTopLevelTypeAction.isChecked"; //$NON-NLS-1$
+
+ private TreeViewer fOutlineViewer;
+
+ private ShowOnlyMainTypeAction(TreeViewer outlineViewer) {
+ super(TextMessages.RubyOutlineInformationControl_GoIntoTopLevelType_label, IAction.AS_CHECK_BOX);
+ setToolTipText(TextMessages.RubyOutlineInformationControl_GoIntoTopLevelType_tooltip);
+ setDescription(TextMessages.RubyOutlineInformationControl_GoIntoTopLevelType_description);
+
+ RubyPluginImages.setLocalImageDescriptors(this, "gointo_toplevel_type.gif"); //$NON-NLS-1$
+
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IRubyHelpContextIds.GO_INTO_TOP_LEVEL_TYPE_ACTION);
+
+ fOutlineViewer= outlineViewer;
+
+ boolean showclass= getDialogSettings().getBoolean(STORE_GO_INTO_TOP_LEVEL_TYPE_CHECKED);
+ setTopLevelTypeOnly(showclass);
+ }
+
+ /*
+ * @see org.eclipse.jface.action.Action#run()
+ */
+ public void run() {
+ setTopLevelTypeOnly(!fShowOnlyMainType);
+ }
+
+ private void setTopLevelTypeOnly(boolean show) {
+ fShowOnlyMainType= show;
+ setChecked(show);
+
+ Tree tree= fOutlineViewer.getTree();
+ tree.setRedraw(false);
+
+ fOutlineViewer.refresh(false);
+ if (!fShowOnlyMainType)
+ fOutlineViewer.expandToLevel(2);
+
+
+ // reveal selection
+ Object selectedElement= getSelectedElement();
+ if (selectedElement != null)
+ fOutlineViewer.reveal(selectedElement);
+
+ tree.setRedraw(true);
+
+ getDialogSettings().put(STORE_GO_INTO_TOP_LEVEL_TYPE_CHECKED, show);
+ }
+ }
+
+ private class OutlineSorter extends AbstractHierarchyViewerSorter {
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.typehierarchy.AbstractHierarchyViewerSorter#getHierarchy(org.eclipse.jdt.core.IType)
+ * @since 3.2
+ */
+ protected ITypeHierarchy getHierarchy(IType type) {
+ return getSuperTypeHierarchy(type);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.typehierarchy.AbstractHierarchyViewerSorter#isSortByDefiningType()
+ * @since 3.2
+ */
+ public boolean isSortByDefiningType() {
+ return fSortByDefiningTypeAction.isChecked();
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.typehierarchy.AbstractHierarchyViewerSorter#isSortAlphabetically()
+ * @since 3.2
+ */
+ public boolean isSortAlphabetically() {
+ return fLexicalSortingAction.isChecked();
+ }
+ }
+
+
+ private class LexicalSortingAction extends Action {
+
+ private static final String STORE_LEXICAL_SORTING_CHECKED= "LexicalSortingAction.isChecked"; //$NON-NLS-1$
+
+ private TreeViewer fOutlineViewer;
+
+ private LexicalSortingAction(TreeViewer outlineViewer) {
+ super(TextMessages.RubyOutlineInformationControl_LexicalSortingAction_label, IAction.AS_CHECK_BOX);
+ setToolTipText(TextMessages.RubyOutlineInformationControl_LexicalSortingAction_tooltip);
+ setDescription(TextMessages.RubyOutlineInformationControl_LexicalSortingAction_description);
+
+ RubyPluginImages.setLocalImageDescriptors(this, "alphab_sort_co.gif"); //$NON-NLS-1$
+
+ fOutlineViewer= outlineViewer;
+
+ boolean checked=getDialogSettings().getBoolean(STORE_LEXICAL_SORTING_CHECKED);
+ setChecked(checked);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IRubyHelpContextIds.LEXICAL_SORTING_BROWSING_ACTION);
+ }
+
+ public void run() {
+ valueChanged(isChecked(), true);
+ }
+
+ private void valueChanged(final boolean on, boolean store) {
+ setChecked(on);
+ BusyIndicator.showWhile(fOutlineViewer.getControl().getDisplay(), new Runnable() {
+ public void run() {
+ fOutlineViewer.refresh(false);
+ }
+ });
+
+ if (store)
+ getDialogSettings().put(STORE_LEXICAL_SORTING_CHECKED, on);
+ }
+ }
+
+
+ private class SortByDefiningTypeAction extends Action {
+
+ private static final String STORE_SORT_BY_DEFINING_TYPE_CHECKED= "SortByDefiningType.isChecked"; //$NON-NLS-1$
+
+ private TreeViewer fOutlineViewer;
+
+ /**
+ * Creates the action.
+ *
+ * @param outlineViewer the outline viewer
+ */
+ private SortByDefiningTypeAction(TreeViewer outlineViewer) {
+ super(TextMessages.RubyOutlineInformationControl_SortByDefiningTypeAction_label);
+ setDescription(TextMessages.RubyOutlineInformationControl_SortByDefiningTypeAction_description);
+ setToolTipText(TextMessages.RubyOutlineInformationControl_SortByDefiningTypeAction_tooltip);
+
+ RubyPluginImages.setLocalImageDescriptors(this, "definingtype_sort_co.gif"); //$NON-NLS-1$
+
+ fOutlineViewer= outlineViewer;
+
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IRubyHelpContextIds.SORT_BY_DEFINING_TYPE_ACTION);
+
+ boolean state= getDialogSettings().getBoolean(STORE_SORT_BY_DEFINING_TYPE_CHECKED);
+ setChecked(state);
+ fInnerLabelProvider.setShowDefiningType(state);
+ }
+
+ /*
+ * @see Action#actionPerformed
+ */
+ public void run() {
+ BusyIndicator.showWhile(fOutlineViewer.getControl().getDisplay(), new Runnable() {
+ public void run() {
+ fInnerLabelProvider.setShowDefiningType(isChecked());
+ getDialogSettings().put(STORE_SORT_BY_DEFINING_TYPE_CHECKED, isChecked());
+
+ setMatcherString(fPattern, false);
+ fOutlineViewer.refresh(true);
+
+ // reveal selection
+ Object selectedElement= getSelectedElement();
+ if (selectedElement != null)
+ fOutlineViewer.reveal(selectedElement);
+ }
+ });
+ }
+ }
+
+ /**
+ * String matcher that can match two patterns.
+ *
+ * @since 3.2
+ */
+ private static class OrStringMatcher extends StringMatcher {
+
+ private StringMatcher fMatcher1;
+ private StringMatcher fMatcher2;
+
+ private OrStringMatcher(String pattern1, String pattern2, boolean ignoreCase, boolean foo) {
+ super("", false, false); //$NON-NLS-1$
+ fMatcher1= new StringMatcher(pattern1, ignoreCase, false);
+ fMatcher2= new StringMatcher(pattern2, ignoreCase, false);
+ }
+
+ public boolean match(String text) {
+ return fMatcher2.match(text) || fMatcher1.match(text);
+ }
+
+ }
+
+
+ /**
+ * Creates a new Ruby outline information control.
+ *
+ * @param parent
+ * @param shellStyle
+ * @param treeStyle
+ * @param commandId
+ */
+ public RubyOutlineInformationControl(Shell parent, int shellStyle, int treeStyle, String commandId) {
+ super(parent, shellStyle, treeStyle, commandId, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected Text createFilterText(Composite parent) {
+ Text text= super.createFilterText(parent);
+ text.addKeyListener(getKeyAdapter());
+ return text;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected TreeViewer createTreeViewer(Composite parent, int style) {
+ Tree tree= new Tree(parent, SWT.SINGLE | (style & ~SWT.MULTI));
+ GridData gd= new GridData(GridData.FILL_BOTH);
+ gd.heightHint= tree.getItemHeight() * 12;
+ tree.setLayoutData(gd);
+
+ final TreeViewer treeViewer= new OutlineTreeViewer(tree);
+
+ // Hard-coded filters
+ treeViewer.addFilter(new NamePatternFilter());
+ treeViewer.addFilter(new MemberFilter());
+
+ fForegroundColor= parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
+
+ fInnerLabelProvider= new OutlineLabelProvider();
+ fInnerLabelProvider.addLabelDecorator(new ProblemsLabelDecorator(null));
+ IDecoratorManager decoratorMgr= PlatformUI.getWorkbench().getDecoratorManager();
+ if (decoratorMgr.getEnabled("org.rubypeople.rdt.ui.override.decorator")) //$NON-NLS-1$
+ fInnerLabelProvider.addLabelDecorator(new OverrideIndicatorLabelDecorator(null));
+
+ treeViewer.setLabelProvider(fInnerLabelProvider);
+
+ fLexicalSortingAction= new LexicalSortingAction(treeViewer);
+ fSortByDefiningTypeAction= new SortByDefiningTypeAction(treeViewer);
+ fShowOnlyMainTypeAction= new ShowOnlyMainTypeAction(treeViewer);
+
+ fOutlineContentProvider= new OutlineContentProvider(false);
+ treeViewer.setContentProvider(fOutlineContentProvider);
+ fOutlineSorter= new OutlineSorter();
+ treeViewer.setSorter(fOutlineSorter);
+ treeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
+
+
+ treeViewer.getTree().addKeyListener(getKeyAdapter());
+
+ return treeViewer;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected String getStatusFieldText() {
+ KeySequence[] sequences= getInvokingCommandKeySequences();
+ if (sequences == null || sequences.length == 0)
+ return ""; //$NON-NLS-1$
+
+ String keySequence= sequences[0].format();
+
+ if (fOutlineContentProvider.isShowingInheritedMembers())
+ return Messages.format(RubyUIMessages.RubyOutlineControl_statusFieldText_hideInheritedMembers, keySequence);
+ else
+ return Messages.format(RubyUIMessages.RubyOutlineControl_statusFieldText_showInheritedMembers, keySequence);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.AbstractInformationControl#getId()
+ * @since 3.0
+ */
+ protected String getId() {
+ return "org.eclipse.jdt.internal.ui.text.QuickOutline"; //$NON-NLS-1$
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setInput(Object information) {
+ if (information == null || information instanceof String) {
+ inputChanged(null, null);
+ return;
+ }
+ IRubyElement je= (IRubyElement)information;
+ IRubyScript cu= (IRubyScript)je.getAncestor(IRubyElement.SCRIPT);
+ if (cu != null)
+ fInput= cu;
+
+ inputChanged(fInput, information);
+ }
+
+ private KeyAdapter getKeyAdapter() {
+ if (fKeyAdapter == null) {
+ fKeyAdapter= new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(e);
+ KeySequence keySequence = KeySequence.getInstance(SWTKeySupport.convertAcceleratorToKeyStroke(accelerator));
+ KeySequence[] sequences= getInvokingCommandKeySequences();
+ if (sequences == null)
+ return;
+ for (int i= 0; i < sequences.length; i++) {
+ if (sequences[i].equals(keySequence)) {
+ e.doit= false;
+ toggleShowInheritedMembers();
+ return;
+ }
+ }
+ }
+ };
+ }
+ return fKeyAdapter;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void handleStatusFieldClicked() {
+ toggleShowInheritedMembers();
+ }
+
+ protected void toggleShowInheritedMembers() {
+ long flags= fInnerLabelProvider.getTextFlags();
+ flags ^= RubyElementLabels.ALL_POST_QUALIFIED;
+ fInnerLabelProvider.setTextFlags(flags);
+ fOutlineContentProvider.toggleShowInheritedMembers();
+ updateStatusFieldText();
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.AbstractInformationControl#fillViewMenu(org.eclipse.jface.action.IMenuManager)
+ */
+ protected void fillViewMenu(IMenuManager viewMenu) {
+ super.fillViewMenu(viewMenu);
+ viewMenu.add(fShowOnlyMainTypeAction);
+
+ viewMenu.add(new Separator("Sorters")); //$NON-NLS-1$
+ viewMenu.add(fLexicalSortingAction);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.AbstractInformationControl#setMatcherString(java.lang.String, boolean)
+ * @since 3.2
+ */
+ protected void setMatcherString(String pattern, boolean update) {
+ fPattern= pattern;
+ if (pattern.length() == 0 || !fSortByDefiningTypeAction.isChecked()) {
+ super.setMatcherString(pattern, update);
+ return;
+ }
+
+ boolean ignoreCase= pattern.toLowerCase().equals(pattern);
+ String pattern2= "*" + RubyElementLabels.CONCAT_STRING + pattern; //$NON-NLS-1$
+ fStringMatcher= new OrStringMatcher(pattern, pattern2, ignoreCase, false);
+
+ if (update)
+ stringMatcherUpdated();
+
+ }
+
+ private ITypeHierarchy getSuperTypeHierarchy(IType type) {
+ ITypeHierarchy th= (ITypeHierarchy)fTypeHierarchies.get(type);
+ if (th == null) {
+ try {
+ th= SuperTypeHierarchyCache.getTypeHierarchy(type, getProgressMonitor());
+ } catch (RubyModelException e) {
+ return null;
+ } catch (OperationCanceledException e) {
+ return null;
+ }
+ fTypeHierarchies.put(type, th);
+ }
+ return th;
+ }
+
+ private IProgressMonitor getProgressMonitor() {
+ IWorkbenchPage wbPage= RubyPlugin.getActivePage();
+ if (wbPage == null)
+ return null;
+
+ IEditorPart editor= wbPage.getActiveEditor();
+ if (editor == null)
+ return null;
+
+ return editor.getEditorSite().getActionBars().getStatusLineManager().getProgressMonitor();
+ }
+
+ /**
+ * Returns the primary type of a compilation unit (has the same
+ * name as the compilation unit).
+ *
+ * @param compilationUnit the compilation unit
+ * @return returns the primary type of the compilation unit, or
+ * <code>null</code> if is does not have one
+ */
+ private IType getMainType(IRubyScript compilationUnit) {
+
+ if (compilationUnit == null)
+ return null;
+
+ return compilationUnit.findPrimaryType();
+ }
+
+}
Added: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/TextMessages.properties
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/TextMessages.properties (rev 0)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/TextMessages.properties 2007-07-07 00:59:07 UTC (rev 2726)
@@ -0,0 +1,24 @@
+###############################################################################
+# Copyright (c) 2007 Aptana, Inc.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html. If redistributing this code,
+# this entire header must remain intact.
+###############################################################################
+# messages.properties
+# contains externalized strings for this package
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# This file should be translated.
+RubyOutlineInformationControl_LexicalSortingAction_label= &Sort
+RubyOutlineInformationControl_LexicalSortingAction_tooltip= Sort
+RubyOutlineInformationControl_LexicalSortingAction_description= Enable Sorting
+
+RubyOutlineInformationControl_SortByDefiningTypeAction_label= Sort by the Defining &Type
+RubyOutlineInformationControl_SortByDefiningTypeAction_tooltip= Sort Members by the Defining Type
+RubyOutlineInformationControl_SortByDefiningTypeAction_description= Sort members by the defining type
+
+RubyOutlineInformationControl_GoIntoTopLevelType_label= &Go Into Top Level Type
+RubyOutlineInformationControl_GoIntoTopLevelType_tooltip= Go Into Top Level Type
+RubyOutlineInformationControl_GoIntoTopLevelType_description= Show children of top level type only
\ No newline at end of file
Added: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/OverrideIndicatorLabelDecorator.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/OverrideIndicatorLabelDecorator.java (rev 0)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/OverrideIndicatorLabelDecorator.java 2007-07-07 00:59:07 UTC (rev 2726)
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.rubypeople.rdt.ui;
+
+import org.eclipse.debug.internal.ui.ImageDescriptorRegistry;
+import org.eclipse.debug.internal.ui.views.launch.ImageImageDescriptor;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.rubypeople.rdt.core.IMethod;
+import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.ITypeHierarchy;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.internal.corext.util.MethodOverrideTester;
+import org.rubypeople.rdt.internal.corext.util.RubyModelUtil;
+import org.rubypeople.rdt.internal.corext.util.SuperTypeHierarchyCache;
+import org.rubypeople.rdt.internal.ui.RubyPlugin;
+import org.rubypeople.rdt.internal.ui.RubyPluginImages;
+
+/**
+ * LabelDecorator that decorates an method's image with override or implements overlays.
+ * The viewer using this decorator is responsible for updating the images on element changes.
+ *
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ *
+ * @since 2.0
+ */
+public class OverrideIndicatorLabelDecorator implements ILabelDecorator, ILightweightLabelDecorator {
+
+ private ImageDescriptorRegistry fRegistry;
+ private boolean fUseNewRegistry= false;
+
+ /**
+ * Creates a decorator. The decorator creates an own image registry to cache
+ * images.
+ */
+ public OverrideIndicatorLabelDecorator() {
+ this(null);
+ fUseNewRegistry= true;
+ }
+
+ /*
+ * Creates decorator with a shared image registry.
+ *
+ * @param registry The registry to use or <code>null</code> to use the Ruby plugin's
+ * image registry.
+ */
+ /**
+ * Note: This constructor is for internal use only. Clients should not call this constructor.
+ * @param registry The registry to use.
+ */
+ public OverrideIndicatorLabelDecorator(ImageDescriptorRegistry registry) {
+ fRegistry= registry;
+ }
+
+ private ImageDescriptorRegistry getRegistry() {
+ if (fRegistry == null) {
+ fRegistry= fUseNewRegistry ? new ImageDescriptorRegistry() : RubyPlugin.getImageDescriptorRegistry();
+ }
+ return fRegistry;
+ }
+
+
+ /* (non-Rubydoc)
+ * @see ILabelDecorator#decorateText(String, Object)
+ */
+ public String decorateText(String text, Object element) {
+ return text;
+ }
+
+ /* (non-Rubydoc)
+ * @see ILabelDecorator#decorateImage(Image, Object)
+ */
+ public Image decorateImage(Image image, Object element) {
+ int adornmentFlags= computeAdornmentFlags(element);
+ if (adornmentFlags != 0) {
+ ImageDescriptor baseImage= new ImageImageDescriptor(image);
+ Rectangle bounds= image.getBounds();
+ return getRegistry().get(new RubyElementImageDescriptor(baseImage, adornmentFlags, new Point(bounds.width, bounds.height)));
+ }
+ return image;
+ }
+
+ /**
+ * Note: This method is for internal use only. Clients should not call this method.
+ * @param element The element to decorate
+ * @return Resulting decorations (combination of RubyElementImageDescriptor.IMPLEMENTS
+ * and RubyElementImageDescriptor.OVERRIDES)
+ */
+ public int computeAdornmentFlags(Object element) {
+ if (element instanceof IMethod) {
+ try {
+ IMethod method= (IMethod) element;
+ if (!method.getRubyProject().isOnLoadpath(method)) {
+ return 0;
+ }
+ if (!method.isConstructor() && method.getVisibility() != IMethod.PRIVATE && !method.isSingleton()) {
+ int res= getOverrideIndicators(method);
+ return res;
+ }
+ } catch (RubyModelException e) {
+ if (!e.isDoesNotExist()) {
+ RubyPlugin.log(e);
+ }
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Note: This method is for internal use only. Clients should not call this method.
+ * @param method The element to decorate
+ * @return Resulting decorations (combination of RubyElementImageDescriptor.IMPLEMENTS
+ * and RubyElementImageDescriptor.OVERRIDES)
+ * @throws RubyModelException
+ */
+ protected int getOverrideIndicators(IMethod method) throws RubyModelException {
+// Node astRoot= RubyPlugin.getDefault().getASTProvider().getAST((IRubyElement) method.getOpenable(), ASTProvider.WAIT_NO, null);
+// if (astRoot != null) {
+// int res= findInHierarchyWithAST(astRoot, method);
+// if (res != -1) {
+// return res;
+// }
+// }
+
+ IType type= method.getDeclaringType();
+
+ MethodOverrideTester methodOverrideTester= SuperTypeHierarchyCache.getMethodOverrideTester(type);
+ IMethod defining= methodOverrideTester.findOverriddenMethod(method, true);
+ if (defining != null) {
+ return RubyElementImageDescriptor.OVERRIDES;
+ }
+ return 0;
+ }
+
+// private int findInHierarchyWithAST(Node astRoot, IMethod method) throws RubyModelException {
+// Node methodNode = ClosestSpanningNodeLocator.Instance().findClosestSpanner(astRoot, method.getNameRange().getOffset(), new INodeAcceptor() {
+//
+// public boolean doesAccept(Node node) {
+// return node instanceof MethodDefNode;
+// }
+//
+// });
+//
+// Node node= NodeFinder.perform(astRoot, method.getNameRange());
+// if (node instanceof SimpleName && node.getParent() instanceof MethodDeclaration) {
+// IMethodBinding binding= ((MethodDeclaration) node.getParent()).resolveBinding();
+// if (binding != null) {
+// IMethodBinding defining= Bindings.findOverriddenMethod(binding, true);
+// if (defining != null) {
+// return RubyElementImageDescriptor.OVERRIDES;
+// }
+// return 0;
+// }
+// }
+// return -1;
+// }
+
+ /**
+ * Note: This method is for internal use only. Clients should not call this method.
+ * @param type The declaring type of the method to decorate.
+ * @param hierarchy The type hierarchy of the declaring type.
+ * @param name The name of the method to find.
+ * @param paramTypes The parameter types of the method to find.
+ * @return The resulting decoration.
+ * @throws RubyModelException
+ * @deprecated Not used anymore. This method is not accurate for methods in generic types.
+ */
+ protected int findInHierarchy(IType type, ITypeHierarchy hierarchy, String name, String[] paramTypes) throws RubyModelException {
+ IType superClass= hierarchy.getSuperclass(type);
+ if (superClass != null) {
+ IMethod res= RubyModelUtil.findMethodInHierarchy(hierarchy, superClass, name, paramTypes, false);
+ if (res != null && res.getVisibility() != IMethod.PRIVATE && RubyModelUtil.isVisibleInHierarchy(res, type.getSourceFolder())) {
+ return RubyElementImageDescriptor.OVERRIDES;
+ }
+ }
+ IType[] interfaces= hierarchy.getSuperInterfaces(type);
+ for (int i= 0; i < interfaces.length; i++) {
+ IMethod res= RubyModelUtil.findMethodInHierarchy(hierarchy, interfaces[i], name, paramTypes, false);
+ if (res != null) {
+ return RubyElementImageDescriptor.OVERRIDES;
+ }
+ }
+ return 0;
+ }
+
+ /* (non-Rubydoc)
+ * @see IBaseLabelProvider#addListener(ILabelProviderListener)
+ */
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ /* (non-Rubydoc)
+ * @see IBaseLabelProvider#dispose()
+ */
+ public void dispose() {
+ if (fRegistry != null && fUseNewRegistry) {
+ fRegistry.dispose();
+ }
+ }
+
+ /* (non-Rubydoc)
+ * @see IBaseLabelProvider#isLabelProperty(Object, String)
+ */
+ public boolean isLabelProperty(Object element, String property) {
+ return true;
+ }
+
+ /* (non-Rubydoc)
+ * @see IBaseLabelProvider#removeListener(ILabelProviderListener)
+ */
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ /* (non-Rubydoc)
+ * @see org.eclipse.jface.viewers.ILightweightLabelDecorator#decorate(java.lang.Object, org.eclipse.jface.viewers.IDecoration)
+ */
+ public void decorate(Object element, IDecoration decoration) {
+ int adornmentFlags= computeAdornmentFlags(element);
+ if ((adornmentFlags & RubyElementImageDescriptor.IMPLEMENTS) != 0) {
+ decoration.addOverlay(RubyPluginImages.DESC_OVR_IMPLEMENTS);
+ } else if ((adornmentFlags & RubyElementImageDescriptor.OVERRIDES) != 0) {
+ decoration.addOverlay(RubyPluginImages.DESC_OVR_OVERRIDES);
+ }
+ }
+
+}
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/text/RubySourceViewerConfiguration.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/text/RubySourceViewerConfiguration.java 2007-07-07 00:29:33 UTC (rev 2725)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/ui/text/RubySourceViewerConfiguration.java 2007-07-07 00:59:07 UTC (rev 2726)
@@ -4,6 +4,7 @@
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.AbstractInformationControlManager;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.jface.text.IDocument;
@@ -51,6 +52,8 @@
import org.rubypeople.rdt.internal.ui.text.RubyAnnotationHover;
import org.rubypeople.rdt.internal.ui.text.RubyCommentScanner;
import org.rubypeople.rdt.internal.ui.text.RubyDoubleClickSelector;
+import org.rubypeople.rdt.internal.ui.text.RubyElementProvider;
+import org.rubypeople.rdt.internal.ui.text.RubyOutlineInformationControl;
import org.rubypeople.rdt.internal.ui.text.RubyPartitionScanner;
import org.rubypeople.rdt.internal.ui.text.RubyReconciler;
import org.rubypeople.rdt.internal.ui.text.comment.CommentFormattingStrategy;
@@ -68,6 +71,7 @@
import org.rubypeople.rdt.internal.ui.text.ruby.hover.RubyEditorTextHoverDescriptor;
import org.rubypeople.rdt.internal.ui.text.ruby.hover.RubyEditorTextHoverProxy;
import org.rubypeople.rdt.internal.ui.text.ruby.hover.RubyInformationProvider;
+import org.rubypeople.rdt.ui.actions.IRubyEditorActionDefinitionIds;
public class RubySourceViewerConfiguration extends TextSourceViewerConfiguration {
@@ -539,5 +543,53 @@
return new RubyCorrectionAssistant(getEditor());
return null;
}
+
+ /**
+ * Returns the outline presenter which will determine and shown
+ * information requested for the current cursor position.
+ *
+ * @param sourceViewer the source viewer to be configured by this configuration
+ * @param doCodeResolve a boolean which specifies whether code resolve should be used to compute the Java element
+ * @return an information presenter
+ * @since 2.1
+ */
+ public IInformationPresenter getOutlinePresenter(ISourceViewer sourceViewer, boolean doCodeResolve) {
+ InformationPresenter presenter;
+ if (doCodeResolve)
+ presenter= new InformationPresenter(getOutlinePresenterControlCreator(sourceViewer, IRubyEditorActionDefinitionIds.OPEN_STRUCTURE));
+ else
+ presenter= new InformationPresenter(getOutlinePresenterControlCreator(sourceViewer, IRubyEditorActionDefinitionIds.SHOW_OUTLINE));
+ presenter.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
+ presenter.setAnchor(AbstractInformationControlManager.ANCHOR_GLOBAL);
+ IInformationProvider provider= new RubyElementProvider(getEditor(), doCodeResolve);
+ presenter.setInformationProvider(provider, IDocument.DEFAULT_CONTENT_TYPE);
+ presenter.setInformationProvider(provider, IRubyPartitions.RUBY_MULTI_LINE_COMMENT);
+ presenter.setInformationProvider(provider, IRubyPartitions.RUBY_SINGLE_LINE_COMMENT);
+ presenter.setInformationProvider(provider, IRubyPartitions.RUBY_STRING);
+ presenter.setInformationProvider(provider, IRubyPartitions.RUBY_REGULAR_EXPRESSION);
+ presenter.setInformationProvider(provider, IRubyPartitions.RUBY_COMMAND);
+ presenter.setSizeConstraints(50, 20, true, false);
+ return presenter;
+ }
+
+ /**
+ * Returns the outline presenter control creator. The creator is a factory creating outline
+ * presenter controls for the given source viewer. This implementation always returns a creator
+ * for <code>JavaOutlineInformationControl</code> instances.
+ *
+ * @param sourceViewer the source viewer to be configured by this configuration
+ * @param commandId the ID of the command that opens this control
+ * @return an information control creator
+ * @since 1.0
+ */
+ private IInformationControlCreator getOutlinePresenterControlCreator(ISourceViewer sourceViewer, final String commandId) {
+ return new IInformationControlCreator() {
+ public IInformationControl createInformationControl(Shell parent) {
+ int shellStyle= SWT.RESIZE;
+ int treeStyle= SWT.V_SCROLL | SWT.H_SCROLL;
+ return new RubyOutlineInformationControl(parent, shellStyle, treeStyle, commandId);
+ }
+ };
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-07 00:29:36
|
Revision: 2725
http://svn.sourceforge.net/rubyeclipse/?rev=2725&view=rev
Author: cawilliams
Date: 2007-07-06 17:29:33 -0700 (Fri, 06 Jul 2007)
Log Message:
-----------
more Quick Outline groundwork
Modified Paths:
--------------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/actions/SelectionConverter.java
Added Paths:
-----------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyElementProvider.java
Modified: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/actions/SelectionConverter.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/actions/SelectionConverter.java 2007-07-06 20:45:34 UTC (rev 2724)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/actions/SelectionConverter.java 2007-07-07 00:29:33 UTC (rev 2725)
@@ -5,8 +5,13 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.rubypeople.rdt.core.ICodeAssist;
import org.rubypeople.rdt.core.IRubyElement;
@@ -20,6 +25,54 @@
import org.rubypeople.rdt.ui.IWorkingCopyManager;
public class SelectionConverter {
+
+ /**
+ * Converts the selection provided by the given part into a structured selection.
+ * The following conversion rules are used:
+ * <ul>
+ * <li><code>part instanceof RubyEditor</code>: returns a structured selection
+ * using code resolve to convert the editor's text selection.</li>
+ * <li><code>part instanceof IWorkbenchPart</code>: returns the part's selection
+ * if it is a structured selection.</li>
+ * <li><code>default</code>: returns an empty structured selection.</li>
+ * </ul>
+ */
+ public static IStructuredSelection getStructuredSelection(IWorkbenchPart part) throws RubyModelException {
+ if (part instanceof RubyEditor)
+ return new StructuredSelection(codeResolve((RubyEditor)part));
+ ISelectionProvider provider= part.getSite().getSelectionProvider();
+ if (provider != null) {
+ ISelection selection= provider.getSelection();
+ if (selection instanceof IStructuredSelection)
+ return (IStructuredSelection)selection;
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ public static IRubyElement getElementAtOffset(RubyEditor editor) throws RubyModelException {
+ return getElementAtOffset(editor, true);
+ }
+
+ /**
+ * @param primaryOnly if <code>true</code> only primary working copies will be returned
+ * @since 3.2
+ */
+ private static IRubyElement getElementAtOffset(RubyEditor editor, boolean primaryOnly) throws RubyModelException {
+ return getElementAtOffset(getInput(editor, primaryOnly), (ITextSelection)editor.getSelectionProvider().getSelection());
+ }
+
+ public static IRubyElement getElementAtOffset(IRubyElement input, ITextSelection selection) throws RubyModelException {
+ if (input instanceof IRubyScript) {
+ IRubyScript cunit= (IRubyScript) input;
+ RubyModelUtil.reconcile(cunit);
+ IRubyElement ref= cunit.getElementAt(selection.getOffset());
+ if (ref == null)
+ return input;
+ else
+ return ref;
+ }
+ return null;
+ }
public static IRubyScript getInputAsRubyScript(RubyEditor editor) {
Object editorInput = SelectionConverter.getInput(editor);
Added: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyElementProvider.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyElementProvider.java (rev 0)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/text/RubyElementProvider.java 2007-07-07 00:29:33 UTC (rev 2725)
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.rubypeople.rdt.internal.ui.text;
+
+
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.information.IInformationProvider;
+import org.eclipse.jface.text.information.IInformationProviderExtension;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IEditorPart;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.internal.ui.actions.SelectionConverter;
+import org.rubypeople.rdt.internal.ui.rubyeditor.EditorUtility;
+import org.rubypeople.rdt.internal.ui.rubyeditor.RubyEditor;
+
+/**
+ * Provides a Ruby element to be displayed in by an information presenter.
+ */
+public class RubyElementProvider implements IInformationProvider, IInformationProviderExtension {
+
+ private RubyEditor fEditor;
+ private boolean fUseCodeResolve;
+
+ public RubyElementProvider(IEditorPart editor) {
+ fUseCodeResolve= false;
+ if (editor instanceof RubyEditor)
+ fEditor= (RubyEditor)editor;
+ }
+
+ public RubyElementProvider(IEditorPart editor, boolean useCodeResolve) {
+ this(editor);
+ fUseCodeResolve= useCodeResolve;
+ }
+
+ /*
+ * @see IInformationProvider#getSubject(ITextViewer, int)
+ */
+ public IRegion getSubject(ITextViewer textViewer, int offset) {
+ if (textViewer != null && fEditor != null) {
+ IRegion region= RubyWordFinder.findWord(textViewer.getDocument(), offset);
+ if (region != null)
+ return region;
+ else
+ return new Region(offset, 0);
+ }
+ return null;
+ }
+
+ /*
+ * @see IInformationProvider#getInformation(ITextViewer, IRegion)
+ */
+ public String getInformation(ITextViewer textViewer, IRegion subject) {
+ return getInformation2(textViewer, subject).toString();
+ }
+
+ /*
+ * @see IInformationProviderExtension#getElement(ITextViewer, IRegion)
+ */
+ public Object getInformation2(ITextViewer textViewer, IRegion subject) {
+ if (fEditor == null)
+ return null;
+
+ try {
+ if (fUseCodeResolve) {
+ IStructuredSelection sel= SelectionConverter.getStructuredSelection(fEditor);
+ if (!sel.isEmpty())
+ return sel.getFirstElement();
+ }
+ IRubyElement element= SelectionConverter.getElementAtOffset(fEditor);
+ if (element != null)
+ return element;
+
+ return EditorUtility.getEditorInputRubyElement(fEditor, false);
+ } catch (RubyModelException e) {
+ return null;
+ }
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-06 20:45:35
|
Revision: 2724
http://svn.sourceforge.net/rubyeclipse/?rev=2724&view=rev
Author: cawilliams
Date: 2007-07-06 13:45:34 -0700 (Fri, 06 Jul 2007)
Log Message:
-----------
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java 2007-07-06 20:39:42 UTC (rev 2723)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/internal/core/RubyType.java 2007-07-06 20:45:34 UTC (rev 2724)
@@ -35,6 +35,7 @@
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.ISourceFolder;
import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.ITypeHierarchy;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.WorkingCopyOwner;
import org.rubypeople.rdt.internal.core.util.MementoTokenizer;
@@ -311,5 +312,28 @@
list.toArray(array);
return array;
}
+
+ /**
+ * @see IType
+ */
+ public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) throws RubyModelException {
+ return this.newSupertypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor);
+ }
+
+ /**
+ * @see IType#newSupertypeHierarchy(WorkingCopyOwner, IProgressMonitor)
+ */
+ public ITypeHierarchy newSupertypeHierarchy(
+ WorkingCopyOwner owner,
+ IProgressMonitor monitor)
+ throws RubyModelException {
+ IRubyScript[] workingCopies = RubyModelManager.getRubyModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
+// CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
+// op.runOperation(monitor);
+// return op.getResult();
+ // XXX Implement!
+ return null;
+ }
+
}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <caw...@us...> - 2007-07-06 20:39:44
|
Revision: 2723
http://svn.sourceforge.net/rubyeclipse/?rev=2723&view=rev
Author: cawilliams
Date: 2007-07-06 13:39:42 -0700 (Fri, 06 Jul 2007)
Log Message:
-----------
more Type Hierarchy groundwork
Modified Paths:
--------------
trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IType.java
Added Paths:
-----------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/LRUMap.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/SuperTypeHierarchyCache.java
Modified: trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IType.java
===================================================================
--- trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IType.java 2007-07-06 20:07:03 UTC (rev 2722)
+++ trunk/org.rubypeople.rdt.core/src/org/rubypeople/rdt/core/IType.java 2007-07-06 20:39:42 UTC (rev 2723)
@@ -188,4 +188,15 @@
*/
IType[] getTypes() throws RubyModelException;
+ /**
+ * Creates and returns a type hierarchy for this type containing
+ * this type and all of its supertypes.
+ *
+ * @param monitor the given progress monitor
+ * @exception RubyModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ * @return a type hierarchy for this type containing this type and all of its supertypes
+ */
+ ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) throws RubyModelException;
+
}
\ No newline at end of file
Added: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/LRUMap.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/LRUMap.java (rev 0)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/LRUMap.java 2007-07-06 20:39:42 UTC (rev 2723)
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.rubypeople.rdt.internal.corext.util;
+
+import java.util.LinkedHashMap;
+
+/**
+ *
+ */
+public class LRUMap extends LinkedHashMap {
+
+ private static final long serialVersionUID= 1L;
+ private final int fMaxSize;
+
+ public LRUMap(int maxSize) {
+ super(maxSize, 0.75f, true);
+ fMaxSize= maxSize;
+ }
+
+ protected boolean removeEldestEntry(java.util.Map.Entry eldest) {
+ return size() > fMaxSize;
+ }
+}
Added: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/SuperTypeHierarchyCache.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/SuperTypeHierarchyCache.java (rev 0)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/SuperTypeHierarchyCache.java 2007-07-06 20:39:42 UTC (rev 2723)
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.rubypeople.rdt.internal.corext.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.ITypeHierarchy;
+import org.rubypeople.rdt.core.ITypeHierarchyChangedListener;
+import org.rubypeople.rdt.core.RubyModelException;
+
+public class SuperTypeHierarchyCache {
+
+ private static class HierarchyCacheEntry implements ITypeHierarchyChangedListener {
+
+ private ITypeHierarchy fTypeHierarchy;
+ private long fLastAccess;
+
+ public HierarchyCacheEntry(ITypeHierarchy hierarchy) {
+ fTypeHierarchy= hierarchy;
+ fTypeHierarchy.addTypeHierarchyChangedListener(this);
+ markAsAccessed();
+ }
+
+ public void typeHierarchyChanged(ITypeHierarchy typeHierarchy) {
+ removeHierarchyEntryFromCache(this);
+ }
+
+ public ITypeHierarchy getTypeHierarchy() {
+ return fTypeHierarchy;
+ }
+
+ public void markAsAccessed() {
+ fLastAccess= System.currentTimeMillis();
+ }
+
+ public long getLastAccess() {
+ return fLastAccess;
+ }
+
+ public void dispose() {
+ fTypeHierarchy.removeTypeHierarchyChangedListener(this);
+ fTypeHierarchy= null;
+ }
+
+ /* (non-Rubydoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return "Super hierarchy of: " + fTypeHierarchy.getType().getElementName(); //$NON-NLS-1$
+ }
+
+ }
+
+
+ private static final int CACHE_SIZE= 8;
+
+ private static ArrayList fgHierarchyCache= new ArrayList(CACHE_SIZE);
+ private static Map fgMethodOverrideTesterCache= new LRUMap(CACHE_SIZE);
+
+ private static int fgCacheHits= 0;
+ private static int fgCacheMisses= 0;
+
+ /**
+ * Get a hierarchy for the given type
+ */
+ public static ITypeHierarchy getTypeHierarchy(IType type) throws RubyModelException {
+ return getTypeHierarchy(type, null);
+ }
+
+ public static MethodOverrideTester getMethodOverrideTester(IType type) throws RubyModelException {
+ MethodOverrideTester test= null;
+ synchronized (fgMethodOverrideTesterCache) {
+ test= (MethodOverrideTester) fgMethodOverrideTesterCache.get(type);
+ }
+ if (test == null) {
+ ITypeHierarchy hierarchy= getTypeHierarchy(type); // don't nest the locks
+ synchronized (fgMethodOverrideTesterCache) {
+ test= (MethodOverrideTester) fgMethodOverrideTesterCache.get(type); // test again after waiting a long time for 'getTypeHierarchy'
+ if (test == null) {
+ test= new MethodOverrideTester(type, hierarchy);
+ fgMethodOverrideTesterCache.put(type, test);
+ }
+ }
+ }
+ return test;
+ }
+
+ private static void removeMethodOverrideTester(ITypeHierarchy hierarchy) {
+ synchronized (fgMethodOverrideTesterCache) {
+ for (Iterator iter= fgMethodOverrideTesterCache.values().iterator(); iter.hasNext();) {
+ MethodOverrideTester curr= (MethodOverrideTester) iter.next();
+ if (curr.getTypeHierarchy().equals(hierarchy)) {
+ iter.remove();
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Get a hierarchy for the given type
+ */
+ public static ITypeHierarchy getTypeHierarchy(IType type, IProgressMonitor progressMonitor) throws RubyModelException {
+ ITypeHierarchy hierarchy= findTypeHierarchyInCache(type);
+ if (hierarchy == null) {
+ fgCacheMisses++;
+ hierarchy= type.newSupertypeHierarchy(progressMonitor);
+ addTypeHierarchyToCache(hierarchy);
+ } else {
+ fgCacheHits++;
+ }
+ return hierarchy;
+ }
+
+ private static void addTypeHierarchyToCache(ITypeHierarchy hierarchy) {
+ synchronized (fgHierarchyCache) {
+ int nEntries= fgHierarchyCache.size();
+ if (nEntries >= CACHE_SIZE) {
+ // find obsolete entries or remove entry that was least recently accessed
+ HierarchyCacheEntry oldest= null;
+ ArrayList obsoleteHierarchies= new ArrayList(CACHE_SIZE);
+ for (int i= 0; i < nEntries; i++) {
+ HierarchyCacheEntry entry= (HierarchyCacheEntry) fgHierarchyCache.get(i);
+ ITypeHierarchy curr= entry.getTypeHierarchy();
+ if (!curr.exists() || hierarchy.contains(curr.getType())) {
+ obsoleteHierarchies.add(entry);
+ } else {
+ if (oldest == null || entry.getLastAccess() < oldest.getLastAccess()) {
+ oldest= entry;
+ }
+ }
+ }
+ if (!obsoleteHierarchies.isEmpty()) {
+ for (int i= 0; i < obsoleteHierarchies.size(); i++) {
+ removeHierarchyEntryFromCache((HierarchyCacheEntry) obsoleteHierarchies.get(i));
+ }
+ } else if (oldest != null) {
+ removeHierarchyEntryFromCache(oldest);
+ }
+ }
+ HierarchyCacheEntry newEntry= new HierarchyCacheEntry(hierarchy);
+ fgHierarchyCache.add(newEntry);
+ }
+ }
+
+
+ /**
+ * Check if the given type is in the hierarchy
+ * @param type
+ * @return Return <code>true</code> if a hierarchy for the given type is cached.
+ */
+ public static boolean hasInCache(IType type) {
+ return findTypeHierarchyInCache(type) != null;
+ }
+
+
+ private static ITypeHierarchy findTypeHierarchyInCache(IType type) {
+ synchronized (fgHierarchyCache) {
+ for (int i= fgHierarchyCache.size() - 1; i>= 0; i--) {
+ HierarchyCacheEntry curr= (HierarchyCacheEntry) fgHierarchyCache.get(i);
+ ITypeHierarchy hierarchy= curr.getTypeHierarchy();
+ if (!hierarchy.exists()) {
+ removeHierarchyEntryFromCache(curr);
+ } else {
+ if (hierarchy.contains(type)) {
+ curr.markAsAccessed();
+ return hierarchy;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static void removeHierarchyEntryFromCache(HierarchyCacheEntry entry) {
+ synchronized (fgHierarchyCache) {
+ removeMethodOverrideTester(entry.getTypeHierarchy());
+ entry.dispose();
+ fgHierarchyCache.remove(entry);
+ }
+ }
+
+
+ /**
+ * Gets the number of times the hierarchy could be taken from the hierarchy.
+ * @return Returns a int
+ */
+ public static int getCacheHits() {
+ return fgCacheHits;
+ }
+
+ /**
+ * Gets the number of times the hierarchy was build. Used for testing.
+ * @return Returns a int
+ */
+ public static int getCacheMisses() {
+ return fgCacheMisses;
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|