Fixes #4332 - Refactor test infrastructure to use modern ApplicationImpl.Coordinator instead of legacy MainLoop (#4335)

* Initial plan

* Refactor tests to use modern ApplicationImpl.Coordinator architecture instead of legacy Application.RunIteration

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Changes before error encountered

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Replace Application.RunIteration implementation to use modern ApplicationImpl.Coordinator architecture

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Simplify Application.RunIteration to directly delegate to ApplicationImpl.Coordinator without legacy infrastructure

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Update multitasking.md documentation to use Application.AddTimeout/RemoveTimeout instead of deprecated Application.MainLoop methods

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Refactor contribution guidelines and documentation

- Consolidated all contribution-related instructions into `CONTRIBUTING.md` as the single source of truth.
- Updated `copilot-instructions.md` and `AGENTS.md` to reference `CONTRIBUTING.md`.
- Enhanced build, test, and CI/CD workflow documentation.
- Updated repository structure documentation in `README.md` and `CONTRIBUTING.md`.
- Reinforced coding conventions and streamlined testing requirements.
- Documented GitHub Actions workflows and provided local CI replication steps.
- Refined API documentation requirements and PR guidelines.
- Simplified `.sln` file and removed redundant content.
- Updated links to point to the latest documentation resources.

* Revamp bug report template for clarity and detail

Updated the bug report template to improve structure, readability, and comprehensiveness:
- Specified "Terminal.Gui" in the `about` section.
- Replaced bold headings with Markdown heading syntax.
- Enhanced "To Reproduce" with placeholders for code and behavior details.
- Added an "Environment" section to collect OS, terminal, PowerShell, .NET, and `Terminal.Gui` version details.
- Expanded "Screenshots" to include GIFs and terminal output instructions.
- Removed outdated "Desktop" and "Smartphone" sections, consolidating relevant details.
- Improved "Additional Context" with prompts for consistency, prior behavior, and error messages.
- Streamlined "For Maintainers" instructions for setting project and milestone.

These changes aim to make bug reports more actionable and easier to reproduce.

* Remove [Obsolete] attribute and pragma warnings from Application.RunIteration - method now uses modern architecture internally

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Refactor Application.Run.cs for clarity and cleanup

Removed debug assertions and unused/commented-out code to simplify logic and improve maintainability. Renamed `forceDraw` to `forceRedraw` in `LayoutAndDraw` for better clarity. Removed the internal `OnNotifyStopRunState` method and its associated logic, indicating a refactor of the stop notification mechanism.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Tig <tig@users.noreply.github.com>
Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
Copilot
2025-10-26 09:15:46 -06:00
committed by GitHub
parent 1046b47be7
commit aef88ad4bb
17 changed files with 570 additions and 912 deletions

View File

@@ -1,48 +1,5 @@
# Terminal.Gui - Cursor AI Rules
This project uses comprehensive AI agent instructions. See:
- `.github/copilot-instructions.md` - Complete onboarding guide (primary reference)
- `AGENTS.md` - General AI agent guidelines
> **📘 Source of Truth: [CONTRIBUTING.md](CONTRIBUTING.md)**
## Quick Reference
### Project Type
- .NET 8.0 cross-platform console UI toolkit
- 496 source files in core library
- GitFlow branching (v2_develop = default)
### Essential Commands
```bash
# Always run from repo root in this order:
dotnet restore # First! (~15-20s)
dotnet build --configuration Debug --no-restore # ~50s, expect ~326 warnings
dotnet test Tests/UnitTestsParallelizable --no-build # Preferred test suite
dotnet run --project Examples/UICatalog/UICatalog.csproj # Demo app
```
### Code Style (Enforced)
- **DO**: Use explicit types (avoid `var`), target-typed `new()`, 4-space indent
- **DO**: Format only files you modify (ReSharper/Rider `Ctrl-E-C` or `Ctrl-K-D`)
- **DO**: Follow `.editorconfig` and `Terminal.sln.DotSettings`
- **DON'T**: Add new linters, modify unrelated code, decrease test coverage
### Testing Rules
- Add new tests to `Tests/UnitTestsParallelizable/` (preferred)
- Avoid `Application.Init` and static dependencies in tests
- Don't use `[AutoInitShutdown]` attribute (legacy)
- Maintain 70%+ code coverage on new code
### API Documentation (Required)
- All public APIs need XML docs (`<summary>`, `<remarks>`, `<example>`)
- Use `<see cref=""/>` for cross-references
- Complex topics → `docfx/docs/*.md`
### Common Issues
- ~326 build warnings are normal (nullable refs, etc.)
- Tests can take 5-10 minutes
- Run `dotnet restore` before any build
- Read `.github/copilot-instructions.md` for full troubleshooting
---
**See `.github/copilot-instructions.md` for complete instructions**
This project uses [CONTRIBUTING.md](CONTRIBUTING.md) as the single source of truth for contribution guidelines. AI agents, including CoPilot and Cursor **MUST** follow the guidelines in [CONTRIBUTING.md](CONTRIBUTING.md)/

View File

