mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-21 21:52:10 +02:00
Bug 563015: terminal: open files/links with ctrl-click
- hover with ctrl+mouse underlines word under cursor - ctrl-click tries to open the word: - if a relative path (not starting with /) a full path is obtained by prepending the shell cwd - if the fullpath maps to a workspace file, it is opened - otherwise open the OpenResource dialog with the word as filter text - if there is line/column information (separated by colons) then the opened editor jumps to that line - http and https words are opened in a browser window Change-Id: I3f46accbf1eac6743d7b0c3b34bf30ac5e7523bb Signed-off-by: Fabrizio Iannetti <fabrizio.iannetti@gmail.com> Also-by: Jonah Graham <jonah@kichwacoders.com> Signed-off-by: Jonah Graham <jonah@kichwacoders.com>
This commit is contained in:
parent
104819751c
commit
e6d5c634b9
23 changed files with 761 additions and 9 deletions
|
@ -286,6 +286,11 @@ public class Spawner extends Process {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long pid() {
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* On Windows, interrupt the spawned program by using Cygwin's utility 'kill -SIGINT' if it's a Cgywin
|
||||
* program, otherwise send it a CTRL-C. If Cygwin's 'kill' command is not available, send a CTRL-C. On
|
||||
|
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.tm.terminal.connector.process;singleton:=true
|
||||
Bundle-Version: 4.7.0.qualifier
|
||||
Bundle-Version: 4.8.0.qualifier
|
||||
Bundle-Activator: org.eclipse.tm.terminal.connector.process.activator.UIPlugin
|
||||
Bundle-Vendor: %providerName
|
||||
Import-Package: org.eclipse.cdt.utils.pty;mandatory:=native,
|
||||
|
|
|
@ -16,8 +16,12 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.io.StreamTokenizer;
|
||||
import java.io.StringReader;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.cdt.utils.pty.PTY;
|
||||
import org.eclipse.cdt.utils.spawner.ProcessFactory;
|
||||
|
@ -32,6 +36,7 @@ import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore;
|
|||
import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.NullSettingsStore;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.TerminalState;
|
||||
import org.eclipse.tm.terminal.connector.process.activator.UIPlugin;
|
||||
import org.eclipse.tm.terminal.connector.process.nls.Messages;
|
||||
import org.eclipse.tm.terminal.view.core.interfaces.constants.ILineSeparatorConstants;
|
||||
import org.eclipse.tm.terminal.view.core.utils.Env;
|
||||
|
@ -296,4 +301,20 @@ public class ProcessConnector extends AbstractStreamsConnector {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.8
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getWorkingDirectory() {
|
||||
long pid = process.pid();
|
||||
try {
|
||||
if (Platform.getOS().equals(Platform.OS_LINUX)) {
|
||||
Path procCwd = Files.readSymbolicLink(FileSystems.getDefault().getPath("/proc/" + pid + "/cwd")); //$NON-NLS-1$//$NON-NLS-2$
|
||||
return Optional.of(procCwd.toAbsolutePath().toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
UIPlugin.log("Failed to obtain working directory of process id " + pid, e); //$NON-NLS-1$
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.connector.process.activator;
|
||||
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.jface.resource.ImageRegistry;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
|
@ -103,4 +105,13 @@ public class UIPlugin extends AbstractUIPlugin {
|
|||
public static ImageDescriptor getImageDescriptor(String key) {
|
||||
return getDefault().getImageRegistry().getDescriptor(key);
|
||||
}
|
||||
|
||||
public static void log(String msg, Throwable e) {
|
||||
log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, msg, e));
|
||||
}
|
||||
|
||||
public static void log(IStatus status) {
|
||||
getDefault().getLog().log(status);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
org.eclipse.tm.terminal.control/debug/log = false
|
||||
org.eclipse.tm.terminal.control/debug/log/char = false
|
||||
org.eclipse.tm.terminal.control/debug/log/VT100Backend = false
|
||||
org.eclipse.tm.terminal.control/debug/log/hover = false
|
||||
|
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.tm.terminal.control; singleton:=true
|
||||
Bundle-Version: 5.1.0.qualifier
|
||||
Bundle-Version: 5.2.0.qualifier
|
||||
Bundle-Activator: org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin
|
||||
Bundle-Vendor: %providerName
|
||||
Bundle-Localization: plugin
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.eclipse.tm.internal.terminal.connector;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
|
@ -260,4 +261,12 @@ public class TerminalConnector implements ITerminalConnector {
|
|||
// maybe we have to be adapted....
|
||||
return Platform.getAdapterManager().getAdapter(this, adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getWorkingDirectory() {
|
||||
if (fConnector != null) {
|
||||
return fConnector.getWorkingDirectory();
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly;
|
|||
/**
|
||||
* Terminal specific version of {@link org.eclipse.swt.events.MouseListener}
|
||||
* @since 4.1
|
||||
* @see ITerminalMouseListener2
|
||||
*/
|
||||
public interface ITerminalMouseListener {
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2021 Kichwa Coders Canada Inc. and others.
|
||||
* This program and the accompanying materials are made available under the terms
|
||||
* of the Eclipse Public License 2.0 which accompanies this distribution, and is
|
||||
* available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.control;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly;
|
||||
|
||||
/**
|
||||
* Extension of {@link ITerminalMouseListener} for consumers that need the stateMask for a button mouse action.
|
||||
*
|
||||
* If ITerminalMouseListener2 is used, the methods in ITerminalMouseListener will not be called.
|
||||
*
|
||||
* @since 5.2
|
||||
* @see ITerminalMouseListener
|
||||
*/
|
||||
public interface ITerminalMouseListener2 extends ITerminalMouseListener {
|
||||
/**
|
||||
* Invoked when a double-click has happend inside the terminal control.<br>
|
||||
* <br>
|
||||
* <strong>Important:</strong> the event fires for every click, even outside the text region.
|
||||
* @param terminalText a read-only view of the current terminal text
|
||||
* @param button see {@link org.eclipse.swt.events.MouseEvent#button} for the meaning of the button values
|
||||
* @param stateMask see {@link org.eclipse.swt.events.MouseEvent#stateMask} for the meaning of the values
|
||||
*/
|
||||
default void mouseDoubleClick(ITerminalTextDataReadOnly terminalText, int line, int column, int button,
|
||||
int stateMask) {
|
||||
// do nothing by default so that implementors only need to implement methods they care about
|
||||
}
|
||||
|
||||
@Override
|
||||
default void mouseDoubleClick(ITerminalTextDataReadOnly terminalText, int line, int column, int button) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when a mouse button is pushed down inside the terminal control.<br>
|
||||
* <br>
|
||||
* <strong>Important:</strong> the event fires for every mouse down, even outside the text region.
|
||||
* @param terminalText a read-only view of the current terminal text
|
||||
* @param button see {@link org.eclipse.swt.events.MouseEvent#button} for the meaning of the button values
|
||||
* @param stateMask see {@link org.eclipse.swt.events.MouseEvent#stateMask} for the meaning of the values
|
||||
*/
|
||||
default void mouseDown(ITerminalTextDataReadOnly terminalText, int line, int column, int button, int stateMask) {
|
||||
// do nothing by default so that implementors only need to implement methods they care about
|
||||
}
|
||||
|
||||
@Override
|
||||
default void mouseDown(ITerminalTextDataReadOnly terminalText, int line, int column, int button) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when a mouse button is released inside the terminal control.<br>
|
||||
* <br>
|
||||
* <strong>Important:</strong> the event fires for every mouse up, even outside the text region.
|
||||
* @param terminalText a read-only view of the current terminal text
|
||||
* @param button see {@link org.eclipse.swt.events.MouseEvent#button} for the meaning of the button values
|
||||
* @param stateMask see {@link org.eclipse.swt.events.MouseEvent#stateMask} for the meaning of the values
|
||||
*/
|
||||
default void mouseUp(ITerminalTextDataReadOnly terminalText, int line, int column, int button, int stateMask) {
|
||||
// do nothing by default so that implementors only need to implement methods they care about
|
||||
}
|
||||
|
||||
@Override
|
||||
default void mouseUp(ITerminalTextDataReadOnly terminalText, int line, int column, int button) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -159,11 +159,13 @@ public interface ITerminalViewControl {
|
|||
|
||||
/**
|
||||
* @since 4.1
|
||||
* @param listener may be a {@link ITerminalMouseListener2} for extra callbacks
|
||||
*/
|
||||
void addMouseListener(ITerminalMouseListener listener);
|
||||
|
||||
/**
|
||||
* @since 4.1
|
||||
* @param listener may be a {@link ITerminalMouseListener2} for extra callbacks
|
||||
*/
|
||||
void removeMouseListener(ITerminalMouseListener listener);
|
||||
|
||||
|
@ -171,4 +173,9 @@ public interface ITerminalViewControl {
|
|||
* @since 5.1
|
||||
*/
|
||||
void setTerminalTitle(String newTitle);
|
||||
|
||||
/**
|
||||
* @since 5.2
|
||||
*/
|
||||
String getHoverSelection();
|
||||
}
|
||||
|
|
|
@ -1405,4 +1405,9 @@ public class VT100TerminalControl implements ITerminalControlForText, ITerminalC
|
|||
getCtlText().removeTerminalMouseListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHoverSelection() {
|
||||
return fCtlText.getHoverSelection();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.eclipse.tm.internal.terminal.provisional.api;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.tm.internal.terminal.control.ITerminalViewControl;
|
||||
|
@ -146,4 +147,12 @@ public interface ITerminalConnector extends IAdaptable {
|
|||
*/
|
||||
String getSettingsSummary();
|
||||
|
||||
/**
|
||||
* @return An optional with the absolute path if available of the current working dir, empty otherwise.
|
||||
* @since 5.2
|
||||
*/
|
||||
default Optional<String> getWorkingDirectory() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,14 +47,17 @@ public final class Logger {
|
|||
public static final String TRACE_DEBUG_LOG = "org.eclipse.tm.terminal.control/debug/log"; //$NON-NLS-1$
|
||||
public static final String TRACE_DEBUG_LOG_CHAR = "org.eclipse.tm.terminal.control/debug/log/char"; //$NON-NLS-1$
|
||||
public static final String TRACE_DEBUG_LOG_VT100BACKEND = "org.eclipse.tm.terminal.control/debug/log/VT100Backend"; //$NON-NLS-1$
|
||||
/** @since 5.2 */
|
||||
public static final String TRACE_DEBUG_LOG_HOVER = "org.eclipse.tm.terminal.control/debug/log/hover"; //$NON-NLS-1$
|
||||
|
||||
private static PrintStream logStream;
|
||||
|
||||
static {
|
||||
// Any of the three known debugging options turns on the creation of the log file
|
||||
// Any of the known debugging options turns on the creation of the log file
|
||||
boolean createLogFile = TerminalPlugin.isOptionEnabled(TRACE_DEBUG_LOG)
|
||||
|| TerminalPlugin.isOptionEnabled(TRACE_DEBUG_LOG_CHAR)
|
||||
|| TerminalPlugin.isOptionEnabled(TRACE_DEBUG_LOG_VT100BACKEND);
|
||||
|| TerminalPlugin.isOptionEnabled(TRACE_DEBUG_LOG_VT100BACKEND)
|
||||
|| TerminalPlugin.isOptionEnabled(TRACE_DEBUG_LOG_HOVER);
|
||||
|
||||
// Log only if tracing is enabled
|
||||
if (createLogFile && TerminalPlugin.getDefault() != null) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package org.eclipse.tm.internal.terminal.provisional.api.provider;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl;
|
||||
|
@ -151,4 +152,12 @@ public abstract class TerminalConnectorImpl {
|
|||
*/
|
||||
public void setTerminalSize(int newWidth, int newHeight) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.2
|
||||
*/
|
||||
public Optional<String> getWorkingDirectory() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,10 +19,14 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.Logger;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
import org.eclipse.tm.terminal.model.TextRange;
|
||||
|
||||
abstract public class AbstractTextCanvasModel implements ITextCanvasModel {
|
||||
private static final boolean DEBUG_HOVER = TerminalPlugin.isOptionEnabled(Logger.TRACE_DEBUG_LOG_HOVER);
|
||||
protected List<ITextCanvasModelListener> fListeners = new ArrayList<>();
|
||||
private int fCursorLine;
|
||||
private int fCursorColumn;
|
||||
|
@ -45,6 +49,8 @@ abstract public class AbstractTextCanvasModel implements ITextCanvasModel {
|
|||
boolean fInUpdate;
|
||||
private int fCols;
|
||||
|
||||
private TextRange fHoverRange = TextRange.EMPTY;
|
||||
|
||||
public AbstractTextCanvasModel(ITerminalTextDataSnapshot snapshot) {
|
||||
fSnapshot = snapshot;
|
||||
fLines = fSnapshot.getHeight();
|
||||
|
@ -309,6 +315,98 @@ abstract public class AbstractTextCanvasModel implements ITextCanvasModel {
|
|||
return fCurrentSelection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasHoverSelection(int line) {
|
||||
if (fHoverRange.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return fHoverRange.contains(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getHoverSelectionStart() {
|
||||
if (!fHoverRange.isEmpty()) {
|
||||
return fHoverRange.getStart();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getHoverSelectionEnd() {
|
||||
// Note - to match behaviour of getSelectionEnd this method
|
||||
// returns the inclusive end. As the fHoverRange is exclusive
|
||||
// we need to decrement the end positions before returning them.
|
||||
if (!fHoverRange.isEmpty()) {
|
||||
Point end = fHoverRange.getEnd();
|
||||
end.x--;
|
||||
end.y--;
|
||||
return end;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expandHoverSelectionAt(final int line, final int col) {
|
||||
if (fHoverRange.contains(col, line)) {
|
||||
// position is inside current hover range -> no change
|
||||
return;
|
||||
}
|
||||
fHoverRange = TextRange.EMPTY;
|
||||
if (line < 0 || line > fSnapshot.getHeight() || col < 0) {
|
||||
return;
|
||||
}
|
||||
int row1 = line;
|
||||
int row2 = line;
|
||||
while (row1 > 0 && fSnapshot.isWrappedLine(row1 - 1))
|
||||
row1--;
|
||||
while (row2 < fSnapshot.getHeight() && fSnapshot.isWrappedLine(row2))
|
||||
row2++;
|
||||
row2++;
|
||||
String lineText = ""; //$NON-NLS-1$
|
||||
for (int l = row1; l < row2; l++) {
|
||||
char[] chars = fSnapshot.getChars(l);
|
||||
if (chars == null)
|
||||
return;
|
||||
lineText += String.valueOf(chars);
|
||||
}
|
||||
int width = fSnapshot.getWidth();
|
||||
int col1 = col + (line - row1) * width;
|
||||
if (lineText.length() <= col1 || isBoundaryChar(lineText.charAt(col1))) {
|
||||
return;
|
||||
}
|
||||
int wordStart = 0;
|
||||
int wordEnd = lineText.length();
|
||||
for (int c = col1; c >= 1; c--) {
|
||||
if (isBoundaryChar(lineText.charAt(c - 1))) {
|
||||
wordStart = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int c = col1; c < lineText.length(); c++) {
|
||||
if (isBoundaryChar(lineText.charAt(c))) {
|
||||
wordEnd = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (wordStart < wordEnd) {
|
||||
fHoverRange = new TextRange(row1 + wordStart / width, row1 + (wordEnd - 1) / width + 1, (wordStart % width),
|
||||
(wordEnd - 1) % width + 1, lineText.substring(wordStart, wordEnd));
|
||||
if (DEBUG_HOVER) {
|
||||
System.out.format("hover: %s <- [%s,%s][%s,%s]\n", //$NON-NLS-1$
|
||||
fHoverRange, col, line, wordStart, wordEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHoverSelectionText() {
|
||||
return fHoverRange.text;
|
||||
}
|
||||
|
||||
private boolean isBoundaryChar(char c) {
|
||||
return Character.isWhitespace(c) || (c < '\u0020') || c == '"' || c == '\'';
|
||||
}
|
||||
|
||||
// helper to sanitize text copied out of a snapshot
|
||||
private static String scrubLine(String text) {
|
||||
// get rid of the empty space at the end of the lines
|
||||
|
|
|
@ -90,6 +90,45 @@ public interface ITextCanvasModel {
|
|||
|
||||
String getSelectedText();
|
||||
|
||||
/**
|
||||
* Expand the hover selection to the word at the given position.
|
||||
*
|
||||
* @param line line
|
||||
* @param col column
|
||||
*/
|
||||
void expandHoverSelectionAt(int line, int col);
|
||||
|
||||
/**
|
||||
* @param line
|
||||
* @return true if line is part of the hover selection
|
||||
*/
|
||||
boolean hasHoverSelection(int line);
|
||||
|
||||
/**
|
||||
* Get the text of the current hover selection.
|
||||
*
|
||||
* @return the hover selection text, never null.
|
||||
*/
|
||||
String getHoverSelectionText();
|
||||
|
||||
/**
|
||||
* Get the start of the hover selection.
|
||||
*
|
||||
* @return the start of the hover selection or null if nothing is selected
|
||||
* {@link Point#x} is the column and {@link Point#y} is the line.
|
||||
* Returns non-null if {@link #hasHoverSelection(int)} returns true
|
||||
*/
|
||||
Point getHoverSelectionStart();
|
||||
|
||||
/**
|
||||
* Get the end of the hover selection (inclusive).
|
||||
*
|
||||
* @return the end of the hover selection or null if nothing is selected
|
||||
* {@link Point#x} is the column and {@link Point#y} is the line.
|
||||
* Returns non-null if {@link #hasHoverSelection(int)} returns true
|
||||
*/
|
||||
Point getHoverSelectionEnd();
|
||||
|
||||
/**
|
||||
* Collect and return all text present in the model.
|
||||
*
|
||||
|
@ -100,4 +139,5 @@ public interface ITextCanvasModel {
|
|||
* @since 4.4
|
||||
*/
|
||||
String getAllText();
|
||||
|
||||
}
|
|
@ -43,6 +43,7 @@ import org.eclipse.swt.graphics.RGB;
|
|||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.tm.internal.terminal.control.ITerminalMouseListener;
|
||||
import org.eclipse.tm.internal.terminal.control.ITerminalMouseListener2;
|
||||
import org.eclipse.tm.terminal.model.TerminalColor;
|
||||
|
||||
/**
|
||||
|
@ -146,7 +147,13 @@ public class TextCanvas extends GridCanvas {
|
|||
Point pt = screenPointToCell(e.x, e.y);
|
||||
if (pt != null) {
|
||||
for (ITerminalMouseListener l : fMouseListeners) {
|
||||
l.mouseDoubleClick(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button);
|
||||
if (l instanceof ITerminalMouseListener2) {
|
||||
ITerminalMouseListener2 l2 = (ITerminalMouseListener2) l;
|
||||
l2.mouseDoubleClick(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button,
|
||||
e.stateMask);
|
||||
} else {
|
||||
l.mouseDoubleClick(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +177,12 @@ public class TextCanvas extends GridCanvas {
|
|||
Point pt = screenPointToCell(e.x, e.y);
|
||||
if (pt != null) {
|
||||
for (ITerminalMouseListener l : fMouseListeners) {
|
||||
l.mouseDown(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button);
|
||||
if (l instanceof ITerminalMouseListener2) {
|
||||
ITerminalMouseListener2 l2 = (ITerminalMouseListener2) l;
|
||||
l2.mouseDown(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button, e.stateMask);
|
||||
} else {
|
||||
l.mouseDown(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +202,12 @@ public class TextCanvas extends GridCanvas {
|
|||
Point pt = screenPointToCell(e.x, e.y);
|
||||
if (pt != null) {
|
||||
for (ITerminalMouseListener l : fMouseListeners) {
|
||||
l.mouseUp(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button);
|
||||
if (l instanceof ITerminalMouseListener2) {
|
||||
ITerminalMouseListener2 l2 = (ITerminalMouseListener2) l;
|
||||
l2.mouseUp(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button, e.stateMask);
|
||||
} else {
|
||||
l.mouseUp(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +217,15 @@ public class TextCanvas extends GridCanvas {
|
|||
if (fDraggingStart != null) {
|
||||
updateHasSelection(e);
|
||||
setSelection(screenPointToCell(e.x, e.y));
|
||||
fCellCanvasModel.expandHoverSelectionAt(-1, -1);
|
||||
} else if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.MOD1) {
|
||||
// highlight (underline) word that would be used by MOD1 + mouse click
|
||||
Point pt = screenPointToCell(e.x, e.y);
|
||||
fCellCanvasModel.expandHoverSelectionAt(pt.y, pt.x);
|
||||
} else {
|
||||
fCellCanvasModel.expandHoverSelectionAt(-1, -1);
|
||||
}
|
||||
redraw();
|
||||
});
|
||||
serVerticalBarVisible(true);
|
||||
setHorizontalBarVisible(false);
|
||||
|
@ -540,4 +565,8 @@ public class TextCanvas extends GridCanvas {
|
|||
fMouseListeners.remove(listener);
|
||||
}
|
||||
|
||||
public String getHoverSelection() {
|
||||
return fCellCanvasModel.getHoverSelectionText();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.eclipse.swt.graphics.Image;
|
|||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.Logger;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly;
|
||||
import org.eclipse.tm.terminal.model.LineSegment;
|
||||
import org.eclipse.tm.terminal.model.TerminalColor;
|
||||
|
@ -35,6 +37,7 @@ import org.eclipse.tm.terminal.model.TerminalStyle;
|
|||
*
|
||||
*/
|
||||
public class TextLineRenderer implements ILinelRenderer {
|
||||
private static final boolean DEBUG_HOVER = TerminalPlugin.isOptionEnabled(Logger.TRACE_DEBUG_LOG_HOVER);
|
||||
private final ITextCanvasModel fModel;
|
||||
private final StyleMap fStyleMap;
|
||||
|
||||
|
@ -76,6 +79,20 @@ public class TextLineRenderer implements ILinelRenderer {
|
|||
drawText(doubleBufferGC, 0, 0, colFirst, segment.getColumn(), text);
|
||||
drawCursor(model, doubleBufferGC, line, 0, 0, colFirst);
|
||||
}
|
||||
if (fModel.hasHoverSelection(line)) {
|
||||
if (DEBUG_HOVER) {
|
||||
System.out.format("hover: %s contains hover selection\n", line); //$NON-NLS-1$
|
||||
}
|
||||
Point hsStart = fModel.getHoverSelectionStart();
|
||||
Point hsEnd = fModel.getHoverSelectionEnd();
|
||||
int colStart = line == hsStart.y ? hsStart.x : 0;
|
||||
int colEnd = line == hsEnd.y ? hsEnd.x : getTerminalText().getWidth();
|
||||
if (colStart < colEnd) {
|
||||
RGB defaultFg = fStyleMap.getForegrondRGB(null);
|
||||
doubleBufferGC.setForeground(new Color(doubleBufferGC.getDevice(), defaultFg));
|
||||
drawUnderline(doubleBufferGC, colStart, colEnd);
|
||||
}
|
||||
}
|
||||
if (fModel.hasLineSelection(line)) {
|
||||
TerminalStyle style = TerminalStyle.getStyle(TerminalColor.SELECTION_FOREGROUND,
|
||||
TerminalColor.SELECTION_BACKGROUND);
|
||||
|
@ -168,6 +185,21 @@ public class TextLineRenderer implements ILinelRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param gc
|
||||
* @param colStart Starting text column to underline (inclusive)
|
||||
* @param colEnd Ending text column to underline (inclusive)
|
||||
*/
|
||||
private void drawUnderline(GC gc, int colStart, int colEnd) {
|
||||
int y = getCellHeight() - 1;
|
||||
int x = getCellWidth() * colStart;
|
||||
|
||||
// x2 is the right side of last column being underlined.
|
||||
int x2 = (colEnd + 1) * getCellWidth() - 1;
|
||||
gc.drawLine(x, y, x2, y);
|
||||
}
|
||||
|
||||
private void setupGC(GC gc, TerminalStyle style) {
|
||||
RGB foregrondColor = fStyleMap.getForegrondRGB(style);
|
||||
gc.setForeground(new Color(gc.getDevice(), foregrondColor));
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2021 Fabrizio Iannetti.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.tm.terminal.model;
|
||||
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
|
||||
/**
|
||||
* Represents a range of text in the terminal.
|
||||
* <p>
|
||||
* Used, for example, to store location of active hover
|
||||
*
|
||||
* @since 5.2
|
||||
*/
|
||||
public final class TextRange {
|
||||
public final int colStart;
|
||||
public final int colEnd;
|
||||
public final int rowStart;
|
||||
public final int rowEnd;
|
||||
public final String text;
|
||||
|
||||
public static final TextRange EMPTY = new TextRange(0, 0, 0, 0, ""); //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param rowStart start row
|
||||
* @param rowEnd end row
|
||||
* @param colStart start column (exclusive)
|
||||
* @param colEnd end column (exclusive)
|
||||
* @param text text in the range
|
||||
*/
|
||||
public TextRange(int rowStart, int rowEnd, int colStart, int colEnd, String text) {
|
||||
super();
|
||||
this.colStart = colStart;
|
||||
this.colEnd = colEnd;
|
||||
this.rowStart = rowStart;
|
||||
this.rowEnd = rowEnd;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public boolean contains(int col, int row) {
|
||||
int colStartInrow = row == rowStart ? colStart : 0;
|
||||
int colEndInRow = row == rowEnd - 1 ? colEnd : col + 1;
|
||||
return col >= colStartInrow && col < colEndInRow && row >= rowStart && row < rowEnd;
|
||||
}
|
||||
|
||||
public boolean contains(int line) {
|
||||
return line >= rowStart && line < rowEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the range represents a non-empty (non-zero) amount of text
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return !(colEnd > colStart || rowEnd > rowStart);
|
||||
}
|
||||
|
||||
public Point getStart() {
|
||||
return new Point(colStart, rowStart);
|
||||
}
|
||||
|
||||
public Point getEnd() {
|
||||
return new Point(colEnd, rowEnd);
|
||||
}
|
||||
|
||||
public int getColStart() {
|
||||
return colStart;
|
||||
}
|
||||
|
||||
public int getColEnd() {
|
||||
return colEnd;
|
||||
}
|
||||
|
||||
public int getRowStart() {
|
||||
return rowStart;
|
||||
}
|
||||
|
||||
public int getRowEnd() {
|
||||
return rowEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("TextRange (%s,%s)-(%s,%s)-'%s'", //$NON-NLS-1$
|
||||
colStart, rowStart, colEnd, rowEnd, text);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.tm.terminal.view.ui;singleton:=true
|
||||
Bundle-Version: 4.8.0.qualifier
|
||||
Bundle-Version: 4.8.100.qualifier
|
||||
Bundle-Activator: org.eclipse.tm.terminal.view.ui.activator.UIPlugin
|
||||
Bundle-Vendor: %providerName
|
||||
Require-Bundle: org.eclipse.core.expressions;bundle-version="3.4.400",
|
||||
|
@ -13,7 +13,10 @@ Require-Bundle: org.eclipse.core.expressions;bundle-version="3.4.400",
|
|||
org.eclipse.egit.ui;bundle-version="2.0.0";resolution:=optional,
|
||||
org.eclipse.tm.terminal.view.core;bundle-version="4.5.0",
|
||||
org.eclipse.tm.terminal.control;bundle-version="4.5.0",
|
||||
org.eclipse.ui;bundle-version="3.8.0"
|
||||
org.eclipse.ui;bundle-version="3.8.0",
|
||||
org.eclipse.ui.ide;bundle-version="3.18.0";resolution:=optional,
|
||||
org.eclipse.ui.editors;bundle-version="3.14.0";resolution:=optional,
|
||||
org.eclipse.text;bundle-version="3.11.0";resolution:=optional
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-11
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Localization: plugin
|
||||
|
|
|
@ -16,6 +16,9 @@ import java.net.URL;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.jface.resource.ImageRegistry;
|
||||
import org.eclipse.swt.custom.CTabFolder;
|
||||
|
@ -253,4 +256,21 @@ public class UIPlugin extends AbstractUIPlugin {
|
|||
public static ImageDescriptor getImageDescriptor(String key) {
|
||||
return getDefault().getImageRegistry().getDescriptor(key);
|
||||
}
|
||||
|
||||
public static void log(String msg, Throwable e) {
|
||||
log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, msg, e));
|
||||
}
|
||||
|
||||
public static void log(IStatus status) {
|
||||
getDefault().getLog().log(status);
|
||||
}
|
||||
|
||||
public static boolean isOptionEnabled(String strOption) {
|
||||
String strEnabled = Platform.getDebugOption(strOption);
|
||||
if (strEnabled == null)
|
||||
return false;
|
||||
|
||||
return Boolean.parseBoolean(strEnabled);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,271 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2021 Fabrizio Iannetti.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.view.ui.tabs;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.core.commands.ExecutionException;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.Adapters;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.window.Window;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.tm.internal.terminal.control.ITerminalMouseListener2;
|
||||
import org.eclipse.tm.internal.terminal.control.ITerminalViewControl;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.Logger;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly;
|
||||
import org.eclipse.tm.terminal.view.ui.activator.UIPlugin;
|
||||
import org.eclipse.ui.IEditorInput;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IWorkbenchPage;
|
||||
import org.eclipse.ui.IWorkbenchPartSite;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PartInitException;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.ide.IDE;
|
||||
import org.eclipse.ui.internal.ide.dialogs.OpenResourceDialog;
|
||||
import org.eclipse.ui.texteditor.IDocumentProvider;
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* @noreference This class is not intended to be referenced by clients.
|
||||
*/
|
||||
public class OpenFileMouseHandler implements ITerminalMouseListener2 {
|
||||
private static final boolean DEBUG_HOVER = UIPlugin.isOptionEnabled(Logger.TRACE_DEBUG_LOG_HOVER);
|
||||
private static final List<String> NEEDED_BUNDLES = //
|
||||
List.of("org.eclipse.core.resources", //$NON-NLS-1$
|
||||
"org.eclipse.ui.ide", //$NON-NLS-1$
|
||||
"org.eclipse.ui.editors", //$NON-NLS-1$
|
||||
"org.eclipse.text"); //$NON-NLS-1$
|
||||
|
||||
private final ITerminalViewControl terminal;
|
||||
private Pattern regex = Pattern.compile("(\\d*)(:(\\d*))?.*"); //$NON-NLS-1$
|
||||
private IWorkbenchPartSite site;
|
||||
|
||||
/**
|
||||
* Check if we have the bundles needed.
|
||||
*/
|
||||
private boolean neededBundlesAvailable;
|
||||
|
||||
OpenFileMouseHandler(IWorkbenchPartSite site, ITerminalViewControl terminal) {
|
||||
this.site = site;
|
||||
this.terminal = terminal;
|
||||
neededBundlesAvailable = true;
|
||||
for (String bundleName : NEEDED_BUNDLES) {
|
||||
if (!bundleAvailable(bundleName)) {
|
||||
this.neededBundlesAvailable = false;
|
||||
if (DEBUG_HOVER) {
|
||||
System.out.format(
|
||||
"hover: the %s bundle is not present, therefore full ctrl-click functionality is not available\n", //$NON-NLS-1$
|
||||
bundleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (neededBundlesAvailable && DEBUG_HOVER) {
|
||||
System.out.format("hover: the bundles needed for full ctrl-click functionality are available\n"); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp(ITerminalTextDataReadOnly terminalText, int line, int column, int button, int stateMask) {
|
||||
if ((stateMask & SWT.MODIFIER_MASK) != SWT.MOD1) {
|
||||
// Only handle Ctrl-click
|
||||
return;
|
||||
}
|
||||
String textToOpen = terminal.getHoverSelection();
|
||||
String lineAndCol = null;
|
||||
if (textToOpen.length() > 0) {
|
||||
try {
|
||||
// if the selection looks like a web URL, open using the browser
|
||||
if (textToOpen.startsWith("http://") || textToOpen.startsWith("https://")) { //$NON-NLS-1$//$NON-NLS-2$
|
||||
try {
|
||||
PlatformUI.getWorkbench().getBrowserSupport().createBrowser(null).openURL(new URL(textToOpen));
|
||||
return;
|
||||
} catch (MalformedURLException e) {
|
||||
// not a valid URL, continue
|
||||
}
|
||||
}
|
||||
|
||||
// After this we need Eclipse IDE features. If we don't have them then we stop here.
|
||||
if (!neededBundlesAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// extract the path from file:// URLs
|
||||
if (textToOpen.startsWith("file://")) { //$NON-NLS-1$
|
||||
textToOpen = textToOpen.substring(7);
|
||||
}
|
||||
// remove optional position info name:[row[:col]]
|
||||
{
|
||||
int startOfRowCol = textToOpen.indexOf(':');
|
||||
if (startOfRowCol == 1 && textToOpen.length() > 2) {
|
||||
// assume this is the device separator on Windows
|
||||
startOfRowCol = textToOpen.indexOf(':', startOfRowCol + 1);
|
||||
}
|
||||
if (startOfRowCol >= 0) {
|
||||
lineAndCol = textToOpen.substring(startOfRowCol + 1);
|
||||
textToOpen = textToOpen.substring(0, startOfRowCol);
|
||||
}
|
||||
}
|
||||
Optional<String> fullPath = Optional.empty();
|
||||
if (!textToOpen.startsWith("/")) { //$NON-NLS-1$
|
||||
// relative path: try to append to the working directory
|
||||
Optional<String> workingDirectory = terminal.getTerminalConnector().getWorkingDirectory();
|
||||
if (workingDirectory.isPresent()) {
|
||||
fullPath = Optional.of(workingDirectory.get() + "/" + textToOpen);
|
||||
}
|
||||
}
|
||||
// if the selection is a file location that maps to a resource
|
||||
// open the resource
|
||||
IFile fileForLocation = ResourcesPlugin.getWorkspace().getRoot()
|
||||
.getFileForLocation(new Path(fullPath.orElse(textToOpen)));
|
||||
if (fileForLocation != null && fileForLocation.exists()) {
|
||||
IEditorPart editor = IDE.openEditor(
|
||||
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), fileForLocation,
|
||||
true);
|
||||
goToLine(lineAndCol, editor);
|
||||
return;
|
||||
}
|
||||
// try an external file, if it exists
|
||||
File file = new File(fullPath.orElse(textToOpen));
|
||||
if (file.exists() && !file.isDirectory()) {
|
||||
try {
|
||||
IEditorPart editor = IDE.openEditor(site.getPage(), file.toURI(),
|
||||
IDE.getEditorDescriptor(file.getName(), true, true).getId(), true);
|
||||
goToLine(lineAndCol, editor);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
OpenResourceDialog openResourceDialog = new OpenResourceDialog(site.getShell(),
|
||||
ResourcesPlugin.getPlugin().getWorkspace().getRoot(), IResource.FILE);
|
||||
openResourceDialog.setInitialPattern(textToOpen);
|
||||
if (openResourceDialog.open() != Window.OK)
|
||||
return;
|
||||
Object[] results = openResourceDialog.getResult();
|
||||
List<IFile> files = new ArrayList<>();
|
||||
for (Object result : results) {
|
||||
if (result instanceof IFile) {
|
||||
files.add((IFile) result);
|
||||
}
|
||||
}
|
||||
if (files.size() > 0) {
|
||||
|
||||
final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
|
||||
if (window == null) {
|
||||
throw new ExecutionException("no active workbench window"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
final IWorkbenchPage page = window.getActivePage();
|
||||
if (page == null) {
|
||||
throw new ExecutionException("no active workbench page"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
try {
|
||||
for (IFile iFile : files) {
|
||||
IEditorPart editor = IDE.openEditor(page, iFile, true);
|
||||
goToLine(lineAndCol, editor);
|
||||
}
|
||||
} catch (final PartInitException e) {
|
||||
throw new ExecutionException("error opening file in editor", e); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException | NullPointerException | ExecutionException | PartInitException e) {
|
||||
UIPlugin.log("Failed to activate OpenResourceDialog", e); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean bundleAvailable(String symbolicName) {
|
||||
Bundle bundle = Platform.getBundle(symbolicName);
|
||||
boolean available = bundle != null && bundle.getState() != Bundle.UNINSTALLED
|
||||
&& bundle.getState() != Bundle.STOPPING;
|
||||
return available;
|
||||
}
|
||||
|
||||
private void goToLine(String lineAndCol, IEditorPart editor) {
|
||||
ITextEditor textEditor = Adapters.adapt(editor, ITextEditor.class);
|
||||
if (textEditor != null) {
|
||||
Optional<Integer> optionalOffset = getRegionFromLineAndCol(textEditor, lineAndCol);
|
||||
optionalOffset.ifPresent(offset -> textEditor.selectAndReveal(offset, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line information for the given line in the given editor
|
||||
*/
|
||||
private Optional<Integer> getRegionFromLineAndCol(ITextEditor editor, String lineAndCol) {
|
||||
if (lineAndCol == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Matcher matcher = regex.matcher(lineAndCol);
|
||||
if (!matcher.matches()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
String lineStr = matcher.group(1);
|
||||
String colStr = matcher.group(3);
|
||||
int line;
|
||||
int col = 0;
|
||||
try {
|
||||
line = Integer.parseInt(lineStr);
|
||||
} catch (NumberFormatException e1) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
col = Integer.parseInt(colStr);
|
||||
} catch (NumberFormatException e1) {
|
||||
// if we can't get a column, go to the line alone
|
||||
}
|
||||
IDocumentProvider provider = editor.getDocumentProvider();
|
||||
IEditorInput input = editor.getEditorInput();
|
||||
try {
|
||||
provider.connect(input);
|
||||
} catch (CoreException e) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
IDocument document = provider.getDocument(input);
|
||||
if (document != null && line > 0) {
|
||||
// document's lines are 0-offset
|
||||
line = line - 1;
|
||||
int lineOffset = document.getLineOffset(line);
|
||||
if (col > 0) {
|
||||
int lineLength = document.getLineLength(line);
|
||||
if (col < lineLength) {
|
||||
lineOffset += col;
|
||||
}
|
||||
}
|
||||
return Optional.of(lineOffset);
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
} finally {
|
||||
provider.disconnect(input);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
|
@ -271,6 +271,10 @@ public class TabFolderManager extends PlatformObject implements ISelectionProvid
|
|||
|
||||
// Add middle mouse button paste support
|
||||
addMiddleMouseButtonPasteSupport(terminal);
|
||||
|
||||
// add support to open resource on ctrl/meta + mouse click
|
||||
addOpenResourceSupport(terminal);
|
||||
|
||||
// Add the "selection" listener to the terminal control
|
||||
new TerminalControlSelectionListener(terminal);
|
||||
// Configure the terminal encoding
|
||||
|
@ -328,6 +332,10 @@ public class TabFolderManager extends PlatformObject implements ISelectionProvid
|
|||
return item;
|
||||
}
|
||||
|
||||
private void addOpenResourceSupport(ITerminalViewControl terminal) {
|
||||
terminal.addMouseListener(new OpenFileMouseHandler(getParentView().getSite(), terminal));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for DnD of terminal tab items between terminal views
|
||||
* <p>
|
||||
|
|
Loading…
Add table
Reference in a new issue