mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-02 01:03:29 +01:00
Forward word, backward word, some small code changes
This commit is contained in:
@@ -1176,7 +1176,7 @@ namespace Terminal.Gui {
|
||||
/// to the mainloop, allowing user code to use async/await.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class Application {
|
||||
public static class Application {
|
||||
/// <summary>
|
||||
/// The current Console Driver in use.
|
||||
/// </summary>
|
||||
@@ -1316,7 +1316,7 @@ namespace Terminal.Gui {
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (Toplevel != null) {
|
||||
Application.End (Toplevel);
|
||||
End (Toplevel);
|
||||
Toplevel = null;
|
||||
}
|
||||
}
|
||||
@@ -1509,8 +1509,9 @@ namespace Terminal.Gui {
|
||||
toplevels.Pop ();
|
||||
if (toplevels.Count == 0)
|
||||
Shutdown ();
|
||||
else {
|
||||
Current = toplevels.Peek () as Toplevel;
|
||||
else
|
||||
{
|
||||
Current = toplevels.Peek();
|
||||
Refresh ();
|
||||
}
|
||||
}
|
||||
@@ -1605,8 +1606,6 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public static void RequestStop ()
|
||||
{
|
||||
var ct = Current as Toplevel;
|
||||
|
||||
Current.Running = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Terminal.Gui {
|
||||
///
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class MessageBox {
|
||||
public static class MessageBox {
|
||||
/// <summary>
|
||||
/// Presents a message with the specified title and message and a list of buttons to show to the user.
|
||||
/// </summary>
|
||||
|
||||
@@ -583,6 +583,8 @@ namespace Terminal.Gui {
|
||||
{
|
||||
int wch;
|
||||
var code = Curses.get_wch (out wch);
|
||||
if (code == Curses.ERR)
|
||||
return;
|
||||
if (code == Curses.KEY_CODE_YES) {
|
||||
if (wch == Curses.KeyResize) {
|
||||
if (Curses.CheckWinChange ()) {
|
||||
@@ -602,7 +604,7 @@ namespace Terminal.Gui {
|
||||
|
||||
// Special handling for ESC, we want to try to catch ESC+letter to simulate alt-letter as well as Alt-Fkey
|
||||
if (wch == 27) {
|
||||
Curses.timeout (100);
|
||||
Curses.timeout (200);
|
||||
|
||||
code = Curses.get_wch (out wch);
|
||||
if (code == Curses.KEY_CODE_YES)
|
||||
|
||||
@@ -407,8 +407,10 @@ namespace Mono.Terminal {
|
||||
}
|
||||
}
|
||||
|
||||
if (idleHandlers.Count > 0)
|
||||
RunIdle ();
|
||||
lock (idleHandlers){
|
||||
if (idleHandlers.Count > 0)
|
||||
RunIdle();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Terminal.Gui {
|
||||
public class Button : View {
|
||||
ustring text;
|
||||
ustring shown_text;
|
||||
char hot_key;
|
||||
Rune hot_key;
|
||||
int hot_pos = -1;
|
||||
bool is_default;
|
||||
|
||||
@@ -112,10 +112,10 @@ namespace Terminal.Gui {
|
||||
shown_text = "[ " + text + " ]";
|
||||
|
||||
hot_pos = -1;
|
||||
hot_key = (char)0;
|
||||
hot_key = (Rune)0;
|
||||
int i = 0;
|
||||
foreach (char c in shown_text) {
|
||||
if (Char.IsUpper (c)) {
|
||||
foreach (Rune c in shown_text) {
|
||||
if (Rune.IsUpper (c)) {
|
||||
hot_key = c;
|
||||
hot_pos = i;
|
||||
break;
|
||||
@@ -197,7 +197,7 @@ namespace Terminal.Gui {
|
||||
public override bool ProcessKey (KeyEvent kb)
|
||||
{
|
||||
var c = kb.KeyValue;
|
||||
if (c == '\n' || c == ' ' || Char.ToUpper ((char)c) == hot_key) {
|
||||
if (c == '\n' || c == ' ' || Rune.ToUpper ((Rune)c) == hot_key) {
|
||||
if (Clicked != null)
|
||||
Clicked ();
|
||||
return true;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Terminal.Gui {
|
||||
public class CheckBox : View {
|
||||
ustring text;
|
||||
int hot_pos = -1;
|
||||
char hot_key;
|
||||
Rune hot_key;
|
||||
|
||||
/// <summary>
|
||||
/// Toggled event, raised when the CheckButton is toggled.
|
||||
@@ -74,8 +74,8 @@ namespace Terminal.Gui {
|
||||
int i = 0;
|
||||
hot_pos = -1;
|
||||
hot_key = (char)0;
|
||||
foreach (char c in text) {
|
||||
if (Char.IsUpper (c)) {
|
||||
foreach (Rune c in text) {
|
||||
if (Rune.IsUpper (c)) {
|
||||
hot_key = c;
|
||||
hot_pos = i;
|
||||
break;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using NStack;
|
||||
|
||||
namespace Terminal.Gui {
|
||||
public class Clipboard {
|
||||
public static class Clipboard {
|
||||
public static ustring Contents { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Terminal.Gui {
|
||||
if (talign == TextAlignment.Justified) {
|
||||
// TODO: ustring needs this
|
||||
var words = str.ToString ().Split (whitespace, StringSplitOptions.RemoveEmptyEntries);
|
||||
int textCount = words.Sum ((arg) => arg.Length);
|
||||
int textCount = words.Sum (arg => arg.Length);
|
||||
|
||||
var spaces = (width- textCount) / (words.Length - 1);
|
||||
var extras = (width - textCount) % words.Length;
|
||||
@@ -186,7 +186,7 @@ namespace Terminal.Gui {
|
||||
{
|
||||
var result = new List<ustring> ();
|
||||
Recalc (text, result, width, TextAlignment.Left);
|
||||
return result.Count ();
|
||||
return result.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace Terminal.Gui {
|
||||
} else if (t is string) {
|
||||
RenderUstr (t as string, col, line, width);
|
||||
} else
|
||||
RenderUstr (((string)t).ToString (), col, line, width);
|
||||
RenderUstr (t.ToString (), col, line, width);
|
||||
}
|
||||
|
||||
public bool IsMarked (int item)
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Terminal.Gui {
|
||||
Help = help ?? "";
|
||||
Action = action;
|
||||
bool nextIsHot = false;
|
||||
foreach (var x in title) {
|
||||
foreach (var x in Title) {
|
||||
if (x == '_')
|
||||
nextIsHot = true;
|
||||
else {
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
// public API to insert, remove ranges
|
||||
// Add word forward/word backwards commands
|
||||
// Save buffer API
|
||||
// Mouse
|
||||
//
|
||||
// Desirable:
|
||||
// Move all the text manipulation into the TextModel
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -34,8 +39,6 @@ namespace Terminal.Gui {
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
try {
|
||||
var stream = File.OpenRead (file);
|
||||
if (stream == null)
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
@@ -115,15 +118,32 @@ namespace Terminal.Gui {
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of text lines in the model
|
||||
/// </summary>
|
||||
public int Count => lines.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the specified line as a List of Rune
|
||||
/// </summary>
|
||||
/// <returns>The line.</returns>
|
||||
/// <param name="line">Line number to retrieve.</param>
|
||||
public List<Rune> GetLine (int line) => lines [line];
|
||||
|
||||
/// <summary>
|
||||
/// Adds a line to the model at the specified position.
|
||||
/// </summary>
|
||||
/// <param name="pos">Line number where the line will be inserted.</param>
|
||||
/// <param name="runes">The line of text, as a List of Rune.</param>
|
||||
public void AddLine (int pos, List<Rune> runes)
|
||||
{
|
||||
lines.Insert (pos, runes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the line at the specified position
|
||||
/// </summary>
|
||||
/// <param name="pos">Position.</param>
|
||||
public void RemoveLine (int pos)
|
||||
{
|
||||
lines.RemoveAt (pos);
|
||||
@@ -306,15 +326,14 @@ namespace Terminal.Gui {
|
||||
/// Loads the contents of the stream into the TextView.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if stream was loaded, <c>false</c> otherwise.</returns>
|
||||
/// <param name="stream">Stream.</param>
|
||||
public bool LoadStream (Stream stream)
|
||||
/// <param name="stream">Stream to load the contents from.</param>
|
||||
public void LoadStream (Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException (nameof (stream));
|
||||
ResetPosition ();
|
||||
var res = model.LoadFile (path);
|
||||
model.LoadStream(stream);
|
||||
SetNeedsDisplay ();
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -406,10 +425,10 @@ namespace Terminal.Gui {
|
||||
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));
|
||||
res = res + ustring.Make ((Rune)10) + StringFromRunes (model.GetLine (row));
|
||||
}
|
||||
line = model.GetLine (maxrow);
|
||||
res = res + ustring.Make (10) + StringFromRunes (line.GetRange (0, endCol));
|
||||
res = res + ustring.Make ((Rune)10) + StringFromRunes (line.GetRange (0, endCol));
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -592,15 +611,32 @@ namespace Terminal.Gui {
|
||||
currentColumn = columnTrack;
|
||||
else if (currentColumn > line.Count)
|
||||
currentColumn = line.Count;
|
||||
|
||||
Adjust ();
|
||||
}
|
||||
|
||||
void Adjust ()
|
||||
{
|
||||
bool need = false;
|
||||
if (currentColumn < leftColumn) {
|
||||
leftColumn = currentColumn;
|
||||
SetNeedsDisplay ();
|
||||
currentColumn = leftColumn;
|
||||
need = true;
|
||||
}
|
||||
if (currentColumn - leftColumn > Frame.Width) {
|
||||
leftColumn = currentColumn - Frame.Width + 1;
|
||||
SetNeedsDisplay ();
|
||||
need = true;
|
||||
}
|
||||
if (currentRow < topRow) {
|
||||
topRow = currentRow;
|
||||
need = true;
|
||||
}
|
||||
if (currentRow - topRow > Frame.Height) {
|
||||
topRow = currentRow - Frame.Height + 1;
|
||||
need = true;
|
||||
}
|
||||
if (need)
|
||||
SetNeedsDisplay ();
|
||||
else
|
||||
PositionCursor ();
|
||||
}
|
||||
|
||||
bool lastWasKill;
|
||||
@@ -786,7 +822,7 @@ namespace Terminal.Gui {
|
||||
currentLine = GetCurrentLine ();
|
||||
if (currentLine.Count == 0) {
|
||||
model.RemoveLine (currentRow);
|
||||
var val = ustring.Make ('\n');
|
||||
var val = ustring.Make ((Rune)'\n');
|
||||
if (lastWasKill)
|
||||
AppendClipboard (val);
|
||||
else
|
||||
@@ -816,7 +852,7 @@ namespace Terminal.Gui {
|
||||
selectionStartRow = currentRow;
|
||||
break;
|
||||
|
||||
case (Key)((int)'w' + Key.AltMask):
|
||||
case ((int)'w' + Key.AltMask):
|
||||
SetClipboard (GetRegion ());
|
||||
selecting = false;
|
||||
break;
|
||||
@@ -828,9 +864,22 @@ namespace Terminal.Gui {
|
||||
break;
|
||||
|
||||
case (Key)((int)'b' + Key.AltMask):
|
||||
var newPos = WordBackward (currentColumn, currentRow);
|
||||
if (newPos.HasValue) {
|
||||
currentColumn = newPos.Value.col;
|
||||
currentRow = newPos.Value.row;
|
||||
}
|
||||
Adjust ();
|
||||
|
||||
break;
|
||||
|
||||
case (Key)((int)'f' + Key.AltMask):
|
||||
case (Key)((int)'f' + Key.AltMask):
|
||||
newPos = WordForward (currentColumn, currentRow);
|
||||
if (newPos.HasValue) {
|
||||
currentColumn = newPos.Value.col;
|
||||
currentRow = newPos.Value.row;
|
||||
}
|
||||
Adjust ();
|
||||
break;
|
||||
|
||||
case Key.Enter:
|
||||
@@ -874,69 +923,134 @@ namespace Terminal.Gui {
|
||||
return true;
|
||||
}
|
||||
|
||||
IEnumerable<(int col, int row, Rune rune)> ForwardIterator (int col, int row)
|
||||
{
|
||||
if (col < 0 || row < 0)
|
||||
yield break;
|
||||
if (row >= model.Count)
|
||||
yield break;
|
||||
var line = GetCurrentLine ();
|
||||
if (col >= line.Count)
|
||||
yield break;
|
||||
|
||||
while (row < model.Count) {
|
||||
for (int c = col; c < line.Count; c++) {
|
||||
yield return (c, row, line [c]);
|
||||
}
|
||||
col = 0;
|
||||
row++;
|
||||
line = GetCurrentLine ();
|
||||
}
|
||||
}
|
||||
|
||||
Rune RuneAt (int col, int row) => model.GetLine (row) [col];
|
||||
|
||||
bool MoveNext (ref int col, ref int row, out Rune rune)
|
||||
{
|
||||
var line = model.GetLine (row);
|
||||
if (col + 1 < line.Count) {
|
||||
col++;
|
||||
rune = line [col];
|
||||
return true;
|
||||
}
|
||||
while (row + 1 < model.Count){
|
||||
col = 0;
|
||||
row++;
|
||||
line = model.GetLine (row);
|
||||
if (line.Count > 0) {
|
||||
rune = line [0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
rune = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MovePrev (ref int col, ref int row, out Rune rune)
|
||||
{
|
||||
var line = model.GetLine (row);
|
||||
|
||||
if (col > 0) {
|
||||
col--;
|
||||
rune = line [col];
|
||||
return true;
|
||||
}
|
||||
if (row == 0) {
|
||||
rune = 0;
|
||||
return false;
|
||||
}
|
||||
while (row > 0) {
|
||||
row--;
|
||||
line = model.GetLine (row);
|
||||
col = line.Count - 1;
|
||||
if (col >= 0) {
|
||||
rune = line [col];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
rune = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
(int col, int row)? WordForward (int fromCol, int fromRow)
|
||||
{
|
||||
var col = fromCol;
|
||||
var row = fromRow;
|
||||
var line = GetCurrentLine ();
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (fromCol != col || fromRow != row)
|
||||
return (col, row);
|
||||
return null;
|
||||
}
|
||||
|
||||
(int col, int row)? WordBackward (int fromCol, int fromRow)
|
||||
{
|
||||
if (fromRow == 0 && fromCol == 0)
|
||||
return null;
|
||||
|
||||
var col = fromCol;
|
||||
var row = fromRow;
|
||||
var line = GetCurrentLine ();
|
||||
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 (fromCol != col || fromRow != row)
|
||||
return (col, row);
|
||||
return null;
|
||||
}
|
||||
|
||||
#if false
|
||||
int WordForward (int p)
|
||||
{
|
||||
if (p >= text.Length)
|
||||
return -1;
|
||||
|
||||
int i = p;
|
||||
if (Rune.IsPunctuation (text [p]) || Rune.IsWhiteSpace (text [p])) {
|
||||
for (; i < text.Length; i++) {
|
||||
var r = text [i];
|
||||
if (Rune.IsLetterOrDigit (r))
|
||||
break;
|
||||
}
|
||||
for (; i < text.Length; i++) {
|
||||
var r = text [i];
|
||||
if (!Rune.IsLetterOrDigit (r))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (; i < text.Length; i++) {
|
||||
var r = text [i];
|
||||
if (!Rune.IsLetterOrDigit (r))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != p)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WordBackward (int p)
|
||||
{
|
||||
if (p == 0)
|
||||
return -1;
|
||||
|
||||
int i = p - 1;
|
||||
if (i == 0)
|
||||
return 0;
|
||||
|
||||
var ti = text [i];
|
||||
if (Rune.IsPunctuation (ti) || Rune.IsSymbol (ti) || Rune.IsWhiteSpace (ti)) {
|
||||
for (; i >= 0; i--) {
|
||||
if (Rune.IsLetterOrDigit (text [i]))
|
||||
break;
|
||||
}
|
||||
for (; i >= 0; i--) {
|
||||
if (!Rune.IsLetterOrDigit (text [i]))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (; i >= 0; i--) {
|
||||
if (!Rune.IsLetterOrDigit (text [i]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
|
||||
if (i != p)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public override bool MouseEvent (MouseEvent ev)
|
||||
{
|
||||
if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked))
|
||||
|
||||
Reference in New Issue
Block a user