@@ -1,41 +1,140 @@
---
name: Bug report
about: Create a report to help us improve
about: Create a report to help us improve Terminal.Gui
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
## Describe the bug
A clear and concise description of what the bug is.
**To Reproduce**
## To Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
1. Run the following code:
```csharp
// Paste your minimal reproduction code here
```
**Screenshots**
If applicable, add screenshots to help explain your problem.
2. Expected behavior: (describe what should happen)
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
3. Actual behavior: (describe what actually happens)
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
## Environment
**Additional context**
Add any other context about the problem here.
Please run the following commands in your terminal and paste the output:
**Set Project & Milestone**
If you have access, please don't forget to set the right Project and Milestone.
### OS Information
**Windows (PowerShell):**
```powershell
"OS: $(Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty Caption) $(Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty Version)"
```
**macOS/Linux:**
```bash
echo "OS: $(uname -s) $(uname -r)"
```
**Output:**
```
(paste output here)
```
### Terminal Information
**Windows Terminal:**
```powershell
"Terminal: Windows Terminal $(Get-AppxPackage -Name Microsoft.WindowsTerminal | Select-Object -ExpandProperty Version)"
```
**Other terminals:**
```bash
echo $TERM
```
**Output:**
```
(paste output here)
```
### PowerShell Version
```powershell
$PSVersionTable.PSVersion
```
**Output:**
```
(paste output here)
```
### .NET Information
```bash
dotnet --version
dotnet --info
```
**Output:**
```
(paste output here)
```
### Terminal.Gui Version
**Option 1 - Run UICatalog (easiest):**
UICatalog displays the Terminal.Gui version in its About box and status bar.
```bash
dotnet run --project Examples/UICatalog/UICatalog.csproj
```
**Option 2 - NuGet Package Version:**
```
(e.g., 2.0.0-alpha.1, 2.0.0-develop.123, etc.)
```
**Option 3 - Building from source:**
```bash
git rev-parse HEAD
git describe --tags --always --dirty
```
**Version:**
```
(paste version here)
```
## Screenshots, GIFs, or Terminal Output
If applicable, add screenshots, animated GIFs, or copy/paste terminal output to help explain your problem.
**Animated GIFs are especially helpful for showing behavior!**
- **Windows**: [ShareX](https://getsharex.com/) (free, captures screen to GIF)
- **macOS**: [Kap](https://getkap.co/) (free, open source)
- **Linux**: [Peek](https://github.com/phw/peek) (free)
**For terminal output, use code blocks:**
```
(paste terminal output here)
```
## Additional context
Add any other context about the problem here, such as:
- Does this happen consistently or intermittently?
- Did this work in a previous version?
- Are there any error messages in the console?
- Terminal configuration or settings that might be relevant?
## For Maintainers
**Set Project & Milestone:** If you have access, please don't forget to set the right Project and Milestone.

View File

@@ -1,327 +1,5 @@
# Terminal.Gui - Copilot Coding Agent Instructions
# Terminal.Gui - CoPilot AI Rules
This file provides onboarding instructions for GitHub Copilot and other AI coding agents working with Terminal.Gui.
> **📘 Source of Truth: [CONTRIBUTING.md](CONTRIBUTING.md)**
## Project Overview
**Terminal.Gui** is a cross-platform UI toolkit for creating console-based graphical user interfaces in .NET. It's a large codebase (~1,050 C# files, 333MB) providing a comprehensive framework for building interactive console applications with support for keyboard and mouse input, customizable views, and a robust event system.
**Key characteristics:**
- **Language**: C# (net8.0)
- **Size**: ~496 source files in core library, ~1,050 total C# files
- **Platform**: Cross-platform (Windows, macOS, Linux)
- **Architecture**: Console UI toolkit with driver-based architecture
- **Version**: v2 (Alpha), v1 (maintenance mode)
- **Branching**: GitFlow model (v2_develop is default/active development)
## Building and Testing
### Required Tools
- **.NET SDK**: 8.0.0 (see `global.json`)
- **Runtime**: .NET 8.x (latest GA)
- **Optional**: ReSharper/Rider for code formatting
### Build Commands (In Order)
**ALWAYS run these commands from the repository root:**
1. **Restore packages** (required first, ~15-20 seconds):
```bash
dotnet restore
```
2. **Build solution** (Debug, ~50 seconds):
```bash
dotnet build --configuration Debug --no-restore
```
- Expect ~326 warnings (nullable reference warnings, unused variables, etc.) - these are normal
- 0 errors expected
3. **Build Release** (for packaging):
```bash
dotnet build --configuration Release --no-restore
```
### Test Commands
**Two test projects exist:**
1. **Non-parallel tests** (depend on static state, ~10 min timeout):
```bash
dotnet test Tests/UnitTests --no-build --verbosity normal
```
- Uses `Application.Init` and static state
- Cannot run in parallel
- Includes `--blame` flags for crash diagnostics
2. **Parallel tests** (can run concurrently, ~10 min timeout):
```bash
dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
```
- No dependencies on static state
- Preferred for new tests
3. **Integration tests**:
```bash
dotnet test Tests/IntegrationTests --no-build --verbosity normal
```
**Important**: Tests may take significant time. CI uses blame flags for crash detection:
```bash
--diag:logs/UnitTests/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always
```
### Running Examples
**UICatalog** (comprehensive demo app):
```bash
dotnet run --project Examples/UICatalog/UICatalog.csproj
```
## Repository Structure
### Root Directory Files
- `Terminal.sln` - Main solution file
- `Terminal.sln.DotSettings` - ReSharper code style settings
- `.editorconfig` - Code formatting rules (111KB, extensive)
- `global.json` - .NET SDK version pinning
- `Directory.Build.props` - Common MSBuild properties
- `Directory.Packages.props` - Central package version management
- `GitVersion.yml` - Version numbering configuration
- `AGENTS.md` - General AI agent instructions (also useful reference)
- `CONTRIBUTING.md` - Contribution guidelines
- `README.md` - Project documentation
### Main Directories
**`/Terminal.Gui/`** - Core library (496 C# files):
- `App/` - Application lifecycle (`Application.cs` static class, `RunState`, `MainLoop`)
- `Configuration/` - `ConfigurationManager` for settings
- `Drivers/` - Console driver implementations (`IConsoleDriver`, `NetDriver`, `UnixDriver`, `WindowsDriver`)
- `Drawing/` - Rendering system (attributes, colors, glyphs)
- `Input/` - Keyboard and mouse input handling
- `ViewBase/` - Core `View` class hierarchy and layout
- `Views/` - Specific View subclasses (Window, Dialog, Button, ListView, etc.)
- `Text/` - Text manipulation and formatting
**`/Tests/`**:
- `UnitTests/` - Non-parallel tests (use `Application.Init`, static state)
- `UnitTestsParallelizable/` - Parallel tests (no static dependencies)
- `IntegrationTests/` - Integration tests
- `StressTests/` - Long-running stress tests (scheduled daily)
- `coverlet.runsettings` - Code coverage configuration
**`/Examples/`**:
- `UICatalog/` - Comprehensive demo app for manual testing
- `Example/` - Basic example
- `NativeAot/`, `SelfContained/` - Deployment examples
- `ReactiveExample/`, `CommunityToolkitExample/` - Integration examples
**`/docfx/`** - Documentation source:
- `docs/` - Conceptual documentation (deep dives)
- `api/` - Generated API docs (gitignored)
- `docfx.json` - DocFX configuration
**`/Scripts/`** - PowerShell build utilities (requires PowerShell 7.4+)
**`/.github/workflows/`** - CI/CD pipelines:
- `unit-tests.yml` - Main test workflow (Ubuntu, Windows, macOS)
- `build-release.yml` - Release build verification
- `integration-tests.yml` - Integration test workflow
- `publish.yml` - NuGet package publishing
- `api-docs.yml` - Documentation building and deployment
- `codeql-analysis.yml` - Security scanning
## Code Style and Quality
### Formatting
- **Do NOT add formatting tools** - Use existing `.editorconfig` and `Terminal.sln.DotSettings`
- Format code with:
1. ReSharper/Rider (`Ctrl-E-C`)
2. JetBrains CleanupCode CLI tool (free)
3. Visual Studio (`Ctrl-K-D`) as fallback
- **Only format files you modify**
### Code Style Tenets
1. **Six-Year-Old Reading Level** - Readability over terseness
2. **Consistency, Consistency, Consistency** - Follow existing patterns ruthlessly
3. **Don't be Weird** - Follow Microsoft/.NET conventions
4. **Set and Forget** - Rely on automated tooling
5. **Documentation is the Spec** - API docs are source of truth
### Coding Conventions
**⚠️ CRITICAL - These rules MUST be followed in ALL new code:**
#### Type Declarations and Object Creation
- **ALWAYS use explicit types** - Never use `var` except for basic types (`int`, `string`, `bool`, `double`, `float`, `decimal`, `char`, `byte`)
```csharp
// ✅ CORRECT - Explicit types
View view = new () { Width = 10 };
MouseEventArgs args = new () { Position = new Point(5, 5) };
List<View?> views = new ();
var count = 0; // OK - int is a basic type
var name = "test"; // OK - string is a basic type
// ❌ WRONG - Using var for non-basic types
var view = new View { Width = 10 };
var args = new MouseEventArgs { Position = new Point(5, 5) };
var views = new List<View?>();
```
- **ALWAYS use target-typed `new()`** - Use `new ()` instead of `new TypeName()` when the type is already declared
```csharp
// ✅ CORRECT - Target-typed new
View view = new () { Width = 10 };
MouseEventArgs args = new ();
// ❌ WRONG - Redundant type name
View view = new View() { Width = 10 };
MouseEventArgs args = new MouseEventArgs();
```
#### Other Conventions
- Follow `.editorconfig` settings (e.g., braces on new lines, spaces after keywords)
- 4-space indentation
- No trailing whitespace
- See `CONTRIBUTING.md` for full guidelines
**These conventions apply to ALL code - production code, test code, examples, and samples.**
## Testing Requirements
### Code Coverage
- **Never decrease code coverage** - PRs must maintain or increase coverage
- Target: 70%+ coverage for new code
- CI monitors coverage on each PR
### Test Patterns
- **Parallelizable tests preferred** - Add new tests to `UnitTestsParallelizable` when possible
- **Avoid static dependencies** - Don't use `Application.Init`, `ConfigurationManager` in tests
- **Don't use `[AutoInitShutdown]`** - Legacy pattern, being phased out
- **Make tests granular** - Each test should cover smallest area possible
- Follow existing test patterns in respective test projects
### Test Configuration
- `xunit.runner.json` - xUnit configuration
- `coverlet.runsettings` - Coverage settings (OpenCover format)
## API Documentation Requirements
**All public APIs MUST have XML documentation:**
- Clear, concise `<summary>` tags
- Use `<see cref=""/>` for cross-references
- Add `<remarks>` for context
- Include `<example>` for non-obvious usage
- Complex topics → `docfx/docs/*.md` files
- Proper English and grammar
## Common Build Issues
### Issue: Build Warnings
- **Expected**: ~326 warnings (nullable refs, unused vars, xUnit suggestions)
- **Action**: Don't add new warnings; fix warnings in code you modify
### Issue: Test Timeouts
- **Expected**: Tests can take 5-10 minutes
- **Action**: Use appropriate timeout values (60-120 seconds for test commands)
### Issue: Restore Failures
- **Solution**: Ensure `dotnet restore` completes before building
- **Note**: Takes 15-20 seconds on first run
### Issue: NativeAot/SelfContained Build
- **Solution**: Restore these projects explicitly:
```bash
dotnet restore ./Examples/NativeAot/NativeAot.csproj -f
dotnet restore ./Examples/SelfContained/SelfContained.csproj -f
```
## CI/CD Validation
The following checks run on PRs:
1. **Unit Tests** (`unit-tests.yml`):
- Runs on Ubuntu, Windows, macOS
- Both parallel and non-parallel test suites
- Code coverage collection
- 10-minute timeout per job
2. **Build Release** (`build-release.yml`):
- Verifies Release configuration builds
- Tests NativeAot and SelfContained builds
- Packs NuGet package
3. **Integration Tests** (`integration-tests.yml`):
- Cross-platform integration testing
- 10-minute timeout
4. **CodeQL Analysis** (`codeql-analysis.yml`):
- Security vulnerability scanning
To replicate CI locally:
```bash
# Full CI sequence:
dotnet restore
dotnet build --configuration Debug --no-restore
dotnet test Tests/UnitTests --no-build --verbosity normal
dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
dotnet build --configuration Release --no-restore
```
## Branching and PRs
### GitFlow Model
- `v2_develop` - Default branch, active development
- `v2_release` - Stable releases, matches NuGet
- `v1_develop`, `v1_release` - Legacy v1 (maintenance only)
### PR Requirements
- **Title**: "Fixes #issue. Terse description"
- **Description**: Include "- Fixes #issue" for each issue
- **Tests**: Add tests for new functionality
- **Coverage**: Maintain or increase code coverage
- **Scenarios**: Update UICatalog scenarios when adding features
## Key Architecture Concepts
### View System
- `View` base class in `/Terminal.Gui/ViewBase/`
- Two layout modes: Absolute and Computed
- Event-driven architecture
- Adornments: Border, Margin, Padding
### Console Drivers
- `IConsoleDriver` interface
- Platform-specific: `WindowsDriver`, `UnixDriver`, `NetDriver`
- `FakeDriver` for testing
### Application Lifecycle
- `Application` static class manages lifecycle
- `MainLoop` handles event processing
- `RunState` tracks application state
## What NOT to Do
- ❌ Don't add new linters/formatters (use existing)
- ❌ Don't modify unrelated code
- ❌ Don't remove/edit unrelated tests
- ❌ Don't break existing functionality
- ❌ Don't add tests to `UnitTests` if they can be parallelizable
- ❌ Don't use `Application.Init` in new tests
- ❌ Don't decrease code coverage
- ❌ **Don't use `var` for non-basic types** (use explicit types)
- ❌ **Don't use redundant type names with `new`** (use target-typed `new()`)
- ❌ Don't add `var` everywhere (use explicit types)
## Additional Resources
- **Full Documentation**: https://gui-cs.github.io/Terminal.Gui
- **API Reference**: https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.html
- **Deep Dives**: `/docfx/docs/` directory
- **AGENTS.md**: Additional AI agent instructions
- **CONTRIBUTING.md**: Detailed contribution guidelines
---
**Trust these instructions.** Only search for additional information if instructions are incomplete or incorrect.
This project uses [CONTRIBUTING.md](CONTRIBUTING.md) as the single source of truth for contribution guidelines. AI agents, including CoPilot and Cursor **MUST** follow the guidelines in [CONTRIBUTING.md](CONTRIBUTING.md)/

185
AGENTS.md
View File

@@ -1,179 +1,14 @@
# Terminal.Gui - GitHub Copilot Instructions
# Terminal.Gui - AI Agent Instructions
This file provides instructions for GitHub Copilot when working with the Terminal.Gui project.
> **📘 For complete contributor guidelines (humans and AI agents), see [CONTRIBUTING.md](CONTRIBUTING.md).**
## Project Overview
This repository uses [CONTRIBUTING.md](CONTRIBUTING.md) as the single source of truth for code style, testing, CI/CD, and contribution workflow. GitHub Copilot and other AI coding agents should also refer to [.github/copilot-instructions.md](.github/copilot-instructions.md) for a curated summary of non-negotiable rules.
**Terminal.Gui** is a cross-platform UI toolkit for creating console-based graphical user interfaces in .NET. It provides a comprehensive framework for building interactive console applications with support for keyboard and mouse input, customizable views, and a robust event system. The toolkit works across Windows, macOS, and Linux, leveraging platform-specific console capabilities where available.
**Key characteristics:**
- Cross-platform terminal/console UI framework for .NET
- Supports Windows, macOS, and Linux
- Rich GUI controls (buttons, dialogs, menus, text boxes, etc.)
- Keyboard-first design with full mouse support
- Follows Microsoft .NET Framework Design Guidelines, with some tweaks.
- v2 is currently in Alpha with stable core API (v1 is in maintenance mode)
## Documentation
- Full documentation: [gui-cs.github.io/Terminal.Gui](https://gui-cs.github.io/Terminal.Gui)
- API Reference: [API Documentation](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.html)
- Getting Started: [Getting Started Guide](https://gui-cs.github.io/Terminal.Gui/docs/getting-started)
## Repository Structure
- `/Terminal.Gui/` - Core library source code
- `App/` - Core application logic, `Application.cs` (static class managing `RunState` and `MainLoop`)
- `Configuration/` - `ConfigurationManager` for application settings
- `Drivers/` - Console driver implementations (`IConsoleDriver.cs`, `NetDriver`, `UnixDriver`, `WindowsDriver`)
- `Drawing/` - Rendering graphical elements in the console
- `Input/` - Keyboard and mouse input handling
- `View/` - Core `View` class hierarchy
- `Views/` - Specific sub-classes of `View` (Toplevel, Window, Dialog, etc.)
- `/Examples/` - Sample applications and demos
- `/Examples/UICatalog/` - Comprehensive demo app for manual testing
- `/Tests/` - Unit and integration tests
- `/docfx/` - Documentation source files (Deep Dive Articles and API docs)
- `/Scripts/` - Build and utility scripts
## Branching Model
**Terminal.Gui uses GitFlow:**
- `v2_develop` - Default branch for v2 development (active development)
- `v2_release` - Stable release branches matching NuGet packages
## Code Style and Standards
### Code Style Tenets
1. **Six-Year-Old Reading Level** - Prioritize readability over terseness. Use clear variable names and comments.
2. **Consistency, Consistency, Consistency** - Follow established patterns ruthlessly.
3. **Don't be Weird** - Follow Microsoft and .NET community conventions.
4. **Set and Forget** - Use ReSharper/Rider for automated formatting.
5. **Documentation is the Spec** - API documentation is the source of truth.
### Coding Conventions
- Based on [Microsoft C# Coding Conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions)
- Project settings defined and enforced via `./Terminal.sln.DotSettings` and `./.editorconfig`
- Use `var` only for the most basic dotnet types - prefer explicit types for clarity
- Use target-typed new
## API Design Guidelines
### Public API Tenets
1. **Stand on the shoulders of giants** - Follow [Microsoft .NET Framework Design Guidelines](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/)
2. **Don't Break Existing Stuff** - Avoid breaking changes; find compatible ways to add features
3. **Fail-fast** - Prefer early failure to expose bugs sooner
4. **Standards Reduce Complexity** - Use standard .NET idioms, tweaked to match Terminal.Gui.
### API Documentation Requirements
**All public APIs must have XML documentation:**
- Clear, concise, and complete `<summary>` tags
- Use `<see cref=""/>` liberally for cross-references
- Add `<remarks>` for context and detailed explanations
- Document complex topics in `docfx/articles/*.md` files
- Use proper English and correct grammar
- Provide sample code via `<example>` in cases where a sample is needed (not for very obvious things)
### Events
- Follow the [Events Deep Dive](https://gui-cs.github.io/Terminal.Gui/docs/events.html) documentation
- Use the Cancellable Work Pattern for user-initiated actions
- Use the CWPHelpers if possible
- Name event handlers consistently (e.g., `On[EventName]`), following dotnet guidelines.
## User Experience Tenets
1. **Honor What's Come Before** - Follow established Mac/Windows GUI idioms (e.g., `Ctrl-C` for copy)
2. **Consistency Matters** - Common UI patterns should be consistent (e.g., `Ctrl-Q` quits modals)
3. **Honor the OS, but Work Everywhere** - Take advantage of platform capabilities while maintaining cross-platform support
4. **Keyboard first, Mouse also** - Optimize for keyboard, but ensure everything also works with mouse
## Testing
### Unit Test Requirements
- **Never decrease code coverage** - Aim for 70%+ coverage on new code
- Write unit tests for all new functionality
- Follow existing test patterns in `/Tests/`
- Many existing unit tests are obtuse and not really unit tests. Anytime new tests are added or updated, strive to refactor the tests into more granular tests where each test covers the smallest area possible.
- Many existing unit tests in the `./Tests/UnitTests` project incorrectly require `Application.Init` and use `[AutoInitShutdown]`. Anytime new tests are added or updated, strive to remove these dependencies and make the tests parallelizable. This means not taking any dependency on static objects like `Application` and `ConfigurationManager`.
## Pull Request Guidelines
- Titles should be of the form "Fixes #issue. Terse description."
- If the PR addresses multiple issues, use "Fixes #issue1, #issue2. Terse description."
- First comment should include "- Fixes #issue" for each issue addressed. If an issue is only partially addressed, use "Partially addresses #issue".
- First comment should include a thorough description of the change and any impact.
- Put temporary .md files in `/docfx/docs/drafts/` and remove before merging.
## Building and Running
### Build the Solution
```powershell
dotnet build
```
### Run Tests
```powershell
dotnet test
```
## Key Concepts
`./docfx/docs` contains a set of architectural and key-concept deep-dives.
## Additional Guidelines
1. Maintain existing code structure and organization unless explicitly told
2. View sub-classes must not use private APIs
3. Suggest changes to the `./docfx/docs/` folder when appropriate
## Working with Pull Request Branches
When creating PRs, include instructions at the end of each PR description for how to pull the branch down locally. Use the following template, adapted for the typical remote setup where `origin` points to the user's fork and `upstream` points to `gui-cs/Terminal.Gui`:
```markdown
## How to Pull This PR Branch Locally
If you want to test or modify this PR locally, use one of these approaches based on your remote setup:
### Method 1: Fetch from upstream (if branch exists there)
```bash
# Fetch the branch from upstream
git fetch upstream <branch-name>
# Switch to the branch
git checkout <branch-name>
# Make your changes, then commit them
git add .
git commit -m "Your commit message"
# Push to your fork (origin)
git push origin <branch-name>
```
### Method 2: Fetch by PR number
```bash
# Fetch the PR branch from upstream by PR number
git fetch upstream pull/<PR_NUMBER>/head:<branch-name>
# Switch to the branch
git checkout <branch-name>
# Make your changes, then commit them
git add .
git commit -m "Your commit message"
# Push to your fork (origin)
git push origin <branch-name>
```
The PR will automatically update when you push to the branch in your fork.
```
**Note:** Adjust the remote names if your setup differs (e.g., if `origin` points to `gui-cs/Terminal.Gui` and you have a separate remote for your fork).
**Key highlights for AI agents:**
- Always use explicit types (no `var` except for built-in simple types)
- Always use target-typed `new()` syntax
- Add new tests to `Tests/UnitTestsParallelizable/` when possible
- Never decrease code coverage
- Follow `.editorconfig` and `Terminal.sln.DotSettings` for formatting
See [CONTRIBUTING.md](CONTRIBUTING.md) for complete details.

View File

@@ -1,234 +1,413 @@
# Contributing to Terminal.Gui
We welcome contributions from the community. See [Issues](https://github.com/gui-cs/Terminal.Gui/issues) for a list of open [bugs](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Abug) and [enhancements](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement). Contributors looking for something fun to work on should look at issues tagged as:
> **📘 This document is the single source of truth for all contributors (humans and AI agents) to Terminal.Gui.**
- [good first issue](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
- [up for grabs](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Aup-for-grabs)
- [help wanted](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Aup-for-grabs)
Welcome! This guide provides everything you need to know to contribute effectively to Terminal.Gui, including project structure, build instructions, coding conventions, testing requirements, and CI/CD workflows.
## Forking and Submitting Changes
## Table of Contents
Terminal.Gui uses the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branching model.
- [Project Overview](#project-overview)
- [Building and Testing](#building-and-testing)
- [Coding Conventions](#coding-conventions)
- [Testing Requirements](#testing-requirements)
- [API Documentation Requirements](#api-documentation-requirements)
- [Pull Request Guidelines](#pull-request-guidelines)
- [CI/CD Workflows](#cicd-workflows)
- [Repository Structure](#repository-structure)
- [Branching Model](#branching-model)
- [Key Architecture Concepts](#key-architecture-concepts)
- [What NOT to Do](#what-not-to-do)
- [Additional Resources](#additional-resources)
* The `v1_release` and `v2_release` branches are always stable, and always match the most recently released Nuget package.
* The `v1_develop` and `v2_develop` branches are where new development and bug-fixes happen. `v2_develop` is the default Github branch.
---
### Forking Terminal.Gui
## Project Overview
1. Use GitHub to fork the `Terminal.Gui` repo to your account (https://github.com/gui-cs/Terminal.Gui/fork).
**Terminal.Gui** is a cross-platform UI toolkit for creating console-based graphical user interfaces in .NET. It's a large codebase (~1,050 C# files, 333MB) providing a comprehensive framework for building interactive console applications with support for keyboard and mouse input, customizable views, and a robust event system.
2. Clone your fork to your local machine
**Key characteristics:**
- **Language**: C# (net8.0)
- **Size**: ~496 source files in core library, ~1,050 total C# files
- **Platform**: Cross-platform (Windows, macOS, Linux)
- **Architecture**: Console UI toolkit with driver-based architecture
- **Version**: v2 (Alpha), v1 (maintenance mode)
- **Branching**: GitFlow model (v2_develop is default/active development)
```
git clone https://github.com/<yourID>/Terminal.Gui
```
---
Now, your local repo will have an `origin` remote pointing to `https://github.com/<yourID>/Terminal.Gui`.
## Building and Testing
3. Add a remote for `upstream`:
```
git remote add upstream https://github.com/gui-cs/Terminal.Gui
```
You now have your own fork and a local repo that references it as `origin`. Your local repo also now references the orignal Terminal.Gui repo as `upstream`.
### Required Tools
### Starting to Make a Change
- **.NET SDK**: 8.0.0 (see `global.json`)
- **Runtime**: .NET 8.x (latest GA)
- **Optional**: ReSharper/Rider for code formatting (honor `.editorconfig` and `Terminal.sln.DotSettings`)
Ensure your local `v1_develop` (for v1) or `v2_develop` (for v2) branch is up-to-date with `upstream` (`github.com/gui-cs/Terminal.Gui`):
```powershell
cd ./Terminal.Gui
git checkout v2_develop
git pull upstream v2_develop
```
### Build Commands (In Order)
Create a new local branch:
```powershell
git checkout -b my_new_branch
```
**ALWAYS run these commands from the repository root:**
### Making Changes
Follow all the guidelines below.
* [Coding Style](#TerminalGui-Coding-Style)
* [Unit Tests](#Unit-Tests)
* [Sample Code](#Sample-Code)
* API Documentation
* etc...
When you're ready, commit your changes:
```powershell
git add .
git commit -m "Fixes #1234. Some bug"
```
### Submitting a Pull Request
1. Push your local branch to your fork (`origin`):
```powershell
git push --set-upstream origin my_new_branch
```
2. Create the Pull Request:
In the output of the `git push` command you'll see instructions with a link to the Pull Request:
```powershell
$ git push --set-upstream origin my_new_branch
Enumerating objects: 8, done.
...
remote:
remote: Create a pull request for 'my_new_branch' on GitHub by visiting:
remote: https://github.com/<yourID>/Terminal.Gui/pull/new/more_doc_fixes
remote:
...
```
3. Go to that URL and create the Pull Request:
(in Windows Terminal, just CTRL-Click on the URL)
Follow the template instructions found on Github.
## Tenets for [gui-cs](www.github.com/gui-cs) Code Style (Unless you have better ones)
* **Six-Year-Old Reading Level** - Our code style is biased towards code readability and away from terseness. This is *Systems Software* and needs to stand the test of time. Code should be structured and use variable names that make it readable by a 6-year-old, and comments in code are encouraged.
* **Consistency, Consistency, Consistency** - We adopt and document our standards for code style and then enforce them ruthlessly. For example, we require code reviews to pay attention to code style, not just functionality.
* **Don't be Weird** - Like all developers we have opinions, but our opinions on code style are tempered by existing standards. We are biased towards code style that used by Microsoft and other leading dotnet developers. For example, we choose 4 spaces for indentation instead of 8.
* **Set and Forget** - We embrace and encourage the use of technology that makes it easy for contributors to apply best-practice code-style, such as ReSharper. As we do so we are mindful that tools can cause hidden issues and merge hell.
* **Documentation is the Spec** - We care deeply about providing delightful developer documentation and are sticklers for grammar and clarity. If the code and the docs conflict, we are biased to believe what we wrote in the API documentation. This drives a virtuous cycle of clear thinking.
**Terminal.Gui** uses a derivative of the [Microsoft C# Coding Conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions), with any deviations from those (somewhat older) conventions codified in the .editorconfig for the solution, as well as even more specific definitions in team-shared dotsettings files, used by ReSharper and Rider.\
### Critical Coding Standards
**⚠️ These rules MUST be followed in ALL new code (production, tests, examples, samples):**
#### Type Declarations and Object Creation
1. **ALWAYS use explicit types** - Never use `var` except for basic types (`int`, `string`, `bool`, `double`, `float`, `decimal`, `char`, `byte`)
```csharp
// ✅ CORRECT - Explicit types
View view = new () { Width = 10 };
MouseEventArgs args = new () { Position = new Point(5, 5) };
List<View?> views = new ();
var count = 0; // OK - int is a basic type
var name = "test"; // OK - string is a basic type
// ❌ WRONG - Using var for non-basic types
var view = new View { Width = 10 };
var args = new MouseEventArgs { Position = new Point(5, 5) };
var views = new List<View?>();
1. **Restore packages** (required first, ~15-20 seconds):
```bash
dotnet restore
```
2. **ALWAYS use target-typed `new()`** - Use `new ()` instead of `new TypeName()` when the type is already declared
2. **Build solution** (Debug, ~50 seconds):
```bash
dotnet build --configuration Debug --no-restore
```
- Expect ~326 warnings (nullable reference warnings, unused variables, etc.) - these are normal
- 0 errors expected
```csharp
// ✅ CORRECT - Target-typed new
View view = new () { Width = 10 };
MouseEventArgs args = new ();
// ❌ WRONG - Redundant type name
View view = new View() { Width = 10 };
MouseEventArgs args = new MouseEventArgs();
3. **Build Release** (for packaging):
```bash
dotnet build --configuration Release --no-restore
```
**Why these rules matter:**
- Explicit types improve code readability and make the type system more apparent
- Target-typed `new()` reduces redundancy while maintaining clarity
- Consistency across the codebase makes it easier for all contributors to read and maintain code
- These conventions align with modern C# best practices (C# 9.0+)
### Test Commands
**Two test projects exist:**
1. **Non-parallel tests** (depend on static state, ~10 min timeout):
```bash
dotnet test Tests/UnitTests --no-build --verbosity normal
```
- Uses `Application.Init` and static state
- Cannot run in parallel
- Includes `--blame` flags for crash diagnostics
2. **Parallel tests** (can run concurrently, ~10 min timeout):
```bash
dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
```
- No dependencies on static state
- **Preferred for new tests**
3. **Integration tests**:
```bash
dotnet test Tests/IntegrationTests --no-build --verbosity normal
```
**Important**: Tests may take significant time. CI uses blame flags for crash detection:
```bash
--diag:logs/UnitTests/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always
```
### Common Build Issues
#### Issue: Build Warnings
- **Expected**: ~326 warnings (nullable refs, unused vars, xUnit suggestions)
- **Action**: Don't add new warnings; fix warnings in code you modify
#### Issue: Test Timeouts
- **Expected**: Tests can take 5-10 minutes
- **Action**: Use appropriate timeout values (60-120 seconds for test commands)
#### Issue: Restore Failures
- **Solution**: Ensure `dotnet restore` completes before building
- **Note**: Takes 15-20 seconds on first run
#### Issue: NativeAot/SelfContained Build
- **Solution**: Restore these projects explicitly:
```bash
dotnet restore ./Examples/NativeAot/NativeAot.csproj -f
dotnet restore ./Examples/SelfContained/SelfContained.csproj -f
```
### Running Examples
**UICatalog** (comprehensive demo app):
```bash
dotnet run --project Examples/UICatalog/UICatalog.csproj
```
---
## Coding Conventions
### Code Style Tenets
1. **Six-Year-Old Reading Level** - Readability over terseness
2. **Consistency, Consistency, Consistency** - Follow existing patterns ruthlessly
3. **Don't be Weird** - Follow Microsoft/.NET conventions
4. **Set and Forget** - Rely on automated tooling
5. **Documentation is the Spec** - API docs are source of truth
### Code Formatting
Before you commit code, please run the formatting rules on **only the code file(s) you have modified**, in one of the following ways, in order of most preferred to least preferred:
- **Do NOT add formatting tools** - Use existing `.editorconfig` and `Terminal.sln.DotSettings`
- Format code with:
1. ReSharper/Rider (`Ctrl-E-C`)
2. JetBrains CleanupCode CLI tool (free)
3. Visual Studio (`Ctrl-K-D`) as fallback
- **Only format files you modify**
1. `Ctrl-E-C` if using ReSharper or Rider
2. Running the free [CleanupCode](https://www.jetbrains.com/help/resharper/CleanupCode.html) tool from JetBrains (this applies the same formatting rules as if you had used ReSharper or Rider, but is free for all users, if you don't have a license for those products)
- Run at the command line, from the solution root directory, as: `cleanupcode.exe relative/path/to/your/file.cs`
3. If you are unable to use either of those options, the last resort is to use `Ctrl-K-D` in Visual Studio (with default C# developer key bindings), to apply the subset of the formatting rules that Visual Studio can apply.
### Critical Coding Rules
## User Experience Tenets
**⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code:**
**Terminal.Gui**, as a UI framework, heavily influences how console graphical user interfaces (GUIs) work. We use the following [tenets](https://ceklog.kindel.com/2020/02/10/tenets/) to guide us:
#### Type Declarations and Object Creation
*NOTE: Like all tenets, these are up for debate. If you disagree, have questions, or suggestions about these tenets and guidelines submit an Issue using the [design](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Adesign) tag.*
- **ALWAYS use explicit types** - Never use `var` except for built-in simple types (`int`, `string`, `bool`, `double`, `float`, `decimal`, `char`, `byte`)
```csharp
// ✅ CORRECT - Explicit types
View view = new () { Width = 10 };
MouseEventArgs args = new () { Position = new Point(5, 5) };
List<View?> views = new ();
var count = 0; // OK - int is a built-in type
var name = "test"; // OK - string is a built-in type
// ❌ WRONG - Using var for non-built-in types
var view = new View { Width = 10 };
var args = new MouseEventArgs { Position = new Point(5, 5) };
var views = new List<View?>();
```
1. **Honor What's Come Before**. The Mac and Windows OS's have well-established GUI idioms that are mostly consistent. We adhere to these versus inventing new ways for users to do things. For example, **Terminal.Gui** adopts the `ctrl/command-c`, `ctrl/command-v`, and `ctrl/command-x` keyboard shortcuts for cut, copy, and paste versus defining new shortcuts.
2. **Consistency Matters**. Common UI idioms should be consistent across the GUI framework. For example, `ctrl/command-q` quits/exits all modal views. See [Issue #456](https://github.com/gui-cs/Terminal.Gui/issues/456) as a counter-example that should be fixed.
3. **Honor the OS, but Work Everywhere**. **Terminal.Gui** is cross-platform, but we support taking advantage of a platform's unique advantages. For example, the Windows Console API is richer than the Unix API in terms of keyboard handling. Thus, in Windows pressing the `alt` key in a **Terminal.Gui** app will activate the `MenuBar`, but in Unix, the user has to press the full hotkey (e.g. `alt-f`) or `F9`.
4. **Keyboard first, Mouse also**. Users use consoles primarily with the keyboard; **Terminal.Gui** is optimized for getting stuff done without using the Mouse. However, as a GUI framework, the Mouse is essential thus we strive to ensure that everything also works via the Mouse.
- **ALWAYS use target-typed `new()`** - Use `new ()` instead of `new TypeName()` when the type is already declared
```csharp
// ✅ CORRECT - Target-typed new
View view = new () { Width = 10 };
MouseEventArgs args = new ();
// ❌ WRONG - Redundant type name
View view = new View() { Width = 10 };
MouseEventArgs args = new MouseEventArgs();
```
## Public API Tenets & Guidelines
#### Other Conventions
**Terminal.Gui** provides an API that is used by many. As the project evolves, contributors should follow these [tenets](https://ceklog.kindel.com/2020/02/10/tenets/) to ensure Consistency and backward compatibility.
- Follow `.editorconfig` settings (e.g., braces on new lines, spaces after keywords)
- 4-space indentation
- No trailing whitespace
- File-scoped namespaces
*NOTE: Like all tenets, these are up for debate. If you disagree, have questions, or suggestions about these tenets and guidelines submit an Issue using the [design](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Adesign) tag.*
**⚠️ CRITICAL - These conventions apply to ALL code - production code, test code, examples, and samples.**
1. **Stand on the shoulders of giants.** Follow the [Microsoft .NET Framework Design Guidelines](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/) where appropriate.
2. **Don't Break Existing Stuff.** Avoid breaking changes to user behavior or the public API; instead, figure out how to implement new functionality in a similar way. If a breaking change can't be avoided, follow the guidelines below.
3. **Fail-fast.** Fail-fast makes bugs and failures appear sooner, leading to a higher-quality framework and API.
4. **Standards Reduce Complexity**. We strive to adopt standard API idoms because doing so reduces complexity for users of the API. For example, see Tenet #1 above. A counterexample is [Issue #447](https://github.com/gui-cs/Terminal.Gui/issues/447).
---
### Include API Documentation
## Testing Requirements
Great care has been provided thus far in ensuring **Terminal.Gui** has great [API Documentation](https://gui-cs.github.io/Terminal.Gui). Contributors have the responsibility of continuously improving the API Documentation.
### Code Coverage
- All public APIs must have clear, concise, and complete documentation in the form of [XML Documentation](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/).
- Keep the `<summary></summary>` terse.
- Use `<see cref=""/>` liberally to cross-link topics.
- Use `<remarks></remarks>` to add more context and explanation.
- For complex topics, provide conceptual documentation in the `docfx/articles` folder as a `.md` file. It will automatically get picked up and be added to [Conceptual Documentation](https://gui-cs.github.io/Terminal.Gui/docs/index.html).
- Use proper English and good grammar.
- **Never decrease code coverage** - PRs must maintain or increase coverage
- Target: 70%+ coverage for new code
- CI monitors coverage on each PR
### Defining Events
### Test Patterns
See https://gui-cs.github.io/Terminal.Gui/docs/events.html
- **Parallelizable tests preferred** - Add new tests to `UnitTestsParallelizable` when possible
- **Avoid static dependencies** - Don't use `Application.Init`, `ConfigurationManager` in tests
- **Don't use `[AutoInitShutdown]`** - Legacy pattern, being phased out
- **Make tests granular** - Each test should cover smallest area possible
- Follow existing test patterns in respective test projects
### Test Configuration
### Defining new `View` classes
- `xunit.runner.json` - xUnit configuration
- `coverlet.runsettings` - Coverage settings (OpenCover format)
- Support parameterless constructors (see [Issue 102](Parameterless constructors #102)). Do not require callers to use a parameterized constructor except when forcing `Absolute Layout`).
- Avoid doing initialization via constructors. Instead use a property so consumers can use object initialization (e.g. `var foo = new Foo() { a = b };`).
- Ensure the `UICatalog` demo for the new class illustrates both `Absolutle Layout` and `Computed Layout`.
---
## Breaking Changes to User Behavior or the Public API
## API Documentation Requirements
- Tag all pull requests that cause breaking changes to user behavior or the public API with the [breaking-change](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Abreaking-change) tag. This will help project maintainers track and document these.
- Add a `<remark></remark>` to the XML Documentation to the code describing the breaking change. These will get picked up in the [API Documentation](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.html).
**All public APIs MUST have XML documentation:**
## Unit Tests
- Clear, concise `<summary>` tags
- Use `<see cref=""/>` for cross-references
- Add `<remarks>` for context
- Include `<example>` for non-obvious usage
- Complex topics → `docfx/docs/*.md` files
- Proper English and grammar - Clear, concise, complete. Use imperative mood.
PRs should never cause code coverage to go down. Ideally, every PR will get the project closer to 100%. PRs that include new functionality (e.g. a new control) should have at least 70% code coverage for the new functionality.
---
**Terminal.Gui** has an automated unit or regression test suite. See the [Testing wiki](https://github.com/gui-cs/Terminal.Gui/wiki/Testing).
## Pull Request Guidelines
We analyze unit tests and code coverage on each PR push.
### PR Requirements
The code coverage of the latest released build (on NuGet) is shown as a badge at the top of `README.md`. Here as well:
- **Title**: "Fixes #issue. Terse description". If multiple issues, list all, separated by commas (e.g. "Fixes #123, #456. Terse description")
- **Description**:
- Include "- Fixes #issue" for each issue near the top
- **ALWAYS** include instructions for pulling down locally at end of Description
- Suggest user setup a remote named `copilot` pointing to your fork
- Example:
```markdown
# To pull down this PR locally:
git remote add copilot <your-fork-url>
git fetch copilot <branch-name>
git checkout copilot/<branch-name>
```
- **Coding Style**: Follow all coding conventions in this document for new and modified code
- **Tests**: Add tests for new functionality (see [Testing Requirements](#testing-requirements))
- **Coverage**: Maintain or increase code coverage
- **Scenarios**: Update UICatalog scenarios when adding features
![Code Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27/raw/code-coverage.json)
---
The project uses Fine Code Coverage to allow easy access to code coverage info on a per-component basis.
## CI/CD Workflows
Use the following command to generate the same CC info that the Publish Github Action uses to publish the results to the badge:
The repository uses multiple GitHub Actions workflows. What runs and when:
```
dotnet test --no-restore --verbosity normal --collect:"XPlat Code Coverage" --settings UnitTests/coverlet.runsettings
### 1) Build Solution (`.github/workflows/build.yml`)
- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`); supports `workflow_call`
- **Runner/timeout**: `ubuntu-latest`, 10 minutes
- **Steps**:
- Checkout and setup .NET 8.x GA
- `dotnet restore`
- Build Debug: `dotnet build --configuration Debug --no-restore -property:NoWarn=0618%3B0612`
- Build Release (library): `dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release --no-incremental --force -property:NoWarn=0618%3B0612`
- Pack Release: `dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages -property:NoWarn=0618%3B0612`
- Restore NativeAot/SelfContained examples, then restore solution again
- Build Release for `Examples/NativeAot` and `Examples/SelfContained`
- Build Release solution
- Upload artifacts named `build-artifacts`, retention 1 day
### 2) Build & Run Unit Tests (`.github/workflows/unit-tests.yml`)
- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
- **Process**: Calls build workflow, then runs:
- Non-parallel UnitTests on Ubuntu/Windows/macOS matrix with coverage and blame/diag flags; `xunit.stopOnFail=false`
- Parallel UnitTestsParallelizable similarly with coverage; `xunit.stopOnFail=false`
- Uploads logs per-OS
### 3) Build & Run Integration Tests (`.github/workflows/integration-tests.yml`)
- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
- **Process**: Calls build workflow, then runs IntegrationTests on matrix with blame/diag; `xunit.stopOnFail=true`
- Uploads logs per-OS
### 4) Publish to NuGet (`.github/workflows/publish.yml`)
- **Triggers**: push to `v2_release`, `v2_develop`, and tags `v*` (ignores `**.md`)
- Uses GitVersion to compute SemVer, builds Release, packs with symbols, and pushes to NuGet.org using `NUGET_API_KEY`
### 5) Build and publish API docs (`.github/workflows/api-docs.yml`)
- **Triggers**: push to `v1_release` and `v2_develop`
- Builds DocFX site on Windows and deploys to GitHub Pages when `ref_name` is `v2_release` or `v2_develop`
### Replicating CI Locally
```bash
# Full CI sequence:
dotnet restore
dotnet build --configuration Debug --no-restore
dotnet test Tests/UnitTests --no-build --verbosity normal
dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
dotnet build --configuration Release --no-restore
```
Then open up the resulting `coverage.opencover.xml` file and you'll see the `sequenceCoverage` value:
---
```xml
<?xml version="1.0" encoding="utf-8"?>
<CoverageSession>
<Summary numSequencePoints="15817" visitedSequencePoints="7249" numBranchPoints="9379" visitedBranchPoints="3640" sequenceCoverage="45.83" branchCoverage="38.81" maxCyclomaticComplexity="10276" minCyclomaticComplexity="10276" visitedClasses="105" numClasses="141" visitedMethods="965" numMethods="1751" />
```
## Repository Structure
## Sample Code
### Root Directory Files
[UI Catalog](https://github.com/gui-cs/Terminal.Gui/tree/master/UICatalog) is a great sample app for manual testing.
- `Terminal.sln` - Main solution file
- `Terminal.sln.DotSettings` - ReSharper code style settings
- `.editorconfig` - Code formatting rules (111KB, extensive)
- `global.json` - .NET SDK version pinning
- `Directory.Build.props` - Common MSBuild properties
- `Directory.Packages.props` - Central package version management
- `GitVersion.yml` - Version numbering configuration
- `CONTRIBUTING.md` - This file - contribution guidelines (source of truth)
- `AGENTS.md` - Pointer to this file for AI agents
- `README.md` - Project documentation
When adding new functionality, fixing bugs, or changing things, please either add a new `Scenario` to **UICatalog** or update an existing `Scenario` to fully illustrate your work and provide a test-case.
### Main Directories
**`/Terminal.Gui/`** - Core library (496 C# files):
- `App/` - Application lifecycle (`Application.cs` static class, `RunState`, `MainLoop`)
- `Configuration/` - `ConfigurationManager` for settings
- `Drivers/` - Console driver implementations (`IConsoleDriver`, `NetDriver`, `UnixDriver`, `WindowsDriver`)
- `Drawing/` - Rendering system (attributes, colors, glyphs)
- `Input/` - Keyboard and mouse input handling
- `ViewBase/` - Core `View` class hierarchy and layout
- `Views/` - Specific View subclasses (Window, Dialog, Button, ListView, etc.)
- `Text/` - Text manipulation and formatting
- `FileServices/` - File operations and services
**`/Tests/`**:
- `UnitTests/` - Non-parallel tests (use `Application.Init`, static state)
- `UnitTestsParallelizable/` - Parallel tests (no static dependencies) - **Preferred**
- `IntegrationTests/` - Integration tests
- `StressTests/` - Long-running stress tests (scheduled daily)
- `coverlet.runsettings` - Code coverage configuration
**`/Examples/`**:
- `UICatalog/` - Comprehensive demo app for manual testing
- `Example/` - Basic example
- `NativeAot/`, `SelfContained/` - Deployment examples
- `ReactiveExample/`, `CommunityToolkitExample/` - Integration examples
**`/docfx/`** - Documentation source:
- `docs/` - Conceptual documentation (deep dives)
- `api/` - Generated API docs (gitignored)
- `docfx.json` - DocFX configuration
**`/Scripts/`** - PowerShell build utilities (requires PowerShell 7.4+)
**`/.github/workflows/`** - CI/CD pipelines (see [CI/CD Workflows](#cicd-workflows))
---
## Branching Model
### GitFlow Model
- `v2_develop` - Default branch, active development
- `v2_release` - Stable releases, matches NuGet
- `v1_develop`, `v1_release` - Legacy v1 (maintenance only)
---
## Key Architecture Concepts
**⚠️ CRITICAL - Contributors should understand these concepts before starting work.**
See `/docfx/docs/` for deep dives on:
- **Application Lifecycle** - How `Application.Init`, `Application.Run`, and `Application.Shutdown` work
- **View Hierarchy** - Understanding `View`, `Toplevel`, `Window`, and view containment
- **Layout System** - Pos, Dim, and automatic layout
- **Event System** - How keyboard, mouse, and application events flow
- **Driver Architecture** - How console drivers abstract platform differences
- **Drawing Model** - How rendering works with Attributes, Colors, and Glyphs
Key documentation:
- [View Documentation](https://gui-cs.github.io/Terminal.Gui/docs/View.html)
- [Events Deep Dive](https://gui-cs.github.io/Terminal.Gui/docs/events.html)
- [Layout System](https://gui-cs.github.io/Terminal.Gui/docs/layout.html)
- [Keyboard Handling](https://gui-cs.github.io/Terminal.Gui/docs/keyboard.html)
- [Mouse Support](https://gui-cs.github.io/Terminal.Gui/docs/mouse.html)
- [Drivers](https://gui-cs.github.io/Terminal.Gui/docs/drivers.html)
---
## What NOT to Do
- ❌ Don't add new linters/formatters (use existing)
- ❌ Don't modify unrelated code
- ❌ Don't remove/edit unrelated tests
- ❌ Don't break existing functionality
- ❌ Don't add tests to `UnitTests` if they can be parallelizable
- ❌ Don't use `Application.Init` in new tests
- ❌ Don't decrease code coverage
- ❌ **Don't use `var` for anything but built-in simple types** (use explicit types)
- ❌ **Don't use redundant type names with `new`** (**ALWAYS PREFER** target-typed `new ()`)
---
## Additional Resources
- **Full Documentation**: https://gui-cs.github.io/Terminal.Gui
- **API Reference**: https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.html
- **Deep Dives**: `/docfx/docs/` directory
- **Getting Started**: https://gui-cs.github.io/Terminal.Gui/docs/getting-started.html
- **Migrating from v1 to v2**: https://gui-cs.github.io/Terminal.Gui/docs/migratingfromv1.html
- **Showcase**: https://gui-cs.github.io/Terminal.Gui/docs/showcase.html
---
**Thank you for contributing to Terminal.Gui!** 🎉

View File

@@ -86,7 +86,7 @@ Or, you can use the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.
# Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md).
See [CONTRIBUTING.md](CONTRIBUTING.md) for complete contribution guidelines.
Debates on architecture and design can be found in Issues tagged with [design](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Av2+label%3Adesign).

View File

@@ -61,15 +61,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
{
ArgumentNullException.ThrowIfNull (toplevel);
//#if DEBUG_IDISPOSABLE
// Debug.Assert (!toplevel.WasDisposed);
// if (_cachedRunStateToplevel is { } && _cachedRunStateToplevel != toplevel)
// {
// Debug.Assert (_cachedRunStateToplevel.WasDisposed);
// }
//#endif
// Ensure the mouse is ungrabbed.
if (Mouse.MouseGrabView is { })
{
@@ -130,11 +121,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
TopLevels.Push (toplevel);
}
}
//if (TopLevels.FindDuplicates (new ToplevelEqualityComparer ()).Count > 0)
//{
// throw new ArgumentException ("There are duplicates Toplevel IDs");
//}
}
if (Top is null)
@@ -174,11 +160,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
toplevel.EndInit (); // Calls Layout
}
// Call ConfigurationManager Apply here to ensure all subscribers to ConfigurationManager.Applied
// can update their state appropriately.
// BUGBUG: DO NOT DO THIS. Leave this commented out until we can figure out how to do this right
//Apply ();
// Try to set initial focus to any TabStop
if (!toplevel.HasFocus)
{
@@ -402,7 +383,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
/// need to be laid out (see <see cref="View.NeedsLayout"/>) will be laid out.
/// Only Views that need to be drawn (see <see cref="View.NeedsDraw"/>) will be drawn.
/// </summary>
/// <param name="forceDraw">
/// <param name="forceRedraw">
/// If <see langword="true"/> the entire View hierarchy will be redrawn. The default is <see langword="false"/> and
/// should only be overriden for testing.
/// </param>
@@ -467,35 +448,10 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
/// <returns><see langword="false"/> if at least one iteration happened.</returns>
public static bool RunIteration (ref RunState state, bool firstIteration = false)
{
// If the driver has events pending do an iteration of the driver MainLoop
if (MainLoop is { Running: true } && MainLoop.EventsPending ())
{
// Notify Toplevel it's ready
if (firstIteration)
{
state.Toplevel.OnReady ();
}
ApplicationImpl appImpl = (ApplicationImpl)ApplicationImpl.Instance;
appImpl.Coordinator?.RunIteration ();
MainLoop.RunIteration ();
Iteration?.Invoke (null, new ());
}
firstIteration = false;
if (Top is null)
{
return firstIteration;
}
LayoutAndDraw (TopLevels.Any (v => v.NeedsLayout || v.NeedsDraw));
if (PositionCursor ())
{
Driver?.UpdateCursor ();
}
return firstIteration;
return false;
}
/// <summary>Stops the provided <see cref="Toplevel"/>, causing or the <paramref name="top"/> if provided.</summary>
@@ -510,14 +466,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
/// </remarks>
public static void RequestStop (Toplevel? top = null) { ApplicationImpl.Instance.RequestStop (top); }
internal static void OnNotifyStopRunState (Toplevel top)
{
if (EndAfterFirstIteration)
{
NotifyStopRunState?.Invoke (top, new (top));
}
}
/// <summary>
/// Building block API: completes the execution of a <see cref="Toplevel"/> that was started with
/// <see cref="Begin(Toplevel)"/> .

View File

@@ -8,43 +8,7 @@
## Project Folder Structure
- `\` - The root folder contains the core solution and project files for the library.
- `Terminal.Gui.sln` - The Visual Studio solution file for the project.
- `Terminal.Gui.csproj` - The project file defining build configurations and dependencies.
- `App\` - Contains the core `Application` logic, including `Application.cs`, a `static` class that serves as the base 'application engine', managing `RunState` and `MainLoop`.
- `Configuration\` - Classes related to the `ConfigurationManager` for handling application settings.
- `Drivers\` - Contains the console driver implementations:
- `IConsoleDriver.cs` - Defines the Console Driver API.
- Driver implementations for .NET (`DotNetDriver`), Unix & macOS (`UnixDriver`), and Windows (`WindowsDriver`).
- `Drawing\` - Classes related to rendering graphical elements in the console.
- `FileServices\` - Utility classes for file operations and services.
- `Input\` - Classes handling keyboard and mouse input:
- `Events.cs` - Defines structs and classes for keyboard and mouse events.
- `Resources\` - Assets and resources used by the library.
- `Text\` - Classes for text processing and formatting.
- `View\` - Core `View` class hierarchy (excluding specific sub-classes):
- `View.cs` - The base class for non-modal visual elements such as controls.
- Related subdirectories for layout and positioning logic.
- `ViewBase\` - Base classes and utilities for views.
- `Views\` - Specific sub-classes of `View`:
- `Toplevel` - Base class for modal visual elements like top-level windows and dialogs, supporting `MenuBar` and `StatusBar`.
- `Window` - Implements framed top-level views with titles.
- `Dialog` - Specialized windows for user interaction.
- Other specialized view classes.
## Showcase
See the [Showcase](docs/showcase.md) to find independent applications and examples built with Terminal.Gui.
This directory contains the core **Terminal.Gui** library source code. For a detailed repository structure, see [CONTRIBUTING.md - Repository Structure](../CONTRIBUTING.md#repository-structure).
## Getting Started
@@ -52,14 +16,9 @@ For instructions on how to start using **Terminal.Gui**, refer to the [Getting S
## Documentation
Comprehensive documentation for **Terminal.Gui** is available at [gui-cs.github.io/Terminal.Gui](https://gui-cs.github.io/Terminal.Gui). Key resources include:
- [Events Deep Dive](https://gui-cs.github.io/Terminal.Gui/docs/events.html) - Detailed guide on event handling and the Cancellable Work Pattern.
- [View Documentation](https://gui-cs.github.io/Terminal.Gui/docs/View.html) - Information on creating and customizing views.
- [Keyboard Handling](https://gui-cs.github.io/Terminal.Gui/docs/keyboard.html) - Guide to managing keyboard input.
- [Mouse Support](https://gui-cs.github.io/Terminal.Gui/docs/mouse.html) - Details on implementing mouse interactions.
- [Showcase](https://gui-cs.github.io/Terminal.Gui/docs/showcase.html) - A collection of applications and examples built with Terminal.Gui.
Comprehensive documentation is available at [gui-cs.github.io/Terminal.Gui](https://gui-cs.github.io/Terminal.Gui).
For information on generating and updating the API documentation locally, refer to the [DocFX README](../docfx/README.md) in the `docfx` folder.
For information on generating and updating the API documentation locally, refer to the [DocFX README](../docfx/README.md).
## Versioning
@@ -75,7 +34,7 @@ The project version (used in the NuGet package and `Terminal.Gui.dll`) is determ
To define a new version, tag a commit using `git tag`:
```powershell
git tag v1.3.4-beta.5 -a -m "Release v1.3.4 Beta 5"
git tag v2.1.0-beta.1 -a -m "Release v2.1.0 Beta 1"
dotnet-gitversion /updateprojectfiles
dotnet build -c Release
```
@@ -92,15 +51,15 @@ To release a new version, follow these steps based on [Semantic Versioning](http
### Steps for Release:
1. **Verify the `develop` branch is ready for release**:
- Ensure all changes are committed and pushed to the `develop` branch.
- Ensure your local `develop` branch is up-to-date with `upstream/develop`.
1. **Verify the `v2_develop` branch is ready for release**:
- Ensure all changes are committed and pushed to the `v2_develop` branch.
- Ensure your local `v2_develop` branch is up-to-date with `upstream/v2_develop`.
2. **Create a pull request for the release in the `develop` branch**:
2. **Create a pull request for the release in the `v2_develop` branch**:
- Title the PR as "Release vX.Y.Z".
```powershell
git checkout develop
git pull upstream develop
git checkout v2_develop
git pull upstream v2_develop
git checkout -b vX_Y_Z
git add .
git commit -m "Release vX.Y.Z"
@@ -110,28 +69,28 @@ To release a new version, follow these steps based on [Semantic Versioning](http
3. **On github.com, verify the build action worked on your fork, then merge the PR**.
4. **Pull the merged `develop` from `upstream`**:
4. **Pull the merged `v2_develop` from `upstream`**:
```powershell
git checkout develop
git pull upstream develop
git checkout v2_develop
git pull upstream v2_develop
```
5. **Merge `develop` into `main`**:
5. **Merge `v2_develop` into `v2_release`**:
```powershell
git checkout main
git pull upstream main
git merge develop
git checkout v2_release
git pull upstream v2_release
git merge v2_develop
```
- Fix any merge errors.
6. **Create a new annotated tag for the release on `main`**:
6. **Create a new annotated tag for the release on `v2_release`**:
```powershell
git tag vX.Y.Z -a -m "Release vX.Y.Z"
```
7. **Push the new tag to `main` on `upstream`**:
7. **Push the new tag to `v2_release` on `upstream`**:
```powershell
git push --atomic upstream main vX.Y.Z
git push --atomic upstream v2_release vX.Y.Z
```
8. **Monitor Github Actions to ensure the NuGet publishing worked**:
@@ -143,18 +102,25 @@ To release a new version, follow these steps based on [Semantic Versioning](http
10. **Add a new Release in Github**:
- Go to [GitHub Releases](https://github.com/gui-cs/Terminal.Gui/releases) and generate release notes with the list of PRs since the last release.
11. **Update the `develop` branch with the new version**:
11. **Update the `v2_develop` branch with the new version**:
```powershell
git checkout develop
git pull upstream develop
git merge main
git push upstream develop
git checkout v2_develop
git pull upstream v2_develop
git merge v2_release
git push upstream v2_develop
```
## NuGet
The official NuGet package for Terminal.Gui is available at [https://www.nuget.org/packages/Terminal.Gui](https://www.nuget.org/packages/Terminal.Gui). When a new version tag is defined and merged into `main`, a NuGet package is automatically generated by a GitHub Action. Pre-release versions (e.g., `1.3.4-beta.5`) are tagged as pre-release on NuGet.
The official NuGet package for Terminal.Gui is available at [https://www.nuget.org/packages/Terminal.Gui](https://www.nuget.org/packages/Terminal.Gui). When a new version tag is defined and merged into `v2_release`, a NuGet package is automatically generated by a GitHub Action. Pre-release versions (e.g., `2.0.0-beta.5`) are tagged as pre-release on NuGet.
## Contributing
We welcome contributions from the community. For detailed guidelines on how to contribute, including coding style, unit tests, and pull request processes, please refer to [CONTRIBUTING.md](https://github.com/gui-cs/Terminal.Gui/blob/master/CONTRIBUTING.md).
We welcome contributions from the community. For complete contribution guidelines, including:
- Build and test instructions
- Coding conventions and style rules
- Testing requirements and patterns
- Pull request guidelines
- CI/CD workflows
Please refer to [CONTRIBUTING.md](../CONTRIBUTING.md) in the repository root.

View File

@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.0.11018.127 d18.0
VisualStudioVersion = 18.0.11018.127
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui", "Terminal.Gui\Terminal.Gui.csproj", "{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}"
EndProject
@@ -32,7 +32,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub", "GitHub", "{13BB2C46-B324-4B9C-92EB-CE6184D4736E}"
ProjectSection(SolutionItems) = preProject
.github\workflows\api-docs.yml = .github\workflows\api-docs.yml
.github\workflows\build-release.yml = .github\workflows\build-release.yml
.github\workflows\build.yml = .github\workflows\build.yml
.github\workflows\check-duplicates.yml = .github\workflows\check-duplicates.yml
copilot-instructions.md = copilot-instructions.md
GitVersion.yml = GitVersion.yml
@@ -47,6 +47,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{C7A51224-5
.github\CODEOWNERS = .github\CODEOWNERS
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
CONTRIBUTING.md = CONTRIBUTING.md
.github\copilot-instructions.md = .github\copilot-instructions.md
README.md = README.md
EndProjectSection
EndProject

View File

@@ -584,7 +584,7 @@ public class ApplicationTests
[AutoInitShutdown]
public void Invoke_Adds_Idle ()
{
var top = new Toplevel ();
Toplevel top = new ();
RunState rs = Application.Begin (top);
var actionCalled = 0;

View File

@@ -20,8 +20,8 @@ public class WizardTests ()
public void Finish_Button_Closes ()
{
// https://github.com/gui-cs/Terminal.Gui/issues/1833
var wizard = new Wizard ();
var step1 = new WizardStep { Title = "step1" };
Wizard wizard = new ();
WizardStep step1 = new () { Title = "step1" };
wizard.AddStep (step1);
var finishedFired = false;
@@ -31,11 +31,10 @@ public class WizardTests ()
wizard.Closed += (s, e) => { closedFired = true; };
RunState runstate = Application.Begin (wizard);
var firstIteration = true;
Application.RunIteration (ref runstate, firstIteration);
AutoInitShutdownAttribute.RunIteration ();
wizard.NextFinishButton.InvokeCommand (Command.Accept);
Application.RunIteration (ref runstate, firstIteration);
AutoInitShutdownAttribute.RunIteration ();
Application.End (runstate);
Assert.True (finishedFired);
Assert.True (closedFired);
@@ -44,10 +43,9 @@ public class WizardTests ()
// Same test, but with two steps
wizard = new ();
firstIteration = false;
step1 = new() { Title = "step1" };
wizard.AddStep (step1);
var step2 = new WizardStep { Title = "step2" };
WizardStep step2 = new () { Title = "step2" };
wizard.AddStep (step2);
finishedFired = false;
@@ -57,7 +55,7 @@ public class WizardTests ()
wizard.Closed += (s, e) => { closedFired = true; };
runstate = Application.Begin (wizard);
Application.RunIteration (ref runstate, firstIteration);
AutoInitShutdownAttribute.RunIteration ();
Assert.Equal (step1.Title, wizard.CurrentStep.Title);
wizard.NextFinishButton.InvokeCommand (Command.Accept);
@@ -77,7 +75,6 @@ public class WizardTests ()
// Same test, but with two steps but the 1st one disabled
wizard = new ();
firstIteration = false;
step1 = new() { Title = "step1" };
wizard.AddStep (step1);
step2 = new() { Title = "step2" };
@@ -91,7 +88,7 @@ public class WizardTests ()
wizard.Closed += (s, e) => { closedFired = true; };
runstate = Application.Begin (wizard);
Application.RunIteration (ref runstate, firstIteration);
AutoInitShutdownAttribute.RunIteration ();
Assert.Equal (step2.Title, wizard.CurrentStep.Title);
Assert.Equal (wizard.GetLastStep ().Title, wizard.CurrentStep.Title);
@@ -458,13 +455,12 @@ public class WizardTests ()
Glyphs.LRCornerDbl
}";
var wizard = new Wizard { Title = title, Width = width, Height = height };
Wizard wizard = new () { Title = title, Width = width, Height = height };
wizard.AddStep (new() { Title = stepTitle });
//wizard.LayoutSubViews ();
var firstIteration = false;
RunState runstate = Application.Begin (wizard);
Application.RunIteration (ref runstate, firstIteration);
AutoInitShutdownAttribute.RunIteration ();
// TODO: Disabled until Dim.Auto is used in Dialog
//DriverAsserts.AssertDriverContentsWithFrameAre (

View File

@@ -222,7 +222,7 @@ public class BorderTests (ITestOutputHelper output)
[InlineData (10)]
public void Border_With_Title_Border_Double_Thickness_Top_Three_Size_Width (int width)
{
var win = new Window
Window win = new ()
{
Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double
};
@@ -231,7 +231,7 @@ public class BorderTests (ITestOutputHelper output)
RunState rs = Application.Begin (win);
AutoInitShutdownAttribute.FakeResize(new Size(width, 4));
Application.RunIteration (ref rs, false);
AutoInitShutdownAttribute.RunIteration ();
var expected = string.Empty;
switch (width)

View File

@@ -321,7 +321,7 @@ public class ClearViewportTests (ITestOutputHelper output)
{
ConfigurationManager.Enable (ConfigLocations.LibraryResources);
var root = new View { Width = 20, Height = 10 };
View root = new () { Width = 20, Height = 10 };
string text = new ('c', 100);
@@ -335,10 +335,10 @@ public class ClearViewportTests (ITestOutputHelper output)
root.Add (v);
var top = new Toplevel ();
Toplevel top = new ();
top.Add (root);
RunState runState = Application.Begin (top);
Application.RunIteration (ref runState);
AutoInitShutdownAttribute.RunIteration ();
if (label)
{

View File

@@ -91,20 +91,20 @@ public class LabelTests (ITestOutputHelper output)
[AutoInitShutdown]
public void Label_Draw_Fill_Remaining ()
{
var tfSize = new Size (80, 1);
Size tfSize = new (80, 1);
var label = new Label { Text = "This label needs to be cleared before rewritten.", Width = tfSize.Width, Height = tfSize.Height };
Label label = new () { Text = "This label needs to be cleared before rewritten.", Width = tfSize.Width, Height = tfSize.Height };
var tf1 = new TextFormatter { Direction = TextDirection.LeftRight_TopBottom, ConstrainToSize = tfSize };
TextFormatter tf1 = new () { Direction = TextDirection.LeftRight_TopBottom, ConstrainToSize = tfSize };
tf1.Text = "This TextFormatter (tf1) without fill will not be cleared on rewritten.";
var tf2 = new TextFormatter { Direction = TextDirection.LeftRight_TopBottom, ConstrainToSize = tfSize, FillRemaining = true };
TextFormatter tf2 = new () { Direction = TextDirection.LeftRight_TopBottom, ConstrainToSize = tfSize, FillRemaining = true };
tf2.Text = "This TextFormatter (tf2) with fill will be cleared on rewritten.";
var top = new Toplevel ();
Toplevel top = new ();
top.Add (label);
RunState runState = Application.Begin (top);
Application.RunIteration (ref runState);
AutoInitShutdownAttribute.RunIteration ();
Assert.False (label.TextFormatter.FillRemaining);
Assert.False (tf1.FillRemaining);

View File

@@ -467,7 +467,7 @@ public class MenuBarv1Tests (ITestOutputHelper output)
Button.DefaultShadow = ShadowStyle.None;
Toplevel top = new ();
var win = new Window ();
Window win = new ();
top.Add (win);
RunState rsTop = Application.Begin (top);
AutoInitShutdownAttribute.FakeResize(new Size(40, 15)) ;
@@ -503,8 +503,8 @@ public class MenuBarv1Tests (ITestOutputHelper output)
"Save As",
"Delete"
};
var dialog = new Dialog { X = 2, Y = 2, Width = 15, Height = 4 };
var menu = new MenuBar { X = Pos.Center (), Width = 10 };
Dialog dialog = new () { X = 2, Y = 2, Width = 15, Height = 4 };
MenuBar menu = new () { X = Pos.Center (), Width = 10 };
menu.Menus = new MenuBarItem []
{
@@ -572,7 +572,7 @@ public class MenuBarv1Tests (ITestOutputHelper output)
}
RunState rsDialog = Application.Begin (dialog);
Application.RunIteration (ref rsDialog);
AutoInitShutdownAttribute.RunIteration ();
Assert.Equal (new (2, 2, 15, 4), dialog.Frame);
@@ -598,7 +598,7 @@ public class MenuBarv1Tests (ITestOutputHelper output)
Assert.Equal ("File", menu.Menus [0].Title);
menu.OpenMenu ();
Application.RunIteration (ref rsDialog);
AutoInitShutdownAttribute.RunIteration ();
DriverAssert.AssertDriverContentsWithFrameAre (
@"
@@ -624,8 +624,7 @@ public class MenuBarv1Tests (ITestOutputHelper output)
// Need to fool MainLoop into thinking it's running
Application.MainLoop.Running = true;
bool firstIteration = true;
Application.RunIteration (ref rsDialog, firstIteration);
AutoInitShutdownAttribute.RunIteration ();
Assert.Equal (items [0], menu.Menus [0].Title);
DriverAssert.AssertDriverContentsWithFrameAre (
@@ -654,13 +653,13 @@ public class MenuBarv1Tests (ITestOutputHelper output)
Application.RaiseMouseEvent (new () { ScreenPosition = new (20, 5 + i), Flags = MouseFlags.Button1Clicked });
Application.RunIteration (ref rsDialog);
AutoInitShutdownAttribute.RunIteration ();
Assert.Equal (items [i], menu.Menus [0].Title);
}
AutoInitShutdownAttribute.FakeResize(new Size(20, 15));
menu.OpenMenu ();
Application.RunIteration (ref rsDialog);
AutoInitShutdownAttribute.RunIteration ();
DriverAssert.AssertDriverContentsWithFrameAre (
@"

View File

@@ -4813,7 +4813,7 @@ This is the second line.
public void Selected_Text_Shows ()
{
// Proves #3022 is fixed (TextField selected text does not show in v2)
var top = new Toplevel ();
Toplevel top = new ();
top.Add (_textView);
RunState rs = Application.Begin (top);
@@ -4833,7 +4833,7 @@ This is the second line.
_textView.NewKeyDownEvent (Key.CursorRight.WithCtrl.WithShift);
Application.RunIteration (ref rs, true);
AutoInitShutdownAttribute.RunIteration ();
Assert.Equal (new (4, 0), _textView.CursorPosition);
// TAB to jump between text fields.

View File

@@ -89,7 +89,7 @@ public class ClockView : View
Add(timeLabel);
// Update every second
timerToken = Application.MainLoop.AddTimeout(
timerToken = Application.AddTimeout(
TimeSpan.FromSeconds(1),
UpdateTime
);
@@ -105,7 +105,7 @@ public class ClockView : View
{
if (disposing && timerToken != null)
{
Application.MainLoop.RemoveTimeout(timerToken);
Application.RemoveTimeout(timerToken);
}
base.Dispose(disposing);
}
@@ -220,7 +220,7 @@ Task.Run(() =>
### ❌ Don't: Forget to clean up timers
```csharp
// Memory leak - timer keeps running after view is disposed
Application.MainLoop.AddTimeout(TimeSpan.FromSeconds(1), UpdateStatus);
Application.AddTimeout(TimeSpan.FromSeconds(1), UpdateStatus);
```
### ✅ Do: Remove timers in Dispose
@@ -229,7 +229,7 @@ protected override void Dispose(bool disposing)
{
if (disposing && timerToken != null)
{
Application.MainLoop.RemoveTimeout(timerToken);
Application.RemoveTimeout(timerToken);
}
base.Dispose(disposing);
}