blob: 7035b4ce172c79a8acced1a3267063e4f86ac070 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 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:
* xored software, Inc. - �ompleted initial version (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.ruby.internal.debug.ui.console;
import java.io.File;
import java.io.IOException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.dltk.core.IDLTKLanguageToolkit;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.debug.core.DLTKDebugPlugin;
import org.eclipse.dltk.debug.ui.DLTKDebugUIPlugin;
import org.eclipse.dltk.internal.ui.editor.EditorUtility;
import org.eclipse.dltk.ruby.core.RubyLanguageToolkit;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.console.IHyperlink;
import org.eclipse.ui.console.TextConsole;
import org.eclipse.ui.ide.IDE;
/**
* A hyper link from a stack trace line of the form "*(*.rb:*)"
*/
public class RubyFileHyperlink implements IHyperlink {
private static final String ERROR_UNKNOWN_HYPERLINK = "Unknown hyperlink"; //$NON-NLS-1$
private static final String ERROR_NO_COLON_IN_LINK = "No ':' in link"; //$NON-NLS-1$
static final boolean DEBUG = false;
private final TextConsole fConsole;
public RubyFileHyperlink(TextConsole console) {
fConsole = console;
}
@Override
public void linkEntered() {
}
@Override
public void linkExited() {
}
@Override
public void linkActivated() {
final String fileName;
int lineNumber;
try {
final String linkText = getLinkText();
fileName = extractFileName(linkText);
lineNumber = extractLineNumber(linkText);
} catch (IllegalArgumentException e) {
DLTKDebugPlugin.log(e);
return;
}
try {
final Object element = findSourceModule(fileName);
if (element == null) {
// did not find source
MessageDialog
.openInformation(
DLTKDebugUIPlugin.getActiveWorkbenchShell(),
ConsoleMessages.RubyFileHyperlink_Information_1,
NLS
.bind(
ConsoleMessages.RubyFileHyperlink_Source_not_found_for__0__2,
new Object[] { fileName }));
return;
}
openInEditor(element, lineNumber);
} catch (CoreException e) {
DLTKDebugUIPlugin
.errorDialog(
ConsoleMessages.RubyFileHyperlink_An_exception_occurred_while_following_link__3,
e);
}
}
/**
* Opens the editor on the specified element and line number
*
* @param element
* @param lineNumber
* line number starting at 1
* @throws CoreException
*/
public static void openInEditor(final Object element, int lineNumber)
throws CoreException {
final IEditorInput input = EditorUtility.getEditorInput(element);
if (input == null) {
return;
}
final IEditorDescriptor descriptor = IDE.getEditorDescriptor(input
.getName(), true, false);
final IWorkbenchPage page = DLTKDebugUIPlugin.getActivePage();
final IEditorPart editor = page.openEditor(input, descriptor.getId());
// documents start at 0
if (lineNumber > 0) {
lineNumber--;
}
EditorUtility.revealInEditor(editor, lineNumber);
}
/**
* Finds {@link IFile} or {@link ISourceModule} matching the specified file
* name
*
* @param fileName
* @return
*/
public static Object findSourceModule(String fileName) {
final IPath path = Path.fromOSString(fileName);
final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
final IFile[] files = root.findFilesForLocation(path);
if (files.length != 0) {
return files[0];
}
if (DEBUG) {
System.out.println("File for " + path + " is not found"); //$NON-NLS-1$ //$NON-NLS-2$
}
final IDLTKLanguageToolkit toolkit = RubyLanguageToolkit.getDefault();
final RubyConsoleSourceModuleLookup lookup = new RubyConsoleSourceModuleLookup(
toolkit);
return lookup.findSourceModuleByLocalPath(path);
}
/**
* Returns the fully qualified name of the type to open
*
* @return fully qualified type name
* @exception IllegalArgumentException
* if unable to parse the type name
*/
static String extractFileName(String linkText)
throws IllegalArgumentException {
int pos = linkText.lastIndexOf(':');
if (pos > 0 && pos < linkText.length() - 1) {
return normalizePath(linkText.substring(0, pos));
}
throw new IllegalArgumentException(ERROR_NO_COLON_IN_LINK);
}
/**
* Calls {@link File#getCanonicalPath()} for the specified file name
*
* @param filePath
* @return
*/
private static String normalizePath(String filePath) {
try {
final File file = new File(filePath);
return file.getCanonicalPath();
} catch (IOException e) {
return filePath;
}
}
/**
* Returns the line number associated with the stack trace or throws
* {@link IllegalArgumentException}.
*
* @exception IllegalArgumentException
* if unable to parse the number
*/
static int extractLineNumber(String linkText)
throws IllegalArgumentException {
int pos = linkText.lastIndexOf(':');
if (pos > 0 && pos < linkText.length() - 1) {
return Integer.parseInt(linkText.substring(pos + 1));
}
throw new IllegalArgumentException(ERROR_NO_COLON_IN_LINK);
}
/**
* Returns this link's text
*
* @exception IllegalArgumentException
* if unable to retrieve the text
*/
protected String getLinkText() throws IllegalArgumentException {
IRegion region = fConsole.getRegion(this);
if (region == null) {
throw new IllegalArgumentException(ERROR_UNKNOWN_HYPERLINK);
}
return getText(region.getOffset(), region.getLength());
}
protected String getText(int offset, int length)
throws IllegalArgumentException {
try {
return fConsole.getDocument().get(offset, length);
} catch (BadLocationException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
}