# 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 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(); ``` - **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 `` tags - Use `` for cross-references - Add `` for context - Include `` 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 git fetch copilot git checkout copilot/ ``` - **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!** 🎉