diff --git a/Terminal.Gui/Event.cs b/Terminal.Gui/Event.cs
index a0ce2ef6a..8556a370b 100644
--- a/Terminal.Gui/Event.cs
+++ b/Terminal.Gui/Event.cs
@@ -38,6 +38,11 @@ namespace Terminal.Gui {
///
SpecialMask = 0xfff00000,
+ ///
+ /// The key code for the user pressing Control-spacebar
+ ///
+ ControlSpace = 0,
+
///
/// The key code for the user pressing Control-A
///
diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs
index 6a4df6661..0eac41b70 100644
--- a/Terminal.Gui/Views/TextView.cs
+++ b/Terminal.Gui/Views/TextView.cs
@@ -7,8 +7,6 @@
//
// TODO:
// Attributed text on spans
-// Render selection
-// Mark/Delete/Cut commands
// Replace insertion with Insert method
// String accumulation (Control-k, control-k is not preserving the last new line, see StringToRunes
//
@@ -63,7 +61,7 @@ namespace Terminal.Gui {
start = i + 1;
}
}
- if (i - start > 0)
+ if (i - start >= 0)
lines.Add (ToRunes (content [start, null]));
return lines;
}
@@ -138,8 +136,11 @@ namespace Terminal.Gui {
int leftColumn;
int currentRow;
int currentColumn;
- bool used;
+ int selectionStartColumn, selectionStartRow;
+ bool selecting;
+ //bool used;
+#if false
///
/// Changed event, raised when the text has clicked.
///
@@ -148,7 +149,7 @@ namespace Terminal.Gui {
/// raised when the text in the entry changes.
///
public event EventHandler Changed;
-
+#endif
///
/// Public constructor.
///
@@ -197,6 +198,12 @@ namespace Terminal.Gui {
///
public override void PositionCursor ()
{
+ if (selecting) {
+ var minRow = Math.Min (Math.Max (Math.Min (selectionStartRow, currentRow)-topRow, 0), Frame.Height);
+ var maxRow = Math.Min (Math.Max (Math.Max (selectionStartRow, currentRow) - topRow, 0), Frame.Height);
+
+ SetNeedsDisplay (new Rect (0, minRow, Frame.Width, maxRow));
+ }
Move (CurrentColumn - leftColumn, CurrentRow - topRow);
}
@@ -209,20 +216,117 @@ namespace Terminal.Gui {
}
}
+ void ColorNormal ()
+ {
+ Driver.SetAttribute (ColorScheme.Normal);
+ }
+
+ void ColorSelection ()
+ {
+ if (HasFocus)
+ Driver.SetAttribute (ColorScheme.Focus);
+ else
+ Driver.SetAttribute (ColorScheme.Normal);
+ }
+
+ // Returns an encoded region start..end (top 32 bits are the row, low32 the column)
+ void GetEncodedRegionBounds (out long start, out long end)
+ {
+ long selection = ((long)(uint)selectionStartRow << 32) | (uint)selectionStartColumn;
+ long point = ((long)(uint)currentRow << 32) | (uint)currentColumn;
+ if (selection > point) {
+ start = point;
+ end = selection;
+ } else {
+ start = selection;
+ end = point;
+ }
+ }
+
+ bool PointInSelection (int col, int row)
+ {
+ long start, end;
+ GetEncodedRegionBounds (out start, out end);
+ var q = ((long)(uint)row << 32) | (uint)col;
+ return q >= start && q <= end;
+ }
+
+ //
+ // Returns a ustring with the text in the selected
+ // region.
+ //
+ public ustring GetRegion ()
+ {
+ long start, end;
+ GetEncodedRegionBounds (out start, out end);
+ int startRow = (int)(start >> 32);
+ var maxrow = ((int)(end >> 32));
+ int startCol = (int)(start & 0xffffffff);
+ var endCol = (int)(end & 0xffffffff);
+ var line = model.GetLine (startRow);
+
+ if (startRow == maxrow)
+ return StringFromRunes (line.GetRange (startCol, endCol));
+
+ ustring res = StringFromRunes (line.GetRange (startCol, line.Count - startCol));
+
+ for (int row = startRow+1; row < maxrow; row++) {
+ res = res + ustring.Make (10) + StringFromRunes (model.GetLine (row));
+ }
+ line = model.GetLine (maxrow);
+ res = res + ustring.Make (10) + StringFromRunes (line.GetRange (0, endCol));
+ return res;
+ }
+
+ //
+ // Clears the contents of the selected region
+ //
+ public void ClearRegion ()
+ {
+ long start, end;
+ long currentEncoded = ((long)(uint)currentRow << 32) | (uint)currentColumn;
+ GetEncodedRegionBounds (out start, out end);
+ int startRow = (int)(start >> 32);
+ var maxrow = ((int)(end >> 32));
+ int startCol = (int)(start & 0xffffffff);
+ var endCol = (int)(end & 0xffffffff);
+ var line = model.GetLine (startRow);
+
+ if (startRow == maxrow) {
+ line.RemoveRange (startCol, endCol - startCol);
+ currentColumn = startCol;
+ SetNeedsDisplay (new Rect (0, startRow - topRow, Frame.Width, startRow - topRow + 1));
+ return;
+ }
+
+ line.RemoveRange (startCol, line.Count - startCol);
+ var line2 = model.GetLine (maxrow);
+ line.AddRange (line2.Skip (endCol));
+ for (int row = startRow + 1; row <= maxrow; row++) {
+ model.RemoveLine (startRow+1);
+ }
+ if (currentEncoded == end) {
+ currentRow -= maxrow - (startRow);
+ }
+ currentColumn = startCol;
+
+ SetNeedsDisplay ();
+ }
+
///
/// Redraw the text editor region
///
/// The region to redraw.
public override void Redraw (Rect region)
{
- Driver.SetAttribute (ColorScheme.Focus);
- Move (0, 0);
+ ColorNormal ();
int bottom = region.Bottom;
int right = region.Right;
for (int row = region.Top; row < bottom; row++) {
int textLine = topRow + row;
if (textLine >= model.Count) {
+ ColorNormal ();
ClearRegion (region.Left, row, region.Right, row + 1);
continue;
}
@@ -237,6 +341,11 @@ namespace Terminal.Gui {
for (int col = region.Left; col < right; col++) {
var lineCol = leftColumn + col;
var rune = lineCol >= lineRuneCount ? ' ' : line [lineCol];
+ if (selecting && PointInSelection (col, row))
+ ColorSelection ();
+ else
+ ColorNormal ();
+
AddRune (col, row, rune);
}
}
@@ -366,6 +475,8 @@ namespace Terminal.Gui {
int restCount;
List rest;
+ // Handle some state here - whether the last command was a kill
+ // operation and the column tracking (up/down)
switch (kb.Key) {
case Key.ControlN:
case Key.CursorDown:
@@ -381,6 +492,7 @@ namespace Terminal.Gui {
break;
}
+ // Dispatch the command.
switch (kb.Key) {
case Key.ControlN:
case Key.CursorDown:
@@ -560,6 +672,24 @@ namespace Terminal.Gui {
case Key.ControlY: // Control-y, yank
InsertText (Clipboard.Contents);
+ selecting = false;
+ break;
+
+ case Key.ControlSpace:
+ selecting = true;
+ selectionStartColumn = currentColumn;
+ selectionStartRow = currentRow;
+ break;
+
+ case (Key)((int)'w' + Key.AltMask):
+ SetClipboard (GetRegion ());
+ selecting = false;
+ break;
+
+ case Key.ControlW:
+ SetClipboard (GetRegion ());
+ ClearRegion ();
+ selecting = false;
break;
case (Key)((int)'b' + Key.AltMask):
@@ -690,7 +820,7 @@ namespace Terminal.Gui {
SetNeedsDisplay ();
return true;
}
- #endif
+#endif
}
}