mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
429 lines
16 KiB
Markdown
429 lines
16 KiB
Markdown
# Contributing to Terminal.Gui
|
|
|
|
> **📘 This document is the single source of truth for all contributors (humans and AI agents) to Terminal.Gui.**
|
|
|
|
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.
|
|
|
|
## Table of Contents
|
|
|
|
- [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)
|
|
|
|
---
|
|
|
|
## 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) 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)
|
|
- **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 (honor `.editorconfig` and `Terminal.sln.DotSettings`)
|
|
|
|
### 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
|
|
```
|
|
|
|
### Common Build Issues
|
|
|
|
#### Issue: Build Warnings
|
|
- **Expected**: None warnings (~100 currently).
|
|
- **Action**: Don't add new warnings; fix warnings in code you modify
|
|
|
|
#### 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
|
|
|
|
**⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code:**
|
|
|
|
- **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**
|
|
- Follow `.editorconfig` settings (e.g., braces on new lines, spaces after keywords)
|
|
- 4-space indentation
|
|
- No trailing whitespace
|
|
- File-scoped namespaces
|
|
- **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?>();
|
|
```
|
|
|
|
- **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();
|
|
```
|
|
|
|
**⚠️ CRITICAL - 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
|
|
- **Coverage collection**:
|
|
- Centralized in `TestResults/` directory at repository root
|
|
- Collected only on Linux (ubuntu-latest) runners in CI for performance
|
|
- Windows and macOS runners skip coverage collection to reduce execution time
|
|
- Coverage reports uploaded to Codecov automatically from Linux runner
|
|
- 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 - Clear, concise, complete. Use imperative mood.
|
|
|
|
---
|
|
|
|
## Pull Request Guidelines
|
|
|
|
### PR Requirements
|
|
|
|
- **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
|
|
- **Warnings**: **CRITICAL - PRs must not introduce any new warnings**
|
|
- Any file modified in a PR that currently generates warnings **MUST** be fixed to remove those warnings
|
|
- Exception: Warnings caused by `[Obsolete]` attributes can remain
|
|
- Expected baseline: ~326 warnings (mostly nullable reference warnings, unused variables, xUnit suggestions)
|
|
- Action: Before submitting a PR, verify your changes don't add new warnings and fix any warnings in files you modify
|
|
|
|
---
|
|
|
|
## CI/CD Workflows
|
|
|
|
The repository uses multiple GitHub Actions workflows. What runs and when:
|
|
|
|
### 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`)
|
|
- **Matrix**: Ubuntu/Windows/macOS
|
|
- **Timeout**: 15 minutes per job
|
|
- **Process**:
|
|
1. Calls build workflow to build solution once
|
|
2. Downloads build artifacts
|
|
3. Runs `dotnet restore` (required for `--no-build` to work)
|
|
4. **Performance optimizations**:
|
|
- Disables Windows Defender on Windows runners (significant speedup)
|
|
- Collects code coverage **only on Linux** (ubuntu-latest) for performance
|
|
- Windows and macOS skip coverage collection to reduce test time
|
|
- Increased blame-hang-timeout to 120s for Windows/macOS (60s for Linux)
|
|
5. Runs two test jobs:
|
|
- **Non-parallel UnitTests**: `Tests/UnitTests` with blame/diag flags; `xunit.stopOnFail=false`
|
|
- **Parallel UnitTestsParallelizable**: `Tests/UnitTestsParallelizable` with blame/diag flags; `xunit.stopOnFail=false`
|
|
6. Uploads test logs and diagnostic data from all runners
|
|
7. **Uploads code coverage to Codecov only from Linux runner**
|
|
|
|
**Test results**: All tests output to unified `TestResults/` directory at repository root
|
|
|
|
### 3) Build & Run Integration Tests (`.github/workflows/integration-tests.yml`)
|
|
|
|
- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
|
|
- **Matrix**: Ubuntu/Windows/macOS
|
|
- **Timeout**: 15 minutes
|
|
- **Process**:
|
|
1. Calls build workflow
|
|
2. Downloads build artifacts
|
|
3. Runs `dotnet restore`
|
|
4. **Performance optimizations** (same as unit tests):
|
|
- Disables Windows Defender on Windows runners
|
|
- Collects code coverage **only on Linux**
|
|
- Increased blame-hang-timeout to 120s for Windows/macOS
|
|
5. Runs IntegrationTests with blame/diag flags; `xunit.stopOnFail=true`
|
|
6. Uploads logs per-OS
|
|
7. **Uploads coverage to Codecov only from Linux runner**
|
|
|
|
### 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
|
|
```
|
|
|
|
---
|
|
|
|
## 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
|
|
- `CONTRIBUTING.md` - This file - contribution guidelines (source of truth)
|
|
- `AGENTS.md` - Pointer to this file for AI agents
|
|
- `README.md` - Project documentation
|
|
|
|
### Main Directories
|
|
|
|
**`/Terminal.Gui/`** - Core library (496 C# files):
|
|
- `App/` - Application lifecycle (`Application.cs` static class, `SessionToken`, `MainLoop`)
|
|
- `Configuration/` - `ConfigurationManager` for settings
|
|
- `Drivers/` - Console driver implementations (`Dotnet`, `Windows`, `Unix`, `Fake`)
|
|
- `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 ()`)
|
|
- ❌ **Don't introduce new warnings** (fix warnings in files you modify; exception: `[Obsolete]` warnings)
|
|
|
|
---
|
|
|
|
## 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!** 🎉
|