diff --git a/Terminal.Gui/Core.cs b/Terminal.Gui/Core.cs
index 50cfce26d..71a1408a8 100644
--- a/Terminal.Gui/Core.cs
+++ b/Terminal.Gui/Core.cs
@@ -1176,7 +1176,7 @@ namespace Terminal.Gui {
/// to the mainloop, allowing user code to use async/await.
///
///
- public class Application {
+ public static class Application {
///
/// The current Console Driver in use.
///
@@ -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 {
///
public static void RequestStop ()
{
- var ct = Current as Toplevel;
-
Current.Running = false;
}
diff --git a/Terminal.Gui/Dialogs/MessageBox.cs b/Terminal.Gui/Dialogs/MessageBox.cs
index 485b92a60..5fa9edb4d 100644
--- a/Terminal.Gui/Dialogs/MessageBox.cs
+++ b/Terminal.Gui/Dialogs/MessageBox.cs
@@ -21,7 +21,7 @@ namespace Terminal.Gui {
///
///
///
- public class MessageBox {
+ public static class MessageBox {
///
/// Presents a message with the specified title and message and a list of buttons to show to the user.
///
diff --git a/Terminal.Gui/Driver.cs b/Terminal.Gui/Driver.cs
index 34042ed18..674173a97 100644
--- a/Terminal.Gui/Driver.cs
+++ b/Terminal.Gui/Driver.cs
@@ -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)
diff --git a/Terminal.Gui/MonoCurses/mainloop.cs b/Terminal.Gui/MonoCurses/mainloop.cs
index 633e9a702..919f706ab 100644
--- a/Terminal.Gui/MonoCurses/mainloop.cs
+++ b/Terminal.Gui/MonoCurses/mainloop.cs
@@ -407,8 +407,10 @@ namespace Mono.Terminal {
}
}
- if (idleHandlers.Count > 0)
- RunIdle ();
+ lock (idleHandlers){
+ if (idleHandlers.Count > 0)
+ RunIdle();
+ }
}
///
diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs
index 75394d309..cf1630b2e 100644
--- a/Terminal.Gui/Views/Button.cs
+++ b/Terminal.Gui/Views/Button.cs
@@ -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;
diff --git a/Terminal.Gui/Views/Checkbox.cs b/Terminal.Gui/Views/Checkbox.cs
index d9b5f3996..4e672200f 100644
--- a/Terminal.Gui/Views/Checkbox.cs
+++ b/Terminal.Gui/Views/Checkbox.cs
@@ -15,7 +15,7 @@ namespace Terminal.Gui {
public class CheckBox : View {
ustring text;
int hot_pos = -1;
- char hot_key;
+ Rune hot_key;
///
/// 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;
diff --git a/Terminal.Gui/Views/Clipboard.cs b/Terminal.Gui/Views/Clipboard.cs
index be6000269..eb1860f10 100644
--- a/Terminal.Gui/Views/Clipboard.cs
+++ b/Terminal.Gui/Views/Clipboard.cs
@@ -2,7 +2,7 @@
using NStack;
namespace Terminal.Gui {
- public class Clipboard {
+ public static class Clipboard {
public static ustring Contents { get; set; }
}
}
diff --git a/Terminal.Gui/Views/Label.cs b/Terminal.Gui/Views/Label.cs
index 433334c97..0c276b9ad 100644
--- a/Terminal.Gui/Views/Label.cs
+++ b/Terminal.Gui/Views/Label.cs
@@ -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 ();
Recalc (text, result, width, TextAlignment.Left);
- return result.Count ();
+ return result.Count;
}
///
diff --git a/Terminal.Gui/Views/ListView.cs b/Terminal.Gui/Views/ListView.cs
index 5f67e6d62..f58e1a07f 100644
--- a/Terminal.Gui/Views/ListView.cs
+++ b/Terminal.Gui/Views/ListView.cs
@@ -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)
diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs
index a5cdc34bc..109548a5c 100644
--- a/Terminal.Gui/Views/Menu.cs
+++ b/Terminal.Gui/Views/Menu.cs
@@ -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 {
diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs
index b5ca54651..3946a4b26 100644
--- a/Terminal.Gui/Views/TextView.cs
+++ b/Terminal.Gui/Views/TextView.cs
@@ -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 ();
}
+ ///
+ /// The number of text lines in the model
+ ///
public int Count => lines.Count;
+ ///
+ /// Returns the specified line as a List of Rune
+ ///
+ /// The line.
+ /// Line number to retrieve.
public List GetLine (int line) => lines [line];
+ ///
+ /// Adds a line to the model at the specified position.
+ ///
+ /// Line number where the line will be inserted.
+ /// The line of text, as a List of Rune.
public void AddLine (int pos, List runes)
{
lines.Insert (pos, runes);
}
+ ///
+ /// Removes the line at the specified position
+ ///
+ /// Position.
public void RemoveLine (int pos)
{
lines.RemoveAt (pos);
@@ -306,15 +326,14 @@ namespace Terminal.Gui {
/// Loads the contents of the stream into the TextView.
///
/// true, if stream was loaded, false otherwise.
- /// Stream.
- public bool LoadStream (Stream stream)
+ /// Stream to load the contents from.
+ 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;
}
///
@@ -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))
diff --git a/demo.cs b/demo.cs
index 90c95bbae..33cfef9c3 100644
--- a/demo.cs
+++ b/demo.cs
@@ -2,7 +2,7 @@ using Terminal.Gui;
using System;
using Mono.Terminal;
-class Demo {
+static class Demo {
class Box10x : View {
public Box10x (int x, int y) : base (new Rect (x, y, 10, 10))
{