Skip to content

Commit 95b502a

Browse files
Philipp0205laeubi
authored andcommitted
Implement word and line selection modes in TextCanvas
Changes from review. - Removed unnecessary null check - Added missing brackets - Smaller changes Fixed compile error.
1 parent 4947706 commit 95b502a

File tree

2 files changed

+157
-9
lines changed

2 files changed

+157
-9
lines changed

terminal/bundles/org.eclipse.terminal.control/src/org/eclipse/terminal/internal/textcanvas/TextCanvas.java

Lines changed: 156 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* Martin Oberhuber (Wind River) - [265352][api] Allow setting fonts programmatically
2121
* Anton Leherbauer (Wind River) - [434749] UnhandledEventLoopException when copying to clipboard while the selection is empty
2222
* Davy Landman (CWI) - [475267][api] Allow custom mouse listeners
23+
* Philipp Kurrle (Advantest) - [2131] Implement word and line selection
2324
*******************************************************************************/
2425
package org.eclipse.terminal.internal.textcanvas;
2526

@@ -43,6 +44,7 @@
4344
import org.eclipse.swt.graphics.Rectangle;
4445
import org.eclipse.swt.widgets.Composite;
4546
import org.eclipse.terminal.control.ITerminalMouseListener;
47+
import org.eclipse.terminal.model.ITerminalTextDataReadOnly;
4648
import org.eclipse.terminal.model.TerminalColor;
4749

4850
/**
@@ -60,6 +62,11 @@ public class TextCanvas extends GridCanvas {
6062
private boolean fHasSelection;
6163
private ResizeListener fResizeListener;
6264
private final List<ITerminalMouseListener> fMouseListeners;
65+
private SelectionMode fSelMode = SelectionMode.NONE;
66+
67+
private enum SelectionMode {
68+
NONE, DRAG, WORD, LINE
69+
}
6370

6471
// The minSize is meant to determine the minimum size of the backing store
6572
// (grid) into which remote data is rendered. If the viewport is smaller
@@ -151,13 +158,43 @@ public void mouseDoubleClick(MouseEvent e) {
151158
for (ITerminalMouseListener l : fMouseListeners) {
152159
l.mouseDoubleClick(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button, e.stateMask);
153160
}
161+
selectWord(pt);
154162
}
155163
}
156164
}
157165

166+
/**
167+
* Select the word at the given point.
168+
* If no word is detected, select the single character at the point.
169+
*
170+
* @param pt
171+
* the point in cell coordinates
172+
*/
173+
private void selectWord(Point pt) {
174+
fSelMode = SelectionMode.WORD;
175+
176+
fCellCanvasModel.expandHoverSelectionAt(pt.y, pt.x);
177+
Point start = fCellCanvasModel.getHoverSelectionStart();
178+
Point end = fCellCanvasModel.getHoverSelectionEnd();
179+
if (start != null && end != null) {
180+
fHasSelection = true;
181+
fDraggingStart = start; // anchor at word start for drag-extend by words
182+
fCellCanvasModel.setSelectionAnchor(start);
183+
fCellCanvasModel.setSelection(start.y, end.y, start.x, end.x);
184+
} else {
185+
fHasSelection = true;
186+
fDraggingStart = pt;
187+
fCellCanvasModel.setSelectionAnchor(pt);
188+
fCellCanvasModel.setSelection(pt.y, pt.y, pt.x, pt.x);
189+
}
190+
// clear hover highlight after using it
191+
fCellCanvasModel.expandHoverSelectionAt(-1, -1);
192+
}
193+
158194
@Override
159195
public void mouseDown(MouseEvent e) {
160196
if (e.button == 1) { // left button
197+
fSelMode = SelectionMode.DRAG;
161198
fDraggingStart = screenPointToCell(e.x, e.y);
162199
fHasSelection = false;
163200
if ((e.stateMask & SWT.SHIFT) != 0) {
@@ -178,18 +215,48 @@ public void mouseDown(MouseEvent e) {
178215
}
179216
}
180217
}
218+
if (e.count == 3) {
219+
selectLine(e);
220+
}
221+
}
222+
223+
private void selectLine(MouseEvent e) {
224+
fSelMode = SelectionMode.LINE;
225+
Point pt = screenPointToCell(e.x, e.y);
226+
if (pt != null) {
227+
ITerminalTextDataReadOnly term = fCellCanvasModel.getTerminalText();
228+
int row = Math.max(0, Math.min(pt.y, term.getHeight() - 1));
229+
int startCol = 0;
230+
int endCol = Math.max(0, term.getWidth() - 1); // inclusive end column
231+
Point start = new Point(startCol, row);
232+
Point end = new Point(endCol, row);
233+
fHasSelection = true;
234+
// keep anchor at the start of the clicked line for drag-extend by lines
235+
fDraggingStart = start;
236+
fCellCanvasModel.setSelectionAnchor(start);
237+
fCellCanvasModel.setSelection(start.y, end.y, start.x, end.x);
238+
// notify custom listeners
239+
if (fMouseListeners.size() > 0) {
240+
for (ITerminalMouseListener l : fMouseListeners) {
241+
l.mouseDown(term, pt.y, pt.x, e.button, e.stateMask);
242+
}
243+
}
244+
}
181245
}
182246

