Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
1b31d54
Release new `main` build (#5005)
tig Apr 19, 2026
c700d81
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
cdd67d8
Updates the sample.gif (#5007)
tig Apr 20, 2026
c511c14
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
8f14fdc
Fix remaining TextView issues (#4987)
BDisp Apr 20, 2026
a79b1a2
Fixes UICatalog --version, adds release workflows and maintainer docs…
tig Apr 20, 2026
5b5045e
Fixes `AppModel.Inline` issues needed for `Output-ConsoleGridView` to…
tig Apr 20, 2026
6c77b70
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
5c9fc9c
Fixes prepare release workflow (#5015)
tig Apr 20, 2026
c743916
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
fa8ebd8
Fix version numbering: auto-increment pre-release from existing tags …
tig Apr 20, 2026
f98bdee
Fix/prepare release (#5019)
tig Apr 20, 2026
95a095b
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
52b2d22
Fixes #4843. Button: avoid create-then-destroy shadow allocation via …
Copilot Apr 20, 2026
0c7dee4
Bump Markdig from 1.1.2 to 1.1.3 (#5017)
dependabot[bot] Apr 20, 2026
487e8b7
Back-merge v2.0.0-beta.218 from main into develop (#5022)
tig Apr 20, 2026
962e15b
Merge pull request #5024 from gui-cs/backmerge/v2.0.0-rc.1
tig Apr 20, 2026
10e1773
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
f9fb3fc
Adds `TreeView.GetSize` (#5025)
tig Apr 20, 2026
033a494
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
a1e11ce
Ensures `CollectionNavigator` does not repond to alt or ctrl keys (#5…
tig Apr 20, 2026
f11f46b
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
806b14f
fixed gitversion yml bug
tig Apr 20, 2026
c50ed2a
Fixes #4865. Add v1→v2 corrections table and expand agent-facing file…
Copilot Apr 20, 2026
022870e
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 20, 2026
ec4afa7
Fixes #5008. Fix Markdown codeblock background attribute (#5011)
Copilot Apr 21, 2026
c0ee2c5
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 21, 2026
7229e11
Fixes #5028. TextView still has remaining's bugs (#5029)
BDisp Apr 21, 2026
7fd0aea
Merge branch 'develop' of github.com:gui-cs/Terminal.Gui into develop
tig Apr 21, 2026
ea11eb0
Fix/prepare release versioning (#5034)
tig Apr 21, 2026
9ca38ad
Release v2.0.0-rc.2 (#5030) (#5031)
tig Apr 21, 2026
3112421
back merge from Main (#5037)
tig Apr 21, 2026
96dec40
Fixes #4970 - Dialog arrangement (#5033)
tig Apr 21, 2026
956ba44
Update READMEs for v2.0.0 stable release (#5039)
tig Apr 21, 2026
877b765
fix(build): add Microsoft.Net.Compilers.Toolset package reference (#5…
rcdailey Apr 21, 2026
c2e928d
Fixes #5040. SelectorBase.TabBehavior setter calls CreateSubViews() w…
BDisp Apr 22, 2026
975c390
Fixes #5043 - `View.ScrollBars` now only show if they fit - Fixes `Vi…
tig Apr 22, 2026
3ed3a9b
Bump Microsoft.NET.Test.Sdk from 18.4.0 to 18.5.0 (#5051)
dependabot[bot] Apr 22, 2026
ced30cb
Back-merge v2.0.0-rc.4 from main into develop (#5054)
tig Apr 22, 2026
9fc8df5
Fixes #4955. Move mdv sample to its own gui-cs repo (#5056)
Copilot Apr 22, 2026
052d5c0
Fixes #5057. Pressing `Alt-T` in a `TextField` causes a `t` to be ent…
BDisp Apr 23, 2026
2cbfb92
Fix stale test project references in CLAUDE.md (#5070)
harder Apr 24, 2026
ec86b77
docs: add hero image to README (#5058)
livlign Apr 25, 2026
7f3c9ea
Fixes #5065. Pressing Shift-Alt-T in a TextField causes a t to be ent…
BDisp Apr 25, 2026
3dbaceb
Fixes #4963, #5064. FileDialog nav fixes & TableView redesign (#5062)
tig Apr 26, 2026
2d85832
Fixes #4179. `SetFocus` on `CanFocus == false` should still set focus…
BDisp Apr 26, 2026
56336a5
Fixes #452. TextView: TextView.LoadFile keeps file open and provides …
BDisp Apr 26, 2026
f12f771
Fixes #5069. ConfigurationManager is trim-safe without TrimmerRootAss…
harder Apr 26, 2026
dfa8967
Fixes #5080. WindowsDriver isn't showing the cursor after exit (#5081)
BDisp Apr 26, 2026
3976180
Fixes #5078. Handle JSON `null` root in `SourcesManager.Load` (#5079)
Copilot Apr 26, 2026
d6b5f81
Fixes #5060. TextField in ReadOnly mode should not automatically scro…
BDisp Apr 27, 2026
d4dcf0b
merged main->develop
tig Apr 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,14 @@ public bool Copy ()

App?.Clipboard?.SetClipboardData (SelectedText);

if (!ReadOnly)
{
return true;
}
_insertionPoint = 0;
ScrollOffset = 0;
ClearAllSelection ();

return true;
}

Expand Down
26 changes: 22 additions & 4 deletions Terminal.Gui/Views/TextInput/TextField/TextField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,12 @@ public TextField ()

private void TextField_Initialized (object? sender, EventArgs e)
{
_insertionPoint = GraphemeHelper.GetGraphemeCount (Text);
if (!ReadOnly)
{
_insertionPoint = GraphemeHelper.GetGraphemeCount (Text);
}

if (Viewport.Width > 0)
if (!ReadOnly && Viewport.Width > 0)
{
int colsWidth = Text.GetColumns ();
ScrollOffset = colsWidth > Viewport.Width + 1 ? colsWidth - Viewport.Width + 1 : 0;
Expand Down Expand Up @@ -145,12 +148,27 @@ protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocus
App.Mouse.UngrabMouse ();
}

// If gaining focus via keyboard (not mouse), select all text
if (newHasFocus && !_focusSetByMouse && _text.Count > 0)
// If gaining focus via keyboard (not mouse), select all text if not ReadOnly
if (newHasFocus && !ReadOnly && !_focusSetByMouse && _text.Count > 0)
{
SelectAll ();
}

if (ReadOnly && InsertionPoint > 0)
{
_insertionPoint = 0;
}

if (ReadOnly && ScrollOffset > 0)
{
ScrollOffset = 0;
}

if (ReadOnly && SelectedLength > 0)
{
ClearAllSelection ();
}

// Reset the flag after handling focus change
_focusSetByMouse = false;

Expand Down
121 changes: 121 additions & 0 deletions Tests/UnitTestsParallelizable/Views/TextFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1539,4 +1539,125 @@ public void CtrlKey_With_AssociatedText_Does_Not_Insert_Into_TextField ()

Assert.Equal ("", tf.Text);
}

[Fact]
public void ReadOnly_ShouldNotAllowAutomaticallyScrolling_AndMustSetInsertionPointToZeroAtInitialization ()
{
TextField tf = new () { Width = 5, ReadOnly = true, Text = "hello world" };
tf.BeginInit ();
tf.EndInit ();

Assert.Equal (0, tf.InsertionPoint);
Assert.Equal (0, tf.ScrollOffset);
Assert.Null (tf.SelectedText);
}

[Fact]
public void ReadOnly_ShouldNotSelectAllText_OnFocus ()
{
TextField tf = new () { Width = 5, ReadOnly = true, Text = "hello world" };
tf.BeginInit ();
tf.EndInit ();

tf.SetFocus ();

Assert.Equal (0, tf.InsertionPoint);
Assert.Equal (0, tf.ScrollOffset);
Assert.Null (tf.SelectedText);
}

[Fact]
public void ReadOnly_ShouldSetInsertionPointAndScrollOffsetToZero_OnFocus ()
{
TextField tf = new () { Width = 5, ReadOnly = true, Text = "hello world" };
tf.BeginInit ();
tf.EndInit ();

// Move insertion point to end of text
tf.InsertionPoint = tf.Text.Length;
Assert.Equal (11, tf.InsertionPoint);
Assert.Equal (7, tf.ScrollOffset);

// Set focus and verify insertion point is still at zero
tf.SetFocus ();
Assert.Equal (0, tf.InsertionPoint);
Assert.Equal (0, tf.ScrollOffset);
}

[Fact]
public void ReadOnly_ShouldSetInsertionPointAndScrollOffsetToZero_LeavingFocus ()
{
TextField tf = new () { Width = 5, ReadOnly = true, Text = "hello world" };

// Create another view to take focus away
View otherView = new () { CanFocus = true };

// Create a container to hold both views
Runnable container = new () { Id = "container", Width = 20, Height = 5 };
container.Add (tf, otherView);
container.BeginInit ();
container.EndInit ();

// Set focus to TextField and verify insertion point and scroll offset are at zero
tf.SetFocus ();
Assert.Equal (0, tf.InsertionPoint);
Assert.Equal (0, tf.ScrollOffset);

// Move insertion point to end of text and then move focus away to verify insertion point is still at zero
tf.InsertionPoint = tf.Text.Length;
Assert.Equal (11, tf.InsertionPoint);
Assert.Equal (7, tf.ScrollOffset);

otherView.SetFocus ();
Assert.Equal (0, tf.InsertionPoint);
Assert.Equal (0, tf.ScrollOffset);
}

[Fact]
public void ReadOnly_ShouldSetInsertionPointAndScrollOffsetToZero_AfterCopyingText ()
{
TextField tf = new () { Width = 5, ReadOnly = true, Text = "hello world" };
tf.BeginInit ();
tf.EndInit ();

// Select all text
tf.SelectAll ();
Assert.Equal (11, tf.InsertionPoint);
Assert.Equal (7, tf.ScrollOffset);
Assert.Equal ("hello world", tf.SelectedText);

// Copy text and verify insertion point and scroll offset are still at zero
tf.Copy ();
Assert.Equal (0, tf.InsertionPoint);
Assert.Equal (0, tf.ScrollOffset);
Assert.Null (tf.SelectedText);
}

[Fact]
public void ReadOnly_ShouldSetInsertionPointAndScrollOffsetToZeroAndClearAllSelection_OnLeavingFocus ()
{
TextField tf = new () { Width = 5, ReadOnly = true, Text = "hello world" };

// Create another view to take focus away
View otherView = new () { CanFocus = true };

// Create a container to hold both views
Runnable container = new () { Id = "container", Width = 20, Height = 5 };
container.Add (tf, otherView);
container.BeginInit ();
container.EndInit ();

// Set focus to TextField and select all text
tf.SetFocus ();
tf.SelectAll ();
Assert.Equal (11, tf.InsertionPoint);
Assert.Equal (7, tf.ScrollOffset);
Assert.Equal ("hello world", tf.SelectedText);

// Move focus away and verify insertion point and scroll offset are at zero and selection is cleared
otherView.SetFocus ();
Assert.Equal (0, tf.InsertionPoint);
Assert.Equal (0, tf.ScrollOffset);
Assert.Null (tf.SelectedText);
}
}
Loading