Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[cdt-dev] Analysis and solutions for Open Declaration/Definition: incorrect editor opened for external files

Title: Analysis and solutions for Open Declaration/Definition: incorrect editor opened for external files

Another issue is that the wrong type of editor is sometimes opened for files not in the workspace, e.g. include paths pointing to SDKs.  Bug 142031 goes into this.  When a non-C++ editor is opened, the F3/Ctrl-F3 commands do not work (and there's no outline, etc).  It seems like there is adequate support for opening external files in a C++ editor, as evidenced when double-clicking on #include nodes in a C++ editor's Outline.  But, the various other commands that open files do not open editors in a uniform manner, sometimes bringing up non-C++ editors. 

I got a satisfactory solution by finding all the clients that open editors (open declaration/definition, open definition from C/C++ Index, double-click from C/C++ Search results -- any other places?) and refactoring the editor-opening code into a common "IEditorPart EditorUtility#openFileInEditor(IPath, ICElement)" routine.  The IPath is the filesystem path of the file to open, and the ICElement is the context element -- e.g. the source file containing an #include node or an ICProject from which the file is referenced. 

        /**
         * Given an absolute path, find some way to open a C/C++ Editor on the file.
         * This searches the workspace, linked resources, and translation units
         * @param fileToOpen the full path to the file
         * @param sourceElement an element in source bearing some relation to the target file
         * (e.g. an #include directive), may be null
         */
        public static IEditorPart openFileInEditor(IPath fileToOpen, ICElement sourceElement) throws CModelException, CoreException {

                IEditorPart part = null;
                IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(fileToOpen);
                if (file != null) {
                        part = EditorUtility.openInEditor(file);
                }
                if (part == null && sourceElement != null) {
                        ICProject cproject = sourceElement.getCProject();
                        ITranslationUnit unit = CoreModel.getDefault().createTranslationUnitFrom(cproject, fileToOpen);
                        if (unit != null) {
                                part = EditorUtility.openInEditor(unit);
                        }
                        if (part == null) {
                                // try linked files
                                IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(fileToOpen);

                                for(int i=0; i<files.length; i++) {
                                        if (files[i].isAccessible()) {
                                                part = EditorUtility.openInEditor(files[i]);
                                                if (part != null)
                                                        break;
                                        }
                                }
                        }
                }
                if (part == null) {
                        // last resort: opens a non-C++ editor.
                        // If you get here, consider passing a real sourceElement if possible.
                        FileStorage input = new FileStorage(fileToOpen);
                        part = EditorUtility.openInEditor(input);              
                }
                return part;
        }

This is essentially the code from the OpenIncludeAction -- it first tries to resolve the path to the workspace and opens the file in normal Eclipse fashion.  If the path is not in the workspace, the ICElement is used to find the project from which to retrieve #include paths.  Finally, if all else fails, an external non-C++ editor is opened.  In the future this could wrap an EFS solution.

This solution requires context (ICElement) to determine where to find #include paths.  Not all the clients have this context readily available.  In the tree views provided for C/C++ Index and C/C++ Search, from which you can navigate to source, the leaf nodes are IPDOMNodes that have no reference (AFAICT) to their owning projects. 

For testing purposes, I found the project by using an ugly hack of looking at the raw Tree to find the parent whose #getData() was an ICProject, and passed this along in #openFileInEditor(IPath, ICElement).  This allows these two clients to correctly open all the sources in proper C++ editors (for project-wide searches).  In workspace-wide searches, symbols found in include paths are still opened in the generic editor because there is no single project.  Not sure what to do here -- picking a random project doesn't quite seem right.  ;)

Would it make sense for a IPDOMNode to return its IPDOM, and for the IPDOM to return the root ICModel object against which it was built?  If so, this would obviate the ugly hack.  (Not sure how this will work with external PDOMs -- maybe they'd return a list of applicable ICProjects?).

-- Ed


Back to the top