183247
@Override
184248
public void mouseUp(MouseEvent e) {
185249
if (e.button == 1) { // left button
186-
updateHasSelection(e);
187-
if (fHasSelection) {
188-
setSelection(screenPointToCell(e.x, e.y));
189-
} else {
190-
fCellCanvasModel.setSelection(-1, -1, -1, -1);
250+
if (fSelMode == SelectionMode.DRAG) {
251+
updateHasSelection(e);
252+
if (fHasSelection) {
253+
setSelection(screenPointToCell(e.x, e.y));
254+
} else {
255+
fCellCanvasModel.setSelection(-1, -1, -1, -1);
256+
}
191257
}
192258
fDraggingStart = null;
259+
fSelMode = SelectionMode.NONE;
193260
}
194261
if (fMouseListeners.size() > 0) {
195262
Point pt = screenPointToCell(e.x, e.y);
@@ -203,8 +270,20 @@ public void mouseUp(MouseEvent e) {
203270
});
204271
addMouseMoveListener(e -> {
205272
if (fDraggingStart != null) {
273+
Point curr = screenPointToCell(e.x, e.y);
206274
updateHasSelection(e);
207-
setSelection(screenPointToCell(e.x, e.y));
275+
switch (fSelMode) {
276+
case WORD:
277+
updateWordSelection(curr);
278+
break;
279+
case LINE:
280+
updateLineSelection(curr);
281+
break;
282+
case DRAG:
283+
default:
284+
setSelection(curr);
285+
break;
286+
}
208287
fCellCanvasModel.expandHoverSelectionAt(-1, -1);
209288
} else if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.MOD1) {
210289
// highlight (underline) word that would be used by MOD1 + mouse click
@@ -215,10 +294,80 @@ public void mouseUp(MouseEvent e) {
215294
}
216295
redraw();
217296
});
218-
setVerticalBarVisible(true);
297+
serVerticalBarVisible(true);
219298
setHorizontalBarVisible(false);
220299
}
221300

301+
private static class Range {
302+
final Point start;
303+
final Point end;
304+
305+
Range(Point start, Point end) {
306+
this.start = start;
307+
this.end = end;
308+
}
309+
310+
boolean isValid() {
311+
return start != null && end != null;
312+
}
313+
}
314+
315+
private Range wordRangeAt(Point pt) {
316+
fCellCanvasModel.expandHoverSelectionAt(pt.y, pt.x);
317+
return new Range(fCellCanvasModel.getHoverSelectionStart(), fCellCanvasModel.getHoverSelectionEnd());
318+
}
319+
320+
private void setNormalizedSelection(Point start, Point end) {
321+
if (start == null || end == null) {
322+
return;
323+
}
324+
325+
Point s = start;
326+
Point e = end;
327+
if (compare(e, s) < 0) { // normalize order
328+
s = end;
329+
e = start;
330+
}
331+
int sCol = Math.max(0, s.x);
332+
int sRow = Math.max(0, s.y);
333+
fCellCanvasModel.setSelection(sRow, e.y, sCol, e.x);
334+
}
335+
336+
private void updateWordSelection(Point curr) {
337+
if (fDraggingStart == null || curr == null) {
338+
return;
339+
}
340+
// Determine word boundaries at anchor and current positions
341+
342+
Range anchor = wordRangeAt(fDraggingStart);
343+
Range current = wordRangeAt(curr);
344+
if (!anchor.isValid() || !current.isValid()) {
345+
return;
346+
}
347+
348+
if (compare(current.start, anchor.start) < 0) {
349+
setNormalizedSelection(current.start, anchor.end);
350+
} else {
351+
setNormalizedSelection(anchor.start, current.end);
352+
}
353+
fHasSelection = true;
354+
// clear hover underline
355+
fCellCanvasModel.expandHoverSelectionAt(-1, -1);
356+
}
357+
358+
private void updateLineSelection(Point curr) {
359+
if (fDraggingStart == null || curr == null) {
360+
return;
361+
}
362+
ITerminalTextDataReadOnly term = fCellCanvasModel.getTerminalText();
363+
int startRow = Math.max(0, Math.min(fDraggingStart.y, curr.y));
364+
int endRow = Math.max(0, Math.max(fDraggingStart.y, curr.y));
365+
int endCol = Math.max(0, term.getWidth() - 1);
366+
setNormalizedSelection(new Point(0, startRow), new Point(endCol, endRow));
367+
fCellCanvasModel.setSelectionAnchor(new Point(0, fDraggingStart.y));
368+
fHasSelection = true;
369+
}
370+
222371
/**
223372
* The user has to drag the mouse to at least one character to make a selection.
224373
* Once this is done, even a one char selection is OK.
@@ -544,5 +693,4 @@ public void removeTerminalMouseListener(ITerminalMouseListener listener) {
544693
public String getHoverSelection() {
545694
return fCellCanvasModel.getHoverSelectionText();
546695
}
547-
548696
}

terminal/bundles/org.eclipse.terminal.control/src/org/eclipse/terminal/internal/textcanvas/VirtualCanvas.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ protected boolean isVertialBarVisible() {
335335
return getVerticalBar().isVisible();
336336
}
337337

338-
protected void setVerticalBarVisible(boolean showVScrollBar) {
338+
protected void serVerticalBarVisible(boolean showVScrollBar) {
339339
ScrollBar vertical = getVerticalBar();
340340
vertical.setVisible(showVScrollBar);
341341
vertical.setSelection(0);

0 commit comments

Comments
 (0)