mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
Merge branch 'v1_develop' into v1_release
This commit is contained in:
4
.github/workflows/api-docs.yml
vendored
4
.github/workflows/api-docs.yml
vendored
@@ -3,7 +3,9 @@ name: Build and publish API docs
|
||||
on:
|
||||
push:
|
||||
# only publish v2 (main or develop); v2 is published via the Terminal.GuiV2Docs repo
|
||||
branches: [main, develop]
|
||||
branches: [v1_release, v1_develop]
|
||||
paths:
|
||||
- docfx/**
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -25,7 +25,7 @@ on:
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
|
||||
if: github.repository == 'gui-cs/Terminal.Gui'|| github.event_name == 'schedule'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
1
.github/workflows/codeql.yml
vendored
1
.github/workflows/codeql.yml
vendored
@@ -29,6 +29,7 @@ jobs:
|
||||
# Consider using larger runners for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
if: github.repository == 'gui-cs/Terminal.Gui'|| github.event_name == 'schedule'
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
6
.github/workflows/dotnet-core.yml
vendored
6
.github/workflows/dotnet-core.yml
vendored
@@ -2,18 +2,18 @@ name: .NET Core
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
branches: [ v1_release, v1_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
branches: [ v1_release, v1_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
@@ -2,7 +2,7 @@ name: Publish Terminal.Gui
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop, v2_release, v2_develop ]
|
||||
branches: [ v1_release, v1_develop, v2_release, v2_develop ]
|
||||
tags:
|
||||
- v*
|
||||
paths-ignore:
|
||||
|
||||
@@ -12,8 +12,8 @@ We welcome contributions from the community. See [Issues](https://github.com/gui
|
||||
|
||||
Terminal.Gui uses the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branching model.
|
||||
|
||||
* The `main` branch is always stable, and always matches the most recently released Nuget package.
|
||||
* The `develop` branch is where bug-fixes to v1.x happens. It is the default branch.
|
||||
* The `v1_release` branch is always stable, and always matches the most recently released Nuget package.
|
||||
* The `v1__develop` branch is where bug-fixes to v1.x happens. It is the default branch.
|
||||
* The `v2_develop` branch is where development on v2.x happens.
|
||||
|
||||
### Forking Terminal.Gui
|
||||
|
||||
@@ -7,22 +7,23 @@ using Terminal.Gui;
|
||||
|
||||
Application.Run<ExampleWindow> ();
|
||||
|
||||
System.Console.WriteLine ($"Username: {((ExampleWindow)Application.Top).usernameText.Text}");
|
||||
|
||||
// Before the application exits, reset Terminal.Gui for clean shutdown
|
||||
Application.Shutdown ();
|
||||
|
||||
System.Console.WriteLine ($@"Username: {ExampleWindow.Username}");
|
||||
|
||||
// Defines a top-level window with border and title
|
||||
public class ExampleWindow : Window {
|
||||
public static string Username { get; internal set; }
|
||||
public TextField usernameText;
|
||||
|
||||
|
||||
public ExampleWindow ()
|
||||
{
|
||||
Title = "Example App (Ctrl+Q to quit)";
|
||||
|
||||
// Create input components and labels
|
||||
var usernameLabel = new Label () {
|
||||
Text = "Username:"
|
||||
var usernameLabel = new Label () {
|
||||
Text = "Username:"
|
||||
};
|
||||
|
||||
usernameText = new TextField ("") {
|
||||
@@ -50,7 +51,7 @@ public class ExampleWindow : Window {
|
||||
// Create login button
|
||||
var btnLogin = new Button () {
|
||||
Text = "Login",
|
||||
Y = Pos.Bottom(passwordLabel) + 1,
|
||||
Y = Pos.Bottom (passwordLabel) + 1,
|
||||
// center the login button horizontally
|
||||
X = Pos.Center (),
|
||||
IsDefault = true,
|
||||
@@ -60,6 +61,7 @@ public class ExampleWindow : Window {
|
||||
btnLogin.Clicked += () => {
|
||||
if (usernameText.Text == "admin" && passwordText.Text == "password") {
|
||||
MessageBox.Query ("Logging In", "Login Successful", "Ok");
|
||||
Username = usernameText.Text.ToString ();
|
||||
Application.RequestStop ();
|
||||
} else {
|
||||
MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
|
||||
|
||||
@@ -2,25 +2,26 @@ mode: ContinuousDeployment
|
||||
tag-prefix: '[vV]'
|
||||
continuous-delivery-fallback-tag: pre
|
||||
branches:
|
||||
develop:
|
||||
v1_develop:
|
||||
mode: ContinuousDeployment
|
||||
tag: pre
|
||||
regex: develop
|
||||
regex: v1_develop
|
||||
source-branches:
|
||||
- main
|
||||
- v1_release
|
||||
pre-release-weight: 100
|
||||
main:
|
||||
v1_release:
|
||||
tag: rc
|
||||
increment: Patch
|
||||
regex: v1_release
|
||||
source-branches:
|
||||
- develop
|
||||
- main
|
||||
feature:
|
||||
- v1_develop
|
||||
- v1_release
|
||||
v1_feature:
|
||||
tag: useBranchName
|
||||
regex: ^features?[/-]
|
||||
source-branches:
|
||||
- develop
|
||||
- main
|
||||
- v1_develop
|
||||
- v1_release
|
||||
pull-request:
|
||||
tag: PullRequest.{BranchName}
|
||||
increment: Inherit
|
||||
|
||||
19
README.md
19
README.md
@@ -38,7 +38,7 @@ dotnet run
|
||||
* [Conceptual Documentation](https://gui-cs.github.io/Terminal.Gui/docs/index.html)
|
||||
* [API Documentation](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui)
|
||||
|
||||
_The Documentation matches the most recent Nuget release from the `main` branch ([](https://www.nuget.org/packages/Terminal.Gui))_
|
||||
_The Documentation matches the most recent Nuget release from the `v1_release_` branch ([](https://www.nuget.org/packages/Terminal.Gui))_
|
||||
|
||||
See the [`Terminal.Gui/` README](https://github.com/gui-cs/Terminal.Gui/tree/master/Terminal.Gui) for an overview of how the library is structured. The [Conceptual Documentation](https://gui-cs.github.io/Terminal.Gui/docs/index.html) provides insight into core concepts.
|
||||
|
||||
@@ -64,28 +64,32 @@ The team is looking forward to seeing new amazing projects made by the community
|
||||
The following example shows a basic Terminal.Gui application in C#:
|
||||
|
||||
```csharp
|
||||
// This is a simple example application. For the full range of functionality
|
||||
// see the UICatalog project
|
||||
|
||||
// A simple Terminal.Gui example in C# - using C# 9.0 Top-level statements
|
||||
|
||||
using Terminal.Gui;
|
||||
|
||||
Application.Run<ExampleWindow> ();
|
||||
|
||||
System.Console.WriteLine ($"Username: {((ExampleWindow)Application.Top).usernameText.Text}");
|
||||
|
||||
// Before the application exits, reset Terminal.Gui for clean shutdown
|
||||
Application.Shutdown ();
|
||||
|
||||
System.Console.WriteLine ($@"Username: {ExampleWindow.Username}");
|
||||
|
||||
// Defines a top-level window with border and title
|
||||
public class ExampleWindow : Window {
|
||||
public static string Username { get; internal set; }
|
||||
public TextField usernameText;
|
||||
|
||||
|
||||
public ExampleWindow ()
|
||||
{
|
||||
Title = "Example App (Ctrl+Q to quit)";
|
||||
|
||||
// Create input components and labels
|
||||
var usernameLabel = new Label () {
|
||||
Text = "Username:"
|
||||
var usernameLabel = new Label () {
|
||||
Text = "Username:"
|
||||
};
|
||||
|
||||
usernameText = new TextField ("") {
|
||||
@@ -113,7 +117,7 @@ public class ExampleWindow : Window {
|
||||
// Create login button
|
||||
var btnLogin = new Button () {
|
||||
Text = "Login",
|
||||
Y = Pos.Bottom(passwordLabel) + 1,
|
||||
Y = Pos.Bottom (passwordLabel) + 1,
|
||||
// center the login button horizontally
|
||||
X = Pos.Center (),
|
||||
IsDefault = true,
|
||||
@@ -123,6 +127,7 @@ public class ExampleWindow : Window {
|
||||
btnLogin.Clicked += () => {
|
||||
if (usernameText.Text == "admin" && passwordText.Text == "password") {
|
||||
MessageBox.Query ("Logging In", "Login Successful", "Ok");
|
||||
Username = usernameText.Text.ToString ();
|
||||
Application.RequestStop ();
|
||||
} else {
|
||||
MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
|
||||
|
||||
@@ -752,9 +752,9 @@ namespace Terminal.Gui {
|
||||
contents = new int [Rows, Cols, 3];
|
||||
for (int row = 0; row < Rows; row++) {
|
||||
for (int col = 0; col < Cols; col++) {
|
||||
//Curses.move (row, col);
|
||||
//Curses.attrset (Colors.TopLevel.Normal);
|
||||
//Curses.addch ((int)(uint)' ');
|
||||
Curses.move (row, col);
|
||||
Curses.attrset (Colors.TopLevel.Normal);
|
||||
Curses.addch ((int)(uint)' ');
|
||||
contents [row, col, 0] = ' ';
|
||||
contents [row, col, 1] = Colors.TopLevel.Normal;
|
||||
contents [row, col, 2] = 0;
|
||||
|
||||
@@ -256,7 +256,7 @@ namespace Unix.Terminal {
|
||||
/// to avoid the dependency on libc-dev Linux.
|
||||
/// </summary>
|
||||
static class CoreCLR {
|
||||
#if NET7_0
|
||||
#if NET6_0_OR_GREATER
|
||||
// Custom resolver to support true single-file apps
|
||||
// (those which run directly from bundle; in-memory).
|
||||
// -1 on Unix means self-referencing binary (libcoreclr.so)
|
||||
|
||||
@@ -113,7 +113,9 @@ namespace Terminal.Gui {
|
||||
ConsoleDriver consoleDriver;
|
||||
volatile ConsoleKeyInfo [] cki = null;
|
||||
static volatile bool isEscSeq;
|
||||
bool stopTasks;
|
||||
|
||||
internal CancellationTokenSource TokenSource = new CancellationTokenSource ();
|
||||
|
||||
#if PROCESS_REQUEST
|
||||
bool neededProcessRequest;
|
||||
#endif
|
||||
@@ -125,21 +127,13 @@ namespace Terminal.Gui {
|
||||
throw new ArgumentNullException ("Console driver instance must be provided.");
|
||||
}
|
||||
this.consoleDriver = consoleDriver;
|
||||
Task.Run (ProcessInputResultQueue);
|
||||
Task.Run (CheckWinChange);
|
||||
}
|
||||
|
||||
internal void StopTasks ()
|
||||
{
|
||||
stopTasks = true;
|
||||
Task.Run (ProcessInputResultQueue, TokenSource.Token);
|
||||
Task.Run (CheckWinChange, TokenSource.Token);
|
||||
}
|
||||
|
||||
public InputResult? ReadConsoleInput ()
|
||||
{
|
||||
while (true) {
|
||||
if (stopTasks) {
|
||||
return null;
|
||||
}
|
||||
while (!TokenSource.IsCancellationRequested) {
|
||||
waitForStart.Set ();
|
||||
winChange.Set ();
|
||||
|
||||
@@ -154,11 +148,13 @@ namespace Terminal.Gui {
|
||||
return inputResultQueue.Dequeue ();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void ProcessInputResultQueue ()
|
||||
{
|
||||
while (true) {
|
||||
while (!TokenSource.IsCancellationRequested) {
|
||||
waitForStart.Wait ();
|
||||
waitForStart.Reset ();
|
||||
|
||||
@@ -176,8 +172,23 @@ namespace Terminal.Gui {
|
||||
ConsoleModifiers mod = 0;
|
||||
ConsoleKeyInfo newConsoleKeyInfo = default;
|
||||
|
||||
while (true) {
|
||||
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey (true);
|
||||
while (!TokenSource.IsCancellationRequested) {
|
||||
ConsoleKeyInfo consoleKeyInfo = default;
|
||||
|
||||
try {
|
||||
if (Console.KeyAvailable) {
|
||||
consoleKeyInfo = Console.ReadKey (true);
|
||||
} else {
|
||||
Task.Delay (100, TokenSource.Token).Wait (TokenSource.Token);
|
||||
if (Console.KeyAvailable) {
|
||||
consoleKeyInfo = Console.ReadKey (true);
|
||||
}
|
||||
}
|
||||
} catch (OperationCanceledException) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((consoleKeyInfo.KeyChar == (char)Key.Esc && !isEscSeq)
|
||||
|| (consoleKeyInfo.KeyChar != (char)Key.Esc && isEscSeq)) {
|
||||
if (cki == null && consoleKeyInfo.KeyChar != (char)Key.Esc && isEscSeq) {
|
||||
@@ -201,18 +212,19 @@ namespace Terminal.Gui {
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
GetConsoleInputType (consoleKeyInfo);
|
||||
break;
|
||||
if (consoleKeyInfo != default) {
|
||||
GetConsoleInputType (consoleKeyInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TokenSource.Token.ThrowIfCancellationRequested ();
|
||||
}
|
||||
}
|
||||
|
||||
void CheckWinChange ()
|
||||
{
|
||||
while (true) {
|
||||
if (stopTasks) {
|
||||
return;
|
||||
}
|
||||
while (!TokenSource.IsCancellationRequested) {
|
||||
winChange.Wait ();
|
||||
winChange.Reset ();
|
||||
WaitWinChange ();
|
||||
@@ -222,13 +234,16 @@ namespace Terminal.Gui {
|
||||
|
||||
void WaitWinChange ()
|
||||
{
|
||||
while (true) {
|
||||
// Wait for a while then check if screen has changed sizes
|
||||
Task.Delay (500).Wait ();
|
||||
while (!TokenSource.IsCancellationRequested) {
|
||||
try {
|
||||
// Wait for a while then check if screen has changed sizes
|
||||
Task.Delay (500, TokenSource.Token).Wait (TokenSource.Token);
|
||||
|
||||
} catch (OperationCanceledException) {
|
||||
|
||||
if (stopTasks) {
|
||||
return;
|
||||
}
|
||||
|
||||
int buffHeight, buffWidth;
|
||||
if (((NetDriver)consoleDriver).IsWinPlatform) {
|
||||
buffHeight = Math.Max (Console.BufferHeight, 0);
|
||||
@@ -691,7 +706,7 @@ namespace Terminal.Gui {
|
||||
|
||||
public override void End ()
|
||||
{
|
||||
mainLoop.netEvents.StopTasks ();
|
||||
mainLoop.Dispose ();
|
||||
|
||||
if (IsWinPlatform) {
|
||||
NetWinConsole.Cleanup ();
|
||||
@@ -1019,8 +1034,28 @@ namespace Terminal.Gui {
|
||||
|
||||
public override void Suspend ()
|
||||
{
|
||||
}
|
||||
if (Environment.OSVersion.Platform != PlatformID.Unix) {
|
||||
return;
|
||||
}
|
||||
|
||||
StopReportingMouseMoves ();
|
||||
Console.ResetColor ();
|
||||
Console.Clear ();
|
||||
|
||||
//Disable alternative screen buffer.
|
||||
Console.Out.Write ("\x1b[?1049l");
|
||||
|
||||
//Set cursor key to cursor.
|
||||
Console.Out.Write ("\x1b[?25h");
|
||||
|
||||
Platform.Suspend ();
|
||||
|
||||
//Enable alternative screen buffer.
|
||||
Console.Out.Write ("\x1b[?1049h");
|
||||
|
||||
Application.Refresh ();
|
||||
StartReportingMouseMoves ();
|
||||
}
|
||||
|
||||
public override void SetAttribute (Attribute c)
|
||||
{
|
||||
@@ -1343,7 +1378,11 @@ namespace Terminal.Gui {
|
||||
public override bool SetCursorVisibility (CursorVisibility visibility)
|
||||
{
|
||||
savedCursorVisibility = visibility;
|
||||
return Console.CursorVisible = visibility == CursorVisibility.Default;
|
||||
Console.Out.Write (visibility == CursorVisibility.Default
|
||||
? "\x1b[?25h"
|
||||
: "\x1b[?25l");
|
||||
|
||||
return visibility == CursorVisibility.Default;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -1423,7 +1462,7 @@ namespace Terminal.Gui {
|
||||
/// <remarks>
|
||||
/// This implementation is used for NetDriver.
|
||||
/// </remarks>
|
||||
internal class NetMainLoop : IMainLoopDriver {
|
||||
internal class NetMainLoop : IMainLoopDriver, IDisposable {
|
||||
ManualResetEventSlim keyReady = new ManualResetEventSlim (false);
|
||||
ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false);
|
||||
Queue<NetEvents.InputResult?> inputResult = new Queue<NetEvents.InputResult?> ();
|
||||
@@ -1453,27 +1492,25 @@ namespace Terminal.Gui {
|
||||
|
||||
void NetInputHandler ()
|
||||
{
|
||||
while (true) {
|
||||
while (!tokenSource.IsCancellationRequested) {
|
||||
waitForProbe.Wait ();
|
||||
waitForProbe.Reset ();
|
||||
if (inputResult.Count == 0) {
|
||||
inputResult.Enqueue (netEvents.ReadConsoleInput ());
|
||||
}
|
||||
try {
|
||||
while (inputResult.Peek () == null) {
|
||||
inputResult.Dequeue ();
|
||||
}
|
||||
if (inputResult.Count > 0) {
|
||||
keyReady.Set ();
|
||||
}
|
||||
} catch (InvalidOperationException) { }
|
||||
while (inputResult.Count > 0 && inputResult.Peek () == null) {
|
||||
inputResult.Dequeue ();
|
||||
}
|
||||
if (inputResult.Count > 0) {
|
||||
keyReady.Set ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IMainLoopDriver.Setup (MainLoop mainLoop)
|
||||
{
|
||||
this.mainLoop = mainLoop;
|
||||
Task.Run (NetInputHandler);
|
||||
Task.Run (NetInputHandler, tokenSource.Token);
|
||||
}
|
||||
|
||||
void IMainLoopDriver.Wakeup ()
|
||||
@@ -1503,8 +1540,7 @@ namespace Terminal.Gui {
|
||||
return inputResult.Count > 0 || CheckTimers (wait, out _);
|
||||
}
|
||||
|
||||
tokenSource.Dispose ();
|
||||
tokenSource = new CancellationTokenSource ();
|
||||
tokenSource.Token.ThrowIfCancellationRequested ();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1537,5 +1573,11 @@ namespace Terminal.Gui {
|
||||
ProcessInput?.Invoke (inputResult.Dequeue ().Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
tokenSource.Cancel ();
|
||||
netEvents.TokenSource.Cancel ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ namespace Terminal.Gui {
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// When invoked sets the SynchronizationContext to one that is tied
|
||||
/// to the mainloop, allowing user code to use async/await.
|
||||
/// to the MainLoop, allowing user code to use async/await.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class Application {
|
||||
@@ -1037,6 +1037,7 @@ namespace Terminal.Gui {
|
||||
toplevel.LayoutSubviews ();
|
||||
toplevel.PositionToplevels ();
|
||||
toplevel.WillPresent ();
|
||||
EnsuresTopOnFront ();
|
||||
if (refreshDriver) {
|
||||
MdiTop?.OnChildLoaded (toplevel);
|
||||
toplevel.OnLoaded ();
|
||||
@@ -1133,9 +1134,9 @@ namespace Terminal.Gui {
|
||||
|
||||
// BUGBUG: MdiTop is not cleared here, but it should be?
|
||||
|
||||
MainLoop = null;
|
||||
Driver?.End ();
|
||||
Driver = null;
|
||||
MainLoop = null;
|
||||
Iteration = null;
|
||||
RootMouseEvent = null;
|
||||
RootKeyEvent = null;
|
||||
|
||||
@@ -394,6 +394,10 @@ namespace Terminal.Gui {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SuperView is Toplevel && Application.Current?.Focused != SuperView) {
|
||||
Application.EnsuresTopOnFront ();
|
||||
}
|
||||
}
|
||||
OnCanFocusChanged ();
|
||||
SetNeedsDisplay ();
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace Terminal.Gui {
|
||||
|
||||
public override void OnCanFocusChanged ()
|
||||
{
|
||||
if (MostFocused == null && CanFocus && Visible) {
|
||||
if (HasFocus && MostFocused == null && CanFocus && Visible) {
|
||||
EnsureFocus ();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ Doing so will update the `.csproj` files in your branch with version info, which
|
||||
|
||||
The following actions will publish the Terminal.Gui package to Nuget:
|
||||
|
||||
* A new version tag is defined and pushed to `main` - this is the normal release process.
|
||||
* A push to the `main` branch without a new version tag - this is a release-candidate build and will be of the form `1.2.3-rc.4`
|
||||
* A push to the `develop` branch - this is a pre-release build and will be of the form `1.2.3-pre.4`
|
||||
* A new version tag is defined and pushed to `v1_release` - this is the normal release process.
|
||||
* A push to the `v1_release` branch without a new version tag - this is a release-candidate build and will be of the form `1.2.3-rc.4`
|
||||
* A push to the `v1_develop` branch - this is a pre-release build and will be of the form `1.2.3-pre.4`
|
||||
|
||||
## Publishing a Release of Terminal.Gui
|
||||
|
||||
@@ -71,17 +71,17 @@ The `tag` must be of the form `v<major>.<minor>.<patch>`, e.g. `v1.2.3`.
|
||||
|
||||
### 1) Verify the `develop` branch is ready for release
|
||||
|
||||
* Ensure everything is committed and pushed to the `develop` branch
|
||||
* Ensure your local `develop` branch is up-to-date with `upstream/develop`
|
||||
* Ensure everything is committed and pushed to the `v1_develop` branch
|
||||
* Ensure your local `v1_develop` branch is up-to-date with `upstream/v1_develop`
|
||||
|
||||
### 2) Create a pull request for the release in the `develop` branch
|
||||
### 2) Create a pull request for the release in the `v1_develop` branch
|
||||
|
||||
The PR title should be of the form "Release v1.2.3"
|
||||
|
||||
```powershell
|
||||
git checkout develop
|
||||
git pull upstream develop
|
||||
git checkout -b v2_3_4
|
||||
git checkout v1_develop
|
||||
git pull upstream v1_develop
|
||||
git checkout -b v1_2_3
|
||||
<touch a file>
|
||||
git add .
|
||||
git commit -m "Release v1.2.3"
|
||||
@@ -90,36 +90,36 @@ git push
|
||||
|
||||
Go to the link printed by `git push` and fill out the Pull Request.
|
||||
|
||||
### 3) On github.com, verify the build action worked on your fork, then merge the PR to `develop`
|
||||
### 3) On github.com, verify the build action worked on your fork, then merge the PR to `v1_develop`
|
||||
|
||||
* Merging the PR will trigger the publish action on `upstream` (the main repo) and publish the Nuget package as a pre-release (e.g. `1.2.3-pre.1`).
|
||||
|
||||
### 4) Pull the merged `develop` from `upstream`
|
||||
|
||||
```powershell
|
||||
git checkout develop
|
||||
git pull upstream develop
|
||||
git checkout v1_develop
|
||||
git pull upstream v1_develop
|
||||
```
|
||||
|
||||
### 5) Merge `develop` into `main`
|
||||
|
||||
```powershell
|
||||
git checkout main
|
||||
git pull upstream main
|
||||
git merge develop
|
||||
git checkout v1_release
|
||||
git pull upstream v1_release
|
||||
git merge v1_develop
|
||||
```
|
||||
|
||||
Fix any merge errors.
|
||||
|
||||
At this point, to release a release candidate, push the `main` branch `upstream` without a new tag.
|
||||
At this point, to release a release candidate, push the `v1_release` branch `upstream` without a new tag.
|
||||
|
||||
```powershell
|
||||
git push upstream main
|
||||
git push upstream v1_release
|
||||
```
|
||||
|
||||
This will publish `1.2.3-rc.1` to Nuget.
|
||||
|
||||
### 6) Create a new annotated tag for the release on `main`
|
||||
### 6) Create a new annotated tag for the release on `v1_release`
|
||||
|
||||
```powershell
|
||||
git tag v1.2.3 -a -m "Release v1.2.3"
|
||||
@@ -146,13 +146,13 @@ https://www.nuget.org/packages/Terminal.Gui
|
||||
|
||||
Generate release notes with the list of PRs since the last release.
|
||||
|
||||
### 11) Update the `develop` branch with the new version
|
||||
### 11) Update the `v1_develop` branch with the new version
|
||||
|
||||
```powershell
|
||||
git checkout develop
|
||||
git pull upstream develop
|
||||
git merge main
|
||||
git push upstream develop
|
||||
git checkout v1_develop
|
||||
git pull upstream v1_develop
|
||||
git merge v1_release
|
||||
git push upstream v1_develop
|
||||
```
|
||||
|
||||
## Nuget
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<DebugType>portable</DebugType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;netstandard2.0;netstandard2.1;net7.0;net8.0</TargetFrameworks>
|
||||
<TargetFrameworks>net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RootNamespace>Terminal.Gui</RootNamespace>
|
||||
<AssemblyName>Terminal.Gui</AssemblyName>
|
||||
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
|
||||
|
||||
@@ -601,10 +601,12 @@ namespace Terminal.Gui {
|
||||
/// <returns></returns>
|
||||
public virtual bool MoveEnd ()
|
||||
{
|
||||
if (source.Count > 0 && selected != source.Count - 1) {
|
||||
if (source?.Count > 0 && selected != source.Count - 1) {
|
||||
selected = source.Count - 1;
|
||||
if (top + selected > Frame.Height - 1) {
|
||||
top = selected;
|
||||
top = selected < Frame.Height - 1
|
||||
? Math.Max (Frame.Height - selected + 1, 0)
|
||||
: Math.Max (selected - Frame.Height + 1, 0);
|
||||
}
|
||||
OnSelectedChanged ();
|
||||
SetNeedsDisplay ();
|
||||
@@ -749,6 +751,11 @@ namespace Terminal.Gui {
|
||||
public void EnsureSelectedItemVisible ()
|
||||
{
|
||||
SuperView?.LayoutSubviews ();
|
||||
// If last item is selected and is removed, ensures a valid selected item
|
||||
if (Source != null && selected > Source.Count - 1) {
|
||||
SelectedItem = Source.Count - 1;
|
||||
SetNeedsDisplay ();
|
||||
}
|
||||
if (selected < top) {
|
||||
top = selected;
|
||||
} else if (Frame.Height > 0 && selected >= top + Frame.Height) {
|
||||
@@ -831,11 +838,30 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Count => src != null ? src.Count : 0;
|
||||
public int Count {
|
||||
get {
|
||||
CheckAndResizeMarksIfRequired ();
|
||||
return src?.Count ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => len;
|
||||
|
||||
void CheckAndResizeMarksIfRequired ()
|
||||
{
|
||||
if (src != null && count != src.Count) {
|
||||
count = src.Count;
|
||||
BitArray newMarks = new BitArray (count);
|
||||
for (var i = 0; i < Math.Min (marks.Length, newMarks.Length); i++) {
|
||||
newMarks [i] = marks [i];
|
||||
}
|
||||
marks = newMarks;
|
||||
|
||||
len = GetMaxLengthItem ();
|
||||
}
|
||||
}
|
||||
|
||||
int GetMaxLengthItem ()
|
||||
{
|
||||
if (src == null || src?.Count == 0) {
|
||||
@@ -896,7 +922,7 @@ namespace Terminal.Gui {
|
||||
/// <inheritdoc/>
|
||||
public bool IsMarked (int item)
|
||||
{
|
||||
if (item >= 0 && item < count)
|
||||
if (item >= 0 && item < Count)
|
||||
return marks [item];
|
||||
return false;
|
||||
}
|
||||
@@ -904,7 +930,7 @@ namespace Terminal.Gui {
|
||||
/// <inheritdoc/>
|
||||
public void SetMark (int item, bool value)
|
||||
{
|
||||
if (item >= 0 && item < count)
|
||||
if (item >= 0 && item < Count)
|
||||
marks [item] = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
<None Update="./Scenarios/Spinning_globe_dark_small.gif" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
|
||||
<PackageReference Include="CsvHelper" Version="32.0.3" />
|
||||
<PackageReference Include="CsvHelper" Version="33.0.1" />
|
||||
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -771,28 +771,28 @@ namespace Terminal.Gui.ApplicationTests {
|
||||
Assert.True (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.False (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
|
||||
Assert.True (win.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
|
||||
Assert.True (win.CanFocus);
|
||||
Assert.True (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.False (win2.HasFocus);
|
||||
Assert.Equal ("win", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed });
|
||||
Assert.True (win.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released });
|
||||
Assert.Null (Toplevel.dragPosition);
|
||||
}
|
||||
@@ -816,35 +816,35 @@ namespace Terminal.Gui.ApplicationTests {
|
||||
Assert.True (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.False (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
win.CanFocus = false;
|
||||
Assert.False (win.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
|
||||
Assert.False (win.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
win.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed });
|
||||
Assert.False (win.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released });
|
||||
Assert.Null (Toplevel.dragPosition);
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="ReportGenerator" Version="5.3.4" />
|
||||
<PackageReference Include="ReportGenerator" Version="5.3.7" />
|
||||
<PackageReference Include="System.Collections" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -300,16 +300,16 @@ namespace Terminal.Gui.ViewTests {
|
||||
Assert.Equal (19, lv.SelectedItem);
|
||||
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
||||
┌──────────┐
|
||||
│Line10 │
|
||||
│Line11 │
|
||||
│Line12 │
|
||||
│Line13 │
|
||||
│Line14 │
|
||||
│Line15 │
|
||||
│Line16 │
|
||||
│Line17 │
|
||||
│Line18 │
|
||||
│Line19 │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────┘", output);
|
||||
|
||||
Assert.True (lv.ScrollUp (20));
|
||||
|
||||
Reference in New Issue
Block a user