|
@@ -171,6 +171,101 @@ namespace Terminal.Gui {
|
|
|
{
|
|
|
lines.RemoveAt (pos);
|
|
|
}
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Returns the maximum line length of the visible lines.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="first">The first line.</param>
|
|
|
+ /// <param name="last">The last line.</param>
|
|
|
+ public int GetMaxVisibleLine (int first, int last)
|
|
|
+ {
|
|
|
+ int maxLength = 0;
|
|
|
+ last = last < lines.Count ? last : lines.Count;
|
|
|
+ for (int i = first; i < last; i++) {
|
|
|
+ var l = GetLine (i).Count;
|
|
|
+ if (l > maxLength) {
|
|
|
+ maxLength = l;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return maxLength;
|
|
|
+ }
|
|
|
+
|
|
|
+ internal static int SetCol (int col, int width, int cols)
|
|
|
+ {
|
|
|
+ if (col + cols <= width) {
|
|
|
+ col += cols;
|
|
|
+ }
|
|
|
+
|
|
|
+ return col;
|
|
|
+ }
|
|
|
+
|
|
|
+ internal static int GetColFromX (List<Rune> t, int start, int x)
|
|
|
+ {
|
|
|
+ if (x < 0) {
|
|
|
+ return x;
|
|
|
+ }
|
|
|
+ int size = start;
|
|
|
+ var pX = x + start;
|
|
|
+ for (int i = start; i < t.Count; i++) {
|
|
|
+ var r = t [i];
|
|
|
+ size += Rune.ColumnWidth (r);
|
|
|
+ if (i == pX || (size > pX)) {
|
|
|
+ return i - start;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return t.Count - start;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Returns the size and length in a range of the string.
|
|
|
+ internal static (int size, int length) DisplaySize (List<Rune> t, int start = -1, int end = -1, bool checkNextRune = true)
|
|
|
+ {
|
|
|
+ if (t == null || t.Count == 0) {
|
|
|
+ return (0, 0);
|
|
|
+ }
|
|
|
+ int size = 0;
|
|
|
+ int len = 0;
|
|
|
+ int tcount = end == -1 ? t.Count : end > t.Count ? t.Count : end;
|
|
|
+ int i = start == -1 ? 0 : start;
|
|
|
+ for (; i < tcount; i++) {
|
|
|
+ var rune = t [i];
|
|
|
+ size += Rune.ColumnWidth (rune);
|
|
|
+ len += Rune.RuneLen (rune);
|
|
|
+ if (checkNextRune && i == tcount - 1 && t.Count > tcount && Rune.ColumnWidth (t [i + 1]) > 1) {
|
|
|
+ size += Rune.ColumnWidth (t [i + 1]);
|
|
|
+ len += Rune.RuneLen (t [i + 1]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return (size, len);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Returns the left column in a range of the string.
|
|
|
+ internal static int CalculateLeftColumn (List<Rune> t, int start, int end, int width, int currentColumn)
|
|
|
+ {
|
|
|
+ if (t == null) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ (var dSize, _) = TextModel.DisplaySize (t, start, end);
|
|
|
+ if (dSize < width) {
|
|
|
+ return start;
|
|
|
+ }
|
|
|
+ int size = 0;
|
|
|
+ int tcount = end > t.Count - 1 ? t.Count - 1 : end;
|
|
|
+ int col = 0;
|
|
|
+ for (int i = tcount; i > start; i--) {
|
|
|
+ var rune = t [i];
|
|
|
+ var s = Rune.ColumnWidth (rune);
|
|
|
+ size += s;
|
|
|
+ if (size >= dSize - width) {
|
|
|
+ col = tcount - i + start;
|
|
|
+ if (start == 0 || col == start || (currentColumn == t.Count && (currentColumn - col > width))) {
|
|
|
+ col++;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return col;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -356,6 +451,15 @@ namespace Terminal.Gui {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ ///<inheritdoc/>
|
|
|
+ public override Rect Frame {
|
|
|
+ get => base.Frame;
|
|
|
+ set {
|
|
|
+ base.Frame = value;
|
|
|
+ Adjust ();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Loads the contents of the file into the <see cref="TextView"/>.
|
|
|
/// </summary>
|
|
@@ -421,11 +525,22 @@ namespace Terminal.Gui {
|
|
|
}
|
|
|
var line = model.GetLine (currentRow);
|
|
|
var retreat = 0;
|
|
|
+ var col = 0;
|
|
|
if (line.Count > 0) {
|
|
|
retreat = Math.Max ((SpecialRune (line [Math.Max (CurrentColumn - leftColumn - 1, 0)])
|
|
|
? 1 : 0), 0);
|
|
|
+ for (int idx = leftColumn < 0 ? 0 : leftColumn; idx < line.Count; idx++) {
|
|
|
+ if (idx == CurrentColumn)
|
|
|
+ break;
|
|
|
+ var cols = Rune.ColumnWidth (line [idx]);
|
|
|
+ col += cols - 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var ccol = CurrentColumn - leftColumn - retreat + col;
|
|
|
+ if (leftColumn <= CurrentColumn && ccol < Frame.Width
|
|
|
+ && topRow <= CurrentRow && CurrentRow - topRow < Frame.Height) {
|
|
|
+ Move (ccol, CurrentRow - topRow);
|
|
|
}
|
|
|
- Move (CurrentColumn - leftColumn - retreat, CurrentRow - topRow);
|
|
|
}
|
|
|
|
|
|
void ClearRegion (int left, int top, int right, int bottom)
|
|
@@ -569,10 +684,12 @@ namespace Terminal.Gui {
|
|
|
}
|
|
|
|
|
|
Move (bounds.Left, row);
|
|
|
- for (int col = bounds.Left; col < right; col++) {
|
|
|
- var lineCol = leftColumn + col;
|
|
|
+ var col = 0;
|
|
|
+ for (int idx = bounds.Left; idx < right; idx++) {
|
|
|
+ var lineCol = leftColumn + idx;
|
|
|
var rune = lineCol >= lineRuneCount ? ' ' : line [lineCol];
|
|
|
- if (selecting && PointInSelection (col, row)) {
|
|
|
+ var cols = Rune.ColumnWidth (rune);
|
|
|
+ if (selecting && PointInSelection (idx, row)) {
|
|
|
ColorSelection ();
|
|
|
} else {
|
|
|
ColorNormal ();
|
|
@@ -581,6 +698,7 @@ namespace Terminal.Gui {
|
|
|
if (!SpecialRune (rune)) {
|
|
|
AddRune (col, row, rune);
|
|
|
}
|
|
|
+ col = TextModel.SetCol (col, bounds.Right, cols);
|
|
|
}
|
|
|
}
|
|
|
PositionCursor ();
|
|
@@ -641,19 +759,25 @@ namespace Terminal.Gui {
|
|
|
|
|
|
void InsertText (ustring text)
|
|
|
{
|
|
|
+ if (ustring.IsNullOrEmpty (text)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
var lines = TextModel.StringToRunes (text);
|
|
|
|
|
|
- if (lines.Count == 0)
|
|
|
+ if (lines.Count == 0) {
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
var line = GetCurrentLine ();
|
|
|
|
|
|
- // Optmize single line
|
|
|
+ // Optimize single line
|
|
|
if (lines.Count == 1) {
|
|
|
line.InsertRange (currentColumn, lines [0]);
|
|
|
currentColumn += lines [0].Count;
|
|
|
- if (currentColumn - leftColumn > Frame.Width)
|
|
|
+ if (currentColumn - leftColumn > Frame.Width) {
|
|
|
leftColumn = currentColumn - Frame.Width + 1;
|
|
|
+ }
|
|
|
SetNeedsDisplay (new Rect (0, currentRow - topRow, Frame.Width, currentRow - topRow + 1));
|
|
|
return;
|
|
|
}
|
|
@@ -666,26 +790,18 @@ namespace Terminal.Gui {
|
|
|
// First line is inserted at the current location, the rest is appended
|
|
|
line.InsertRange (currentColumn, lines [0]);
|
|
|
|
|
|
- for (int i = 1; i < lines.Count; i++)
|
|
|
+ for (int i = 1; i < lines.Count; i++) {
|
|
|
model.AddLine (currentRow + i, lines [i]);
|
|
|
+ }
|
|
|
|
|
|
var last = model.GetLine (currentRow + lines.Count - 1);
|
|
|
var lastp = last.Count;
|
|
|
last.InsertRange (last.Count, rest);
|
|
|
|
|
|
- // Now adjjust column and row positions
|
|
|
+ // Now adjust column and row positions
|
|
|
currentRow += lines.Count - 1;
|
|
|
currentColumn = lastp;
|
|
|
- if (currentRow - topRow > Frame.Height) {
|
|
|
- topRow = currentRow - Frame.Height + 1;
|
|
|
- if (topRow < 0)
|
|
|
- topRow = 0;
|
|
|
- }
|
|
|
- if (currentColumn < leftColumn)
|
|
|
- leftColumn = currentColumn;
|
|
|
- if (currentColumn - leftColumn >= Frame.Width)
|
|
|
- leftColumn = currentColumn - Frame.Width + 1;
|
|
|
- SetNeedsDisplay ();
|
|
|
+ Adjust ();
|
|
|
}
|
|
|
|
|
|
// The column we are tracking, or -1 if we are not tracking any column
|
|
@@ -707,38 +823,63 @@ namespace Terminal.Gui {
|
|
|
|
|
|
void Adjust ()
|
|
|
{
|
|
|
+ var offB = OffSetBackground ();
|
|
|
+ var line = GetCurrentLine ();
|
|
|
bool need = false;
|
|
|
if (currentColumn < leftColumn) {
|
|
|
- currentColumn = leftColumn;
|
|
|
+ leftColumn = currentColumn;
|
|
|
need = true;
|
|
|
- }
|
|
|
- if (currentColumn - leftColumn > Frame.Width) {
|
|
|
- leftColumn = currentColumn - Frame.Width + 1;
|
|
|
+ } else if (currentColumn - leftColumn > Frame.Width + offB.width ||
|
|
|
+ TextModel.DisplaySize (line, leftColumn, currentColumn).size >= Frame.Width + offB.width) {
|
|
|
+ leftColumn = Math.Max (TextModel.CalculateLeftColumn (line, leftColumn,
|
|
|
+ currentColumn, Frame.Width - 1 + offB.width, currentColumn), 0);
|
|
|
need = true;
|
|
|
}
|
|
|
if (currentRow < topRow) {
|
|
|
topRow = currentRow;
|
|
|
need = true;
|
|
|
- }
|
|
|
- if (currentRow - topRow > Frame.Height) {
|
|
|
- topRow = currentRow - Frame.Height + 1;
|
|
|
+ } else if (currentRow - topRow >= Frame.Height + offB.height) {
|
|
|
+ topRow = Math.Min (Math.Max (currentRow - Frame.Height + 1, 0), currentRow);
|
|
|
need = true;
|
|
|
}
|
|
|
- if (need)
|
|
|
+ if (need) {
|
|
|
SetNeedsDisplay ();
|
|
|
- else
|
|
|
+ } else {
|
|
|
PositionCursor ();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ (int width, int height) OffSetBackground ()
|
|
|
+ {
|
|
|
+ int w = 0;
|
|
|
+ int h = 0;
|
|
|
+ if (SuperView?.Frame.Right - Frame.Right < 0) {
|
|
|
+ w = SuperView.Frame.Right - Frame.Right - 1;
|
|
|
+ }
|
|
|
+ if (SuperView?.Frame.Bottom - Frame.Bottom < 0) {
|
|
|
+ h = SuperView.Frame.Bottom - Frame.Bottom - 1;
|
|
|
+ }
|
|
|
+ return (w, h);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Will scroll the <see cref="TextView"/> to display the specified row at the top
|
|
|
+ /// Will scroll the <see cref="TextView"/> to display the specified row at the top if <paramref name="isRow"/> is true or
|
|
|
+ /// will scroll the <see cref="TextView"/> to display the specified column at the left if <paramref name="isRow"/> is false.
|
|
|
/// </summary>
|
|
|
- /// <param name="row">Row that should be displayed at the top, if the value is negative it will be reset to zero</param>
|
|
|
- public void ScrollTo (int row)
|
|
|
+ /// <param name="idx">Row that should be displayed at the top or Column that should be displayed at the left,
|
|
|
+ /// if the value is negative it will be reset to zero</param>
|
|
|
+ /// <param name="isRow">If true (default) the <paramref name="idx"/> is a row, column otherwise.</param>
|
|
|
+ public void ScrollTo (int idx, bool isRow = true)
|
|
|
{
|
|
|
- if (row < 0)
|
|
|
- row = 0;
|
|
|
- topRow = row > model.Count ? model.Count - 1 : row;
|
|
|
+ if (idx < 0) {
|
|
|
+ idx = 0;
|
|
|
+ }
|
|
|
+ if (isRow) {
|
|
|
+ topRow = idx > model.Count - 1 ? model.Count - 1 : idx;
|
|
|
+ } else {
|
|
|
+ var maxlength = model.GetMaxVisibleLine (topRow, topRow + Frame.Height);
|
|
|
+ leftColumn = idx > maxlength - 1 ? maxlength - 1 : idx;
|
|
|
+ }
|
|
|
SetNeedsDisplay ();
|
|
|
}
|
|
|
|
|
@@ -786,7 +927,7 @@ namespace Terminal.Gui {
|
|
|
break;
|
|
|
|
|
|
case Key.PageUp:
|
|
|
- case ((int)'v' + Key.AltMask):
|
|
|
+ case ((int)'V' + Key.AltMask):
|
|
|
int nPageUpShift = Frame.Height - 1;
|
|
|
if (currentRow > 0) {
|
|
|
if (columnTrack == -1)
|
|
@@ -816,53 +957,33 @@ namespace Terminal.Gui {
|
|
|
var currentLine = GetCurrentLine ();
|
|
|
if (currentColumn < currentLine.Count) {
|
|
|
currentColumn++;
|
|
|
- if (currentColumn >= leftColumn + Frame.Width) {
|
|
|
- leftColumn++;
|
|
|
- SetNeedsDisplay ();
|
|
|
- }
|
|
|
- PositionCursor ();
|
|
|
} else {
|
|
|
if (currentRow + 1 < model.Count) {
|
|
|
currentRow++;
|
|
|
currentColumn = 0;
|
|
|
- leftColumn = 0;
|
|
|
if (currentRow >= topRow + Frame.Height) {
|
|
|
topRow++;
|
|
|
}
|
|
|
- SetNeedsDisplay ();
|
|
|
- PositionCursor ();
|
|
|
}
|
|
|
- break;
|
|
|
}
|
|
|
+ Adjust ();
|
|
|
break;
|
|
|
|
|
|
case Key.B | Key.CtrlMask:
|
|
|
case Key.CursorLeft:
|
|
|
if (currentColumn > 0) {
|
|
|
currentColumn--;
|
|
|
- if (currentColumn < leftColumn) {
|
|
|
- leftColumn--;
|
|
|
- SetNeedsDisplay ();
|
|
|
- }
|
|
|
- PositionCursor ();
|
|
|
} else {
|
|
|
if (currentRow > 0) {
|
|
|
currentRow--;
|
|
|
if (currentRow < topRow) {
|
|
|
topRow--;
|
|
|
- SetNeedsDisplay ();
|
|
|
}
|
|
|
currentLine = GetCurrentLine ();
|
|
|
currentColumn = currentLine.Count;
|
|
|
- int prev = leftColumn;
|
|
|
- leftColumn = currentColumn - Frame.Width + 1;
|
|
|
- if (leftColumn < 0)
|
|
|
- leftColumn = 0;
|
|
|
- if (prev != leftColumn)
|
|
|
- SetNeedsDisplay ();
|
|
|
- PositionCursor ();
|
|
|
}
|
|
|
}
|
|
|
+ Adjust ();
|
|
|
break;
|
|
|
|
|
|
case Key.Delete:
|
|
@@ -890,10 +1011,7 @@ namespace Terminal.Gui {
|
|
|
model.RemoveLine (currentRow);
|
|
|
currentRow--;
|
|
|
currentColumn = prevCount;
|
|
|
- leftColumn = currentColumn - Frame.Width + 1;
|
|
|
- if (leftColumn < 0)
|
|
|
- leftColumn = 0;
|
|
|
- SetNeedsDisplay ();
|
|
|
+ Adjust ();
|
|
|
}
|
|
|
break;
|
|
|
|
|
@@ -901,11 +1019,7 @@ namespace Terminal.Gui {
|
|
|
case Key.Home:
|
|
|
case Key.A | Key.CtrlMask:
|
|
|
currentColumn = 0;
|
|
|
- if (currentColumn < leftColumn) {
|
|
|
- leftColumn = 0;
|
|
|
- SetNeedsDisplay ();
|
|
|
- } else
|
|
|
- PositionCursor ();
|
|
|
+ Adjust ();
|
|
|
break;
|
|
|
case Key.DeleteChar:
|
|
|
case Key.D | Key.CtrlMask: // Delete
|
|
@@ -932,12 +1046,7 @@ namespace Terminal.Gui {
|
|
|
currentLine = GetCurrentLine ();
|
|
|
currentColumn = currentLine.Count;
|
|
|
int pcol = leftColumn;
|
|
|
- leftColumn = currentColumn - Frame.Width + 1;
|
|
|
- if (leftColumn < 0)
|
|
|
- leftColumn = 0;
|
|
|
- if (pcol != leftColumn)
|
|
|
- SetNeedsDisplay ();
|
|
|
- PositionCursor ();
|
|
|
+ Adjust ();
|
|
|
break;
|
|
|
|
|
|
case Key.K | Key.CtrlMask: // kill-to-end
|
|
@@ -978,11 +1087,7 @@ namespace Terminal.Gui {
|
|
|
selectionStartRow = currentRow;
|
|
|
break;
|
|
|
|
|
|
- case ((int)'w' + Key.AltMask):
|
|
|
- SetClipboard (GetRegion ());
|
|
|
- selecting = false;
|
|
|
- break;
|
|
|
-
|
|
|
+ case ((int)'W' + Key.AltMask):
|
|
|
case Key.W | Key.CtrlMask:
|
|
|
SetClipboard (GetRegion ());
|
|
|
if (!isReadOnly)
|
|
@@ -990,7 +1095,8 @@ namespace Terminal.Gui {
|
|
|
selecting = false;
|
|
|
break;
|
|
|
|
|
|
- case (Key)((int)'b' + Key.AltMask):
|
|
|
+ case Key.CtrlMask | Key.CursorLeft:
|
|
|
+ case (Key)((int)'B' + Key.AltMask):
|
|
|
var newPos = WordBackward (currentColumn, currentRow);
|
|
|
if (newPos.HasValue) {
|
|
|
currentColumn = newPos.Value.col;
|
|
@@ -1000,7 +1106,8 @@ namespace Terminal.Gui {
|
|
|
|
|
|
break;
|
|
|
|
|
|
- case (Key)((int)'f' + Key.AltMask):
|
|
|
+ case Key.CtrlMask | Key.CursorRight:
|
|
|
+ case (Key)((int)'F' + Key.AltMask):
|
|
|
newPos = WordForward (currentColumn, currentRow);
|
|
|
if (newPos.HasValue) {
|
|
|
currentColumn = newPos.Value.col;
|
|
@@ -1012,7 +1119,6 @@ namespace Terminal.Gui {
|
|
|
case Key.Enter:
|
|
|
if (isReadOnly)
|
|
|
break;
|
|
|
- var orow = currentRow;
|
|
|
currentLine = GetCurrentLine ();
|
|
|
restCount = currentLine.Count - currentColumn;
|
|
|
rest = currentLine.GetRange (currentColumn, restCount);
|
|
@@ -1063,11 +1169,12 @@ namespace Terminal.Gui {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- private void MoveUp ()
|
|
|
+ void MoveUp ()
|
|
|
{
|
|
|
if (currentRow > 0) {
|
|
|
- if (columnTrack == -1)
|
|
|
+ if (columnTrack == -1) {
|
|
|
columnTrack = currentColumn;
|
|
|
+ }
|
|
|
currentRow--;
|
|
|
if (currentRow < topRow) {
|
|
|
topRow--;
|
|
@@ -1078,11 +1185,12 @@ namespace Terminal.Gui {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void MoveDown ()
|
|
|
+ void MoveDown ()
|
|
|
{
|
|
|
if (currentRow + 1 < model.Count) {
|
|
|
- if (columnTrack == -1)
|
|
|
+ if (columnTrack == -1) {
|
|
|
columnTrack = currentColumn;
|
|
|
+ }
|
|
|
currentRow++;
|
|
|
if (currentRow >= topRow + Frame.Height) {
|
|
|
topRow++;
|
|
@@ -1090,6 +1198,8 @@ namespace Terminal.Gui {
|
|
|
}
|
|
|
TrackColumn ();
|
|
|
PositionCursor ();
|
|
|
+ } else if (currentRow > Frame.Height) {
|
|
|
+ Adjust ();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1186,28 +1296,31 @@ namespace Terminal.Gui {
|
|
|
{
|
|
|
var col = fromCol;
|
|
|
var row = fromRow;
|
|
|
- var line = GetCurrentLine ();
|
|
|
- var rune = RuneAt (col, row);
|
|
|
+ try {
|
|
|
+ var rune = RuneAt (col, row);
|
|
|
|
|
|
- var srow = row;
|
|
|
- if (Rune.IsPunctuation (rune) || Rune.IsWhiteSpace (rune)) {
|
|
|
- while (MoveNext (ref col, ref row, out rune)) {
|
|
|
- if (Rune.IsLetterOrDigit (rune))
|
|
|
- break;
|
|
|
- }
|
|
|
- while (MoveNext (ref col, ref row, out rune)) {
|
|
|
- if (!Rune.IsLetterOrDigit (rune))
|
|
|
- break;
|
|
|
- }
|
|
|
- } else {
|
|
|
- while (MoveNext (ref col, ref row, out rune)) {
|
|
|
- if (!Rune.IsLetterOrDigit (rune))
|
|
|
- break;
|
|
|
+ var srow = row;
|
|
|
+ if (Rune.IsPunctuation (rune) || Rune.IsWhiteSpace (rune)) {
|
|
|
+ while (MoveNext (ref col, ref row, out rune)) {
|
|
|
+ if (Rune.IsLetterOrDigit (rune))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ while (MoveNext (ref col, ref row, out rune)) {
|
|
|
+ if (!Rune.IsLetterOrDigit (rune))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ while (MoveNext (ref col, ref row, out rune)) {
|
|
|
+ if (!Rune.IsLetterOrDigit (rune))
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
+ if (fromCol != col || fromRow != row)
|
|
|
+ return (col, row);
|
|
|
+ return null;
|
|
|
+ } catch (Exception) {
|
|
|
+ return null;
|
|
|
}
|
|
|
- if (fromCol != col || fromRow != row)
|
|
|
- return (col, row);
|
|
|
- return null;
|
|
|
}
|
|
|
|
|
|
(int col, int row)? WordBackward (int fromCol, int fromRow)
|
|
@@ -1217,27 +1330,30 @@ namespace Terminal.Gui {
|
|
|
|
|
|
var col = fromCol;
|
|
|
var row = fromRow;
|
|
|
- var line = GetCurrentLine ();
|
|
|
- var rune = RuneAt (col, row);
|
|
|
+ try {
|
|
|
+ var rune = RuneAt (col, row);
|
|
|
|
|
|
- if (Rune.IsPunctuation (rune) || Rune.IsSymbol (rune) || Rune.IsWhiteSpace (rune)) {
|
|
|
- while (MovePrev (ref col, ref row, out rune)) {
|
|
|
- if (Rune.IsLetterOrDigit (rune))
|
|
|
- break;
|
|
|
- }
|
|
|
- while (MovePrev (ref col, ref row, out rune)) {
|
|
|
- if (!Rune.IsLetterOrDigit (rune))
|
|
|
- break;
|
|
|
- }
|
|
|
- } else {
|
|
|
- while (MovePrev (ref col, ref row, out rune)) {
|
|
|
- if (!Rune.IsLetterOrDigit (rune))
|
|
|
- break;
|
|
|
+ if (Rune.IsPunctuation (rune) || Rune.IsSymbol (rune) || Rune.IsWhiteSpace (rune)) {
|
|
|
+ while (MovePrev (ref col, ref row, out rune)) {
|
|
|
+ if (Rune.IsLetterOrDigit (rune))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ while (MovePrev (ref col, ref row, out rune)) {
|
|
|
+ if (!Rune.IsLetterOrDigit (rune))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ while (MovePrev (ref col, ref row, out rune)) {
|
|
|
+ if (!Rune.IsLetterOrDigit (rune))
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
+ if (fromCol != col || fromRow != row)
|
|
|
+ return (col, row);
|
|
|
+ return null;
|
|
|
+ } catch (Exception) {
|
|
|
+ return null;
|
|
|
}
|
|
|
- if (fromCol != col || fromRow != row)
|
|
|
- return (col, row);
|
|
|
- return null;
|
|
|
}
|
|
|
|
|
|
///<inheritdoc/>
|
|
@@ -1265,18 +1381,30 @@ namespace Terminal.Gui {
|
|
|
currentRow = ev.Y + topRow;
|
|
|
}
|
|
|
var r = GetCurrentLine ();
|
|
|
- if (ev.X - leftColumn >= r.Count)
|
|
|
+ var idx = TextModel.GetColFromX (r, leftColumn, ev.X);
|
|
|
+ if (idx - leftColumn >= r.Count) {
|
|
|
currentColumn = r.Count - leftColumn;
|
|
|
- else
|
|
|
- currentColumn = ev.X - leftColumn;
|
|
|
+ } else {
|
|
|
+ currentColumn = idx + leftColumn;
|
|
|
+ }
|
|
|
}
|
|
|
PositionCursor ();
|
|
|
} else if (ev.Flags == MouseFlags.WheeledDown) {
|
|
|
lastWasKill = false;
|
|
|
- MoveDown ();
|
|
|
+ columnTrack = currentColumn;
|
|
|
+ ScrollTo (topRow + 1);
|
|
|
} else if (ev.Flags == MouseFlags.WheeledUp) {
|
|
|
lastWasKill = false;
|
|
|
- MoveUp ();
|
|
|
+ columnTrack = currentColumn;
|
|
|
+ ScrollTo (topRow - 1);
|
|
|
+ } else if (ev.Flags == MouseFlags.WheeledRight) {
|
|
|
+ lastWasKill = false;
|
|
|
+ columnTrack = currentColumn;
|
|
|
+ ScrollTo (leftColumn + 1, false);
|
|
|
+ } else if (ev.Flags == MouseFlags.WheeledLeft) {
|
|
|
+ lastWasKill = false;
|
|
|
+ columnTrack = currentColumn;
|
|
|
+ ScrollTo (leftColumn - 1, false);
|
|
|
}
|
|
|
|
|
|
return true;
|