-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* .NET C# stacktrace support #5489 Fixes: Issue #5489 Signed-off-by: Victor Rubezhny <vrubezhny@redhat.com>
- Loading branch information
Showing
14 changed files
with
1,001 additions
and
334 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/console/AbstractOutputCustomizer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2017 Red Hat, 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 | ||
* | ||
* Contributors: | ||
* Red Hat, Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.che.ide.console; | ||
|
||
import static com.google.common.base.Preconditions.checkNotNull; | ||
import static com.google.common.base.Strings.nullToEmpty; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
import org.eclipse.che.api.promises.client.Function; | ||
import org.eclipse.che.api.promises.client.FunctionException; | ||
import org.eclipse.che.api.promises.client.Promise; | ||
import org.eclipse.che.ide.api.app.AppContext; | ||
import org.eclipse.che.ide.api.editor.EditorAgent; | ||
import org.eclipse.che.ide.api.editor.EditorPartPresenter; | ||
import org.eclipse.che.ide.api.editor.OpenEditorCallbackImpl; | ||
import org.eclipse.che.ide.api.editor.document.Document; | ||
import org.eclipse.che.ide.api.editor.text.LinearRange; | ||
import org.eclipse.che.ide.api.editor.text.TextPosition; | ||
import org.eclipse.che.ide.api.editor.texteditor.TextEditor; | ||
import org.eclipse.che.ide.api.resources.Container; | ||
import org.eclipse.che.ide.api.resources.File; | ||
import org.eclipse.che.ide.api.resources.Resource; | ||
import org.eclipse.che.ide.resource.Path; | ||
|
||
import com.google.gwt.user.client.Timer; | ||
|
||
/** | ||
* Default customizer adds an anchor link to the lines that match a stack trace | ||
* line pattern and installs a handler function for the link. The handler parses | ||
* the stack trace line, searches for the candidate Java files to navigate to, | ||
* opens the first file (of the found candidates) in editor and reveals it to | ||
* the required line according to the stack trace line information | ||
* | ||
* @author Victor Rubezhny | ||
*/ | ||
abstract public class AbstractOutputCustomizer implements OutputCustomizer { | ||
|
||
protected AppContext appContext; | ||
protected EditorAgent editorAgent; | ||
|
||
public AbstractOutputCustomizer(AppContext appContext, EditorAgent editorAgent) { | ||
this.appContext = appContext; | ||
this.editorAgent = editorAgent; | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* | ||
* @see org.eclipse.che.ide.extension.machine.client.outputspanel.console. | ||
* OutputCustomizer#canCustomize(java.lang.String) | ||
*/ | ||
@Override | ||
abstract public boolean canCustomize(String text); | ||
|
||
/* | ||
* (non-Javadoc) | ||
* | ||
* @see org.eclipse.che.ide.extension.machine.client.outputspanel.console. | ||
* OutputCustomizer#customize(java.lang.String) | ||
*/ | ||
@Override | ||
abstract public String customize(String text); | ||
|
||
/* | ||
* Returns the list of workspace files filtered by a relative path | ||
*/ | ||
protected Promise<List<File>> collectChildren(Container root, Path relativeFilePath) { | ||
return root.getTree(-1).then(new Function<Resource[], List<File>>() { | ||
@Override | ||
public List<File> apply(Resource[] children) throws FunctionException { | ||
return Stream.of(children) | ||
.filter(child -> child.isFile() && endsWith(child.asFile().getLocation(), relativeFilePath)) | ||
.map(Resource::asFile).collect(Collectors.toList()); | ||
} | ||
}); | ||
} | ||
|
||
/* | ||
* Checks if a path's last segments are equal to the provided relative path | ||
*/ | ||
protected boolean endsWith(Path path, Path relativePath) { | ||
checkNotNull(path); | ||
checkNotNull(relativePath); | ||
|
||
if (path.segmentCount() < relativePath.segmentCount()) | ||
return false; | ||
|
||
for (int i = relativePath.segmentCount() - 1, j = path.segmentCount() - 1; i >= 0; i--, j--) { | ||
if (!nullToEmpty(relativePath.segment(i)).equals(path.segment(j))) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Finds a file by its path, opens it in editor and sets the text selection and | ||
* reveals according to the specified line and column numbers | ||
* | ||
* @param file | ||
* @param lineNumber | ||
* @param columnNumber | ||
*/ | ||
protected void openFileInEditorAndReveal(AppContext appContext, EditorAgent editorAgent, Path file, | ||
final int lineNumber, final int columnNumber) { | ||
appContext.getWorkspaceRoot().getFile(file).then(optional -> { | ||
if (optional.isPresent()) { | ||
editorAgent.openEditor(optional.get(), new OpenEditorCallbackImpl() { | ||
@Override | ||
public void onEditorOpened(EditorPartPresenter editor) { | ||
Timer t = new Timer() { | ||
@Override | ||
public void run() { | ||
EditorPartPresenter editorPart = editorAgent.getActiveEditor(); | ||
selectRange(editorPart, lineNumber, columnNumber); | ||
} | ||
}; | ||
t.schedule(500); | ||
} | ||
|
||
@Override | ||
public void onEditorActivated(EditorPartPresenter editor) { | ||
selectRange(editor, lineNumber, columnNumber); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Selects and shows the specified line and column of text in editor | ||
* | ||
* @param editor | ||
* @param line | ||
* @param column | ||
*/ | ||
protected void selectRange(EditorPartPresenter editor, int line, int column) { | ||
line--; | ||
column--; | ||
if (line < 0) | ||
line = 0; | ||
if (editor instanceof TextEditor) { | ||
Document document = ((TextEditor) editor).getDocument(); | ||
LinearRange selectionRange = document.getLinearRangeForLine(line); | ||
if (column >= 0) { | ||
selectionRange = LinearRange.createWithStart(selectionRange.getStartOffset() + column).andLength(0); | ||
} | ||
document.setSelectedRange(selectionRange, true); | ||
document.setCursorPosition(new TextPosition(line, column >= 0 ? column : 0)); | ||
} | ||
} | ||
} |
185 changes: 185 additions & 0 deletions
185
ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/console/CSharpOutputCustomizer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2017 Red Hat, 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 | ||
* | ||
* Contributors: | ||
* Red Hat, Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.che.ide.console; | ||
|
||
import static com.google.gwt.regexp.shared.RegExp.compile; | ||
|
||
import org.eclipse.che.ide.api.app.AppContext; | ||
import org.eclipse.che.ide.api.editor.EditorAgent; | ||
import org.eclipse.che.ide.resource.Path; | ||
|
||
import com.google.gwt.regexp.shared.RegExp; | ||
|
||
/** | ||
* Output customizer adds an anchor link to the lines that match a .NET C# | ||
* compilation error or warning message and a stack trace line pattern and | ||
* installs the handler functions for the links. The handler parses the stack | ||
* trace line, searches for a candidate C# file to navigate to, opens the found | ||
* file in editor and reveals it to the required line and column (if available) | ||
* according to the line information | ||
* | ||
* @author Victor Rubezhny | ||
*/ | ||
public class CSharpOutputCustomizer extends AbstractOutputCustomizer { | ||
|
||
private static final RegExp COMPILATION_ERROR_OR_WARNING = compile( | ||
"(.+\\.(cs|CS)\\(\\d+,\\d+\\): (error|warning) .+: .+ \\[.+\\])"); | ||
private static final RegExp LINE_AT = compile("(\\s+at .+ in .+\\.(cs|CS):line \\d+)"); | ||
|
||
/** | ||
* Constructs Compound Output Customizer Object | ||
* | ||
* @param appContext | ||
* @param editorAgent | ||
*/ | ||
public CSharpOutputCustomizer(AppContext appContext, EditorAgent editorAgent) { | ||
super(appContext, editorAgent); | ||
|
||
exportCompilationMessageAnchorClickHandlerFunction(); | ||
exportStacktraceLineAnchorClickHandlerFunction(); | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* | ||
* @see org.eclipse.che.ide.extension.machine.client.outputspanel.console. | ||
* OutputCustomizer#canCustomize(java.lang.String) | ||
*/ | ||
@Override | ||
public boolean canCustomize(String text) { | ||
return (COMPILATION_ERROR_OR_WARNING.exec(text) != null || LINE_AT.exec(text) != null); | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* | ||
* @see org.eclipse.che.ide.extension.machine.client.outputspanel.console. | ||
* OutputCustomizer#customize(java.lang.String) | ||
*/ | ||
@Override | ||
public String customize(String text) { | ||
if (COMPILATION_ERROR_OR_WARNING.exec(text) != null) | ||
return customizeCompilationErrorOrWarning(text); | ||
|
||
if (LINE_AT.exec(text) != null) | ||
return customizeStacktraceLine(text); | ||
|
||
return text; | ||
} | ||
|
||
/* | ||
* Customizes a Compilation Error/Warning line | ||
*/ | ||
private String customizeCompilationErrorOrWarning(String text) { | ||
try { | ||
int end = text.indexOf("):"), openBracket = text.lastIndexOf("(", end), comma = text.lastIndexOf(",", end), | ||
closeSBracket = text.lastIndexOf("]"), openSBracket = text.lastIndexOf("[", closeSBracket); | ||
String fileName = text.substring(0, openBracket).trim(); | ||
String projectFileName = text.substring(openSBracket + "[".length(), closeSBracket).trim(); | ||
int lineNumber = Integer.valueOf(text.substring(openBracket + "(".length(), comma).trim()); | ||
int columnNumber = Integer.valueOf(text.substring(comma + ",".length(), end).trim()); | ||
|
||
String customText = "<a href='javascript:openCSCM(\"" + fileName + "\",\"" + projectFileName + "\"," | ||
+ lineNumber + "," + columnNumber + ");'>"; | ||
customText += text.substring(0, end + ")".length()); | ||
customText += "</a>"; | ||
customText += text.substring(end + ")".length()); | ||
text = customText; | ||
} catch (IndexOutOfBoundsException ex) { | ||
// ignore | ||
} catch (NumberFormatException ex) { | ||
// ignore | ||
} | ||
|
||
return text; | ||
} | ||
|
||
/* | ||
* Customizes a Stacktrace line | ||
*/ | ||
private String customizeStacktraceLine(String text) { | ||
try { | ||
int start = text.lastIndexOf(" in ") + " in ".length(), end = text.indexOf(":line ", start); | ||
|
||
String fileName = text.substring(start, end).trim(); | ||
int lineNumber = Integer.valueOf(text.substring(end + ":line ".length()).trim()); | ||
|
||
String customText = text.substring(0, start); | ||
customText += "<a href='javascript:openCSSTL(\"" + fileName + "\"," + lineNumber + ");'>"; | ||
customText += text.substring(start); | ||
customText += "</a>"; | ||
text = customText; | ||
} catch (IndexOutOfBoundsException ex) { | ||
// ignore | ||
} catch (NumberFormatException ex) { | ||
// ignore | ||
} | ||
|
||
return text; | ||
} | ||
|
||
/** | ||
* A callback that is to be called for an anchor for C# Compilation | ||
* Error/Warning Message | ||
* | ||
* @param fileName | ||
* @param projectFile | ||
* @param lineNumber | ||
* @param columnNumber | ||
*/ | ||
public void handleCompilationMessageAnchorClick(String fileName, String projectFile, final int lineNumber, | ||
final int columnNumber) { | ||
if (fileName == null || projectFile == null) { | ||
return; | ||
} | ||
|
||
openFileInEditorAndReveal(appContext, editorAgent, | ||
Path.valueOf(projectFile).removeFirstSegments(1).parent().append(fileName), lineNumber, columnNumber); | ||
} | ||
|
||
/** | ||
* A callback that is to be called for an anchor for C# Runtime Exception | ||
* Stacktrace line | ||
* | ||
* @param fileName | ||
* @param lineNumber | ||
*/ | ||
public void handleStacktraceLineAnchorClick(String fileName, int lineNumber) { | ||
if (fileName == null) { | ||
return; | ||
} | ||
|
||
openFileInEditorAndReveal(appContext, editorAgent, | ||
Path.valueOf(fileName).removeFirstSegments(1), lineNumber, 0); | ||
} | ||
|
||
/** | ||
* Sets up a java callback to be called for an anchor for C# Compilation | ||
* Error/Warning Message | ||
*/ | ||
public native void exportCompilationMessageAnchorClickHandlerFunction() /*-{ | ||
var that = this; | ||
$wnd.openCSCM = $entry(function(fileName,projectFile,lineNumber,columnNumber) { | ||
that.@org.eclipse.che.ide.console.CSharpOutputCustomizer::handleCompilationMessageAnchorClick(*)(fileName,projectFile,lineNumber,columnNumber); | ||
}); | ||
}-*/; | ||
|
||
/** | ||
* Sets up a java callback to be called for an anchor for C# Runtime Exception | ||
* Stacktrace line | ||
*/ | ||
public native void exportStacktraceLineAnchorClickHandlerFunction() /*-{ | ||
var that = this; | ||
$wnd.openCSSTL = $entry(function(fileName,lineNumber) { | ||
that.@org.eclipse.che.ide.console.CSharpOutputCustomizer::handleStacktraceLineAnchorClick(*)(fileName,lineNumber); | ||
}); | ||
}-*/; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.