mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Revise terminology proposal based on maintainer feedback
Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
@@ -1,159 +1,114 @@
|
||||
# Application.Run Terminology Proposal - Executive Summary
|
||||
# Application.Run Terminology - Executive Summary
|
||||
|
||||
## 🎯 Purpose
|
||||
## The Ask
|
||||
|
||||
Propose clearer, more intuitive terminology for the `Application.Run` lifecycle APIs in Terminal.Gui.
|
||||
Propose improved terminology for `Application.Run` lifecycle APIs to reduce confusion.
|
||||
|
||||
## 📊 The Problem in 30 Seconds
|
||||
## Maintainer Feedback
|
||||
|
||||
Based on @tig's review:
|
||||
- ✅ Keep deep analysis and diagrams
|
||||
- ✅ Keep `Begin` and `End` (not wordy like BeginSession/EndSession)
|
||||
- ✅ Keep `RequestStop` (non-blocking nature is clear)
|
||||
- ✅ Preserve distinction between `RunLoop` (starts driver's mainloop) and `RunIteration` (one iteration)
|
||||
|
||||
## The Real Problems (Only 2)
|
||||
|
||||
### 1. `RunState` Sounds Like State Data
|
||||
|
||||
```csharp
|
||||
// Current: "Run" means too many things
|
||||
Application.Run(window); // ← Complete lifecycle
|
||||
Application.RunLoop(runState); // ← Event loop?
|
||||
Application.RunIteration(); // ← One iteration?
|
||||
|
||||
RunState runState = Application.Begin(window); // ← Begin what? What's RunState?
|
||||
Application.End(runState); // ← End what?
|
||||
RunState rs = Application.Begin(window); // ❌ What state does it hold?
|
||||
```
|
||||
|
||||
**Result:** Confused users, unclear docs, steep learning curve.
|
||||
**Reality:** It's a token/handle for Begin/End pairing, not state data.
|
||||
|
||||
## ✅ The Solution in 30 Seconds
|
||||
**Solution:** Rename to `RunToken` (clear it's a token, concise).
|
||||
|
||||
### 2. `EndAfterFirstIteration` Confuses End() Method with Loop Control
|
||||
|
||||
```csharp
|
||||
// Proposed: Clear, self-documenting names
|
||||
Application.Run(window); // ← Unchanged (high-level)
|
||||
|
||||
ToplevelSession session = Application.BeginSession(window); // ✅ Clear
|
||||
Application.ProcessEvents(session); // ✅ Clear
|
||||
Application.EndSession(session); // ✅ Clear
|
||||
Application.EndAfterFirstIteration = true; // ❌ Does this call End()?
|
||||
```
|
||||
|
||||
**Result:** Self-documenting APIs, faster learning, industry alignment.
|
||||
**Reality:** It controls `RunLoop()` behavior, not lifecycle cleanup.
|
||||
|
||||
## 📈 Impact
|
||||
**Solution:** Rename to `StopAfterFirstIteration` (aligns with `RequestStop`, clearly about loop control).
|
||||
|
||||
### Who This Affects
|
||||
- ✅ **New users:** Easier to understand and learn
|
||||
- ✅ **Existing users:** Optional upgrade via [Obsolete] warnings
|
||||
- ✅ **Documentation:** Clearer explanations possible
|
||||
- ✅ **Maintainers:** Fewer confused user questions
|
||||
## Proposed Changes (Minimal - 2 Names Only)
|
||||
|
||||
### Breaking Changes
|
||||
- ❌ **NONE** - All existing APIs continue to work
|
||||
- ✅ Old APIs marked `[Obsolete]` with helpful migration messages
|
||||
- ✅ Gradual migration at each user's own pace
|
||||
| Current | Proposed | Why |
|
||||
|---------|----------|-----|
|
||||
| `RunState` | `RunToken` | Clear it's a token, not state |
|
||||
| `EndAfterFirstIteration` | `StopAfterFirstIteration` | Clear it controls loop, aligns with RequestStop |
|
||||
|
||||
## 🔄 Complete Mapping
|
||||
## Keep Unchanged
|
||||
|
||||
| Current API | Proposed API | Benefit |
|
||||
|-------------|--------------|---------|
|
||||
| `RunState` | `ToplevelSession` | Clear it's a session token |
|
||||
| `Begin()` | `BeginSession()` | Unambiguous what's beginning |
|
||||
| `RunLoop()` | `ProcessEvents()` | Describes the action |
|
||||
| `RunIteration()` | `ProcessEventsIteration()` | Consistent naming |
|
||||
| `End()` | `EndSession()` | Unambiguous what's ending |
|
||||
| `RequestStop()` | `StopProcessingEvents()` | Explicit about what stops |
|
||||
| API | Why It Works |
|
||||
|-----|--------------|
|
||||
| `Begin` / `End` | Clear, concise - not wordy |
|
||||
| `RequestStop` | "Request" appropriately conveys non-blocking |
|
||||
| `RunLoop` / `RunIteration` | Distinction is important: RunLoop starts mainloop, RunIteration processes one iteration |
|
||||
|
||||
## 💡 Why "Session"?
|
||||
## Usage Comparison
|
||||
|
||||
1. **Industry Standard**
|
||||
- `HttpContext` - one HTTP request session
|
||||
- `DbContext` - one database session
|
||||
- `CancellationToken` - one cancellation scope
|
||||
|
||||
2. **Accurate**
|
||||
- A Toplevel execution IS a bounded session
|
||||
- Multiple sessions can exist (nested modals)
|
||||
- Sessions have clear begin/end lifecycle
|
||||
|
||||
3. **Clear**
|
||||
- "Session" implies temporary, bounded execution
|
||||
- "BeginSession/EndSession" are unambiguous pairs
|
||||
- "ToplevelSession" clearly indicates purpose
|
||||
|
||||
## 📚 Documentation Structure
|
||||
|
||||
```
|
||||
TERMINOLOGY_README.md (Start Here)
|
||||
├─ Overview and navigation
|
||||
├─ Problem statement
|
||||
└─ Links to all documents
|
||||
|
||||
TERMINOLOGY_PROPOSAL.md
|
||||
├─ Complete analysis
|
||||
├─ 3 options with rationale
|
||||
├─ Migration strategy
|
||||
└─ FAQ
|
||||
|
||||
TERMINOLOGY_QUICK_REFERENCE.md
|
||||
├─ Side-by-side comparisons
|
||||
├─ Usage examples
|
||||
└─ Quick lookup tables
|
||||
|
||||
TERMINOLOGY_INDUSTRY_COMPARISON.md
|
||||
├─ Framework comparisons
|
||||
├─ Industry patterns
|
||||
└─ Why this solution
|
||||
|
||||
TERMINOLOGY_VISUAL_GUIDE.md
|
||||
├─ ASCII diagrams
|
||||
├─ Flow charts
|
||||
└─ Visual comparisons
|
||||
### Before (Confusing)
|
||||
```csharp
|
||||
RunState rs = Application.Begin(window);
|
||||
Application.EndAfterFirstIteration = true;
|
||||
Application.RunLoop(rs);
|
||||
Application.End(rs);
|
||||
```
|
||||
|
||||
## 🚀 Next Steps
|
||||
### After (Clear)
|
||||
```csharp
|
||||
RunToken token = Application.Begin(window);
|
||||
Application.StopAfterFirstIteration = true;
|
||||
Application.RunLoop(token);
|
||||
Application.End(token);
|
||||
```
|
||||
|
||||
1. **Review** - Community reviews this proposal
|
||||
2. **Feedback** - Gather comments and suggestions
|
||||
3. **Refine** - Adjust based on feedback
|
||||
4. **Approve** - Get maintainer approval
|
||||
5. **Implement** - Add new APIs with [Obsolete] on old ones
|
||||
6. **Document** - Update all documentation
|
||||
7. **Migrate** - Examples and guides use new terminology
|
||||
## Benefits
|
||||
|
||||
## ⏱️ Timeline (Proposed)
|
||||
- ✅ Addresses the 2 primary sources of confusion
|
||||
- ✅ Minimal disruption (only 2 names)
|
||||
- ✅ Backward compatible (obsolete attributes on old names)
|
||||
- ✅ Respects maintainer feedback
|
||||
- ✅ Preserves what works well
|
||||
|
||||
- **Phase 1 (Release N):** Add new APIs, mark old ones obsolete
|
||||
- **Phase 2 (Release N+1):** Update all documentation
|
||||
- **Phase 3 (Release N+2):** Update all examples
|
||||
- **Phase 4 (Release N+3+):** Consider removing obsolete APIs (or keep forever)
|
||||
## Documents
|
||||
|
||||
## 🗳️ Alternative Options
|
||||
- **TERMINOLOGY_PROPOSAL.md** - Complete analysis with rationale
|
||||
- **TERMINOLOGY_QUICK_REFERENCE.md** - Quick comparison and examples
|
||||
- **TERMINOLOGY_VISUAL_GUIDE.md** - Visual diagrams showing the issues
|
||||
|
||||
This proposal includes 3 options:
|
||||
## Alternative Options
|
||||
|
||||
1. **Session-Based** ⭐ (Recommended)
|
||||
- BeginSession/ProcessEvents/EndSession
|
||||
- Most accurate and industry-aligned
|
||||
### For RunState
|
||||
- **RunToken** ⭐ (Recommended) - Clear, concise
|
||||
- ExecutionContext - Industry standard but longer
|
||||
- Keep as-is - Not recommended (remains misleading)
|
||||
|
||||
2. **Modal/Show**
|
||||
- Activate/EventLoop/Deactivate
|
||||
- Aligns with WPF patterns
|
||||
### For EndAfterFirstIteration
|
||||
- **StopAfterFirstIteration** ⭐ (Recommended) - Aligns with RequestStop
|
||||
- SingleIteration - Shorter but less obvious
|
||||
- Keep as-is - Not recommended (continues confusion)
|
||||
|
||||
3. **Lifecycle**
|
||||
- Start/Execute/Stop
|
||||
- Simple verbs
|
||||
## Migration Path
|
||||
|
||||
See [TERMINOLOGY_PROPOSAL.md](TERMINOLOGY_PROPOSAL.md) for detailed comparison.
|
||||
Backward compatible via obsolete attributes:
|
||||
|
||||
## 💬 Feedback Welcome
|
||||
```csharp
|
||||
[Obsolete("Use RunToken instead")]
|
||||
public class RunState { ... }
|
||||
|
||||
- What do you think of the proposed names?
|
||||
- Do you prefer a different option?
|
||||
- Any concerns about migration?
|
||||
- Timeline reasonable for your projects?
|
||||
[Obsolete("Use StopAfterFirstIteration instead")]
|
||||
public static bool EndAfterFirstIteration { get; set; }
|
||||
```
|
||||
|
||||
## 📖 Full Documentation
|
||||
|
||||
Read the complete proposal: [TERMINOLOGY_README.md](TERMINOLOGY_README.md)
|
||||
Users can migrate gradually with simple find/replace.
|
||||
|
||||
---
|
||||
|
||||
**Status:** 📝 Awaiting Community Feedback
|
||||
|
||||
**Issue:** #4329
|
||||
|
||||
**Created:** 2025-10-25
|
||||
|
||||
**Author:** GitHub Copilot
|
||||
**Status:** Revised based on maintainer feedback
|
||||
**Focus:** Minimal, targeted changes addressing real confusion
|
||||
**Impact:** Low (2 names), High clarity gain
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
# Application.Run Terminology - Industry Comparison
|
||||
|
||||
This document compares Terminal.Gui's terminology with other popular UI frameworks to provide context for the proposed changes.
|
||||
|
||||
## Framework Comparison Matrix
|
||||
|
||||
### Complete Lifecycle (Show/Run a Window)
|
||||
|
||||
| Framework | API | Notes |
|
||||
|-----------|-----|-------|
|
||||
| **Terminal.Gui (current)** | `Application.Run(toplevel)` | Modal execution |
|
||||
| **Terminal.Gui (proposed)** | `Application.Run(toplevel)` | Keep same (high-level API) |
|
||||
| **WPF** | `window.ShowDialog()` | Modal, returns DialogResult |
|
||||
| **WPF** | `window.Show()` | Non-modal |
|
||||
| **WinForms** | `form.ShowDialog()` | Modal |
|
||||
| **WinForms** | `Application.Run(form)` | Main message loop |
|
||||
| **Avalonia** | `window.ShowDialog()` | Modal, async |
|
||||
| **GTK#** | `window.ShowAll()` + `Gtk.Application.Run()` | Combined |
|
||||
| **Qt** | `QApplication::exec()` | Main event loop |
|
||||
| **Electron** | `mainWindow.show()` | Non-modal |
|
||||
|
||||
### Session/Context Token
|
||||
|
||||
| Framework | Concept | Type | Purpose |
|
||||
|-----------|---------|------|---------|
|
||||
| **Terminal.Gui (current)** | `RunState` | Class | Token for Begin/End pairing |
|
||||
| **Terminal.Gui (proposed)** | `ToplevelSession` | Class | Session token (clearer name) |
|
||||
| **WPF** | N/A | - | Hidden by framework |
|
||||
| **WinForms** | `ApplicationContext` | Class | Message loop context |
|
||||
| **Avalonia** | N/A | - | Hidden by framework |
|
||||
| **ASP.NET** | `HttpContext` | Class | Request context (analogous) |
|
||||
| **Entity Framework** | `DbContext` | Class | Session context (analogous) |
|
||||
|
||||
**Analysis:** "Session" or "Context" are industry standards for bounded execution periods. "State" is misleading.
|
||||
|
||||
### Initialize/Start
|
||||
|
||||
| Framework | API | Purpose |
|
||||
|-----------|-----|---------|
|
||||
| **Terminal.Gui (current)** | `Application.Begin(toplevel)` | Prepare toplevel for execution |
|
||||
| **Terminal.Gui (proposed)** | `Application.BeginSession(toplevel)` | Start an execution session |
|
||||
| **WPF** | `window.Show()` / `window.ShowDialog()` | Combined with event loop |
|
||||
| **WinForms** | `Application.Run(form)` | Combined initialization |
|
||||
| **Node.js HTTP** | `server.listen()` | Start accepting requests |
|
||||
| **ASP.NET** | `app.Run()` | Start web server |
|
||||
| **Qt** | `widget->show()` | Show widget |
|
||||
|
||||
**Analysis:** Most frameworks combine initialization with execution. Terminal.Gui's separation is powerful for advanced scenarios.
|
||||
|
||||
### Event Loop Processing
|
||||
|
||||
| Framework | API | Purpose | Notes |
|
||||
|-----------|-----|---------|-------|
|
||||
| **Terminal.Gui (current)** | `Application.RunLoop(runState)` | Process events until stopped | Confusing "Run" + "Loop" |
|
||||
| **Terminal.Gui (proposed)** | `Application.ProcessEvents(session)` | Process events until stopped | Clear action verb |
|
||||
| **WPF** | `Dispatcher.Run()` | Run dispatcher loop | Hidden in most apps |
|
||||
| **WinForms** | `Application.Run()` | Process message loop | Auto-started |
|
||||
| **Node.js** | `eventLoop.run()` | Run event loop | Internal |
|
||||
| **Qt** | `QApplication::exec()` | Execute event loop | "exec" = execute |
|
||||
| **GTK** | `Gtk.Application.Run()` | Main loop | Standard GTK term |
|
||||
| **Win32** | `GetMessage()` / `DispatchMessage()` | Message pump | Manual control |
|
||||
| **X11** | `XNextEvent()` | Process events | Manual control |
|
||||
|
||||
**Analysis:** "ProcessEvents" or "EventLoop" are clearer than "RunLoop". The term "pump" is Windows-specific.
|
||||
|
||||
### Single Iteration
|
||||
|
||||
| Framework | API | Purpose |
|
||||
|-----------|-----|---------|
|
||||
| **Terminal.Gui (current)** | `Application.RunIteration()` | Process one event cycle |
|
||||
| **Terminal.Gui (proposed)** | `Application.ProcessEventsIteration()` | Process one event cycle |
|
||||
| **Game Engines (Unity)** | `Update()` / `Tick()` | One frame/tick |
|
||||
| **Game Engines (Unreal)** | `Tick(DeltaTime)` | One frame |
|
||||
| **WPF** | `Dispatcher.ProcessEvents()` | Process pending events |
|
||||
| **WinForms** | `Application.DoEvents()` | Process pending events |
|
||||
| **Node.js** | `setImmediate()` / `process.nextTick()` | Next event loop iteration |
|
||||
|
||||
**Analysis:** "Iteration", "Tick", or "DoEvents" are all clear. "ProcessEvents" aligns with WPF.
|
||||
|
||||
### Cleanup/End
|
||||
|
||||
| Framework | API | Purpose |
|
||||
|-----------|-----|---------|
|
||||
| **Terminal.Gui (current)** | `Application.End(runState)` | Clean up after execution |
|
||||
| **Terminal.Gui (proposed)** | `Application.EndSession(session)` | End the execution session |
|
||||
| **WPF** | `window.Close()` | Close window |
|
||||
| **WinForms** | `form.Close()` | Close form |
|
||||
| **ASP.NET** | Request ends automatically | Dispose context |
|
||||
| **Entity Framework** | `context.Dispose()` | Dispose context |
|
||||
|
||||
**Analysis:** "EndSession" pairs clearly with "BeginSession". "Close" works for windows but not for execution context.
|
||||
|
||||
### Stop/Request Stop
|
||||
|
||||
| Framework | API | Purpose |
|
||||
|-----------|-----|---------|
|
||||
| **Terminal.Gui (current)** | `Application.RequestStop()` | Signal loop to stop |
|
||||
| **Terminal.Gui (proposed)** | `Application.StopProcessingEvents()` | Stop event processing |
|
||||
| **WPF** | `window.Close()` | Close window, stops its loop |
|
||||
| **WinForms** | `Application.Exit()` | Exit application |
|
||||
| **Node.js** | `server.close()` | Stop accepting connections |
|
||||
| **CancellationToken** | `cancellationToken.Cancel()` | Request cancellation |
|
||||
|
||||
**Analysis:** "RequestStop" is already clear. "StopProcessingEvents" is more explicit about what stops.
|
||||
|
||||
## Terminology Patterns Across Industries
|
||||
|
||||
### Game Development
|
||||
|
||||
Game engines use clear, explicit terminology:
|
||||
|
||||
```csharp
|
||||
// Unity pattern
|
||||
void Start() { } // Initialize
|
||||
void Update() { } // Per-frame update (tick)
|
||||
void OnDestroy() { } // Cleanup
|
||||
|
||||
// Typical game loop
|
||||
while (running)
|
||||
{
|
||||
ProcessInput();
|
||||
UpdateGameState();
|
||||
Render();
|
||||
}
|
||||
```
|
||||
|
||||
**Lesson:** Use explicit verbs that describe what happens each phase.
|
||||
|
||||
### Web Development
|
||||
|
||||
Web frameworks use session/context patterns:
|
||||
|
||||
```csharp
|
||||
// ASP.NET Core
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.Run(async context => // HttpContext = request session
|
||||
{
|
||||
await context.Response.WriteAsync("Hello");
|
||||
});
|
||||
}
|
||||
|
||||
// Entity Framework
|
||||
using (var context = new DbContext()) // Session
|
||||
{
|
||||
// Work with data
|
||||
}
|
||||
```
|
||||
|
||||
**Lesson:** "Context" or "Session" for bounded execution periods is industry standard.
|
||||
|
||||
### GUI Frameworks
|
||||
|
||||
Desktop GUI frameworks separate showing from modal execution:
|
||||
|
||||
```csharp
|
||||
// WPF pattern
|
||||
window.Show(); // Non-modal
|
||||
var result = window.ShowDialog(); // Modal (blocks)
|
||||
|
||||
// Terminal.Gui (current - confusing)
|
||||
Application.Run(toplevel); // Modal? Non-modal? Unclear
|
||||
|
||||
// Terminal.Gui (proposed - clearer)
|
||||
Application.Run(toplevel); // High-level: modal execution
|
||||
// OR low-level:
|
||||
var session = Application.BeginSession(toplevel);
|
||||
Application.ProcessEvents(session);
|
||||
Application.EndSession(session);
|
||||
```
|
||||
|
||||
**Lesson:** Separate high-level convenience from low-level control.
|
||||
|
||||
## Key Insights
|
||||
|
||||
### 1. "Run" is Overloaded Everywhere
|
||||
|
||||
Many frameworks have "Run" methods, but they mean different things:
|
||||
- **WPF**: `Application.Run()` - "run the entire application"
|
||||
- **WinForms**: `Application.Run(form)` - "run with this form as main"
|
||||
- **ASP.NET**: `app.Run()` - "start the web server"
|
||||
- **Terminal.Gui**: `Application.Run(toplevel)` - "run this toplevel modally"
|
||||
|
||||
**Solution:** Keep high-level `Run()` for simplicity, but clarify low-level APIs.
|
||||
|
||||
### 2. Session/Context Pattern is Standard
|
||||
|
||||
The pattern of a token representing a bounded execution period is common:
|
||||
- `HttpContext` - one HTTP request
|
||||
- `DbContext` - one database session
|
||||
- `ExecutionContext` - one execution scope
|
||||
- `CancellationToken` - one cancellation scope
|
||||
|
||||
**Terminal.Gui's `RunState` fits this pattern** - it should be named accordingly.
|
||||
|
||||
### 3. Begin/End vs Start/Stop vs Open/Close
|
||||
|
||||
Different frameworks use different pairs:
|
||||
- **Begin/End** - .NET (BeginInvoke/EndInvoke, BeginInit/EndInit)
|
||||
- **Start/Stop** - Common (StartService/StopService)
|
||||
- **Open/Close** - Resources (OpenFile/CloseFile, OpenConnection/CloseConnection)
|
||||
|
||||
Terminal.Gui currently uses **Begin/End**, which is fine, but it needs a noun:
|
||||
- ✅ `BeginSession/EndSession` - Clear
|
||||
- ❓ `Begin/End` - Begin what?
|
||||
|
||||
### 4. Event Processing Terminology
|
||||
|
||||
Most frameworks use one of:
|
||||
- **ProcessEvents** - Explicit action (WPF, WinForms)
|
||||
- **EventLoop** - Noun describing the construct
|
||||
- **Pump/PumpMessages** - Windows-specific
|
||||
- **Dispatch** - Action of dispatching events
|
||||
|
||||
**Terminal.Gui's "RunLoop"** is ambiguous - it could be a verb (run the loop) or a noun (the RunLoop object).
|
||||
|
||||
## Recommendations Based on Industry Analysis
|
||||
|
||||
### Primary Recommendation: Session-Based (Option 1)
|
||||
|
||||
```
|
||||
Application.Run(toplevel) // Keep - familiar, simple
|
||||
├─ Application.BeginSession(toplevel) → ToplevelSession
|
||||
├─ Application.ProcessEvents(session)
|
||||
└─ Application.EndSession(session)
|
||||
```
|
||||
|
||||
**Aligns with:**
|
||||
- .NET patterns (BeginInvoke/EndInvoke, HttpContext sessions)
|
||||
- Industry standard "session" terminology
|
||||
- Explicit "ProcessEvents" from WPF/WinForms
|
||||
|
||||
**Why it wins:**
|
||||
1. "Session" is universally understood as bounded execution
|
||||
2. "ProcessEvents" is explicit about what happens
|
||||
3. Begin/End is already .NET standard
|
||||
4. Minimal disruption to existing mental model
|
||||
|
||||
### Alternative: Lifecycle-Based (Option 3)
|
||||
|
||||
```
|
||||
Application.Run(toplevel)
|
||||
├─ Application.Start(toplevel) → ExecutionContext
|
||||
├─ Application.Execute(context)
|
||||
└─ Application.Stop(context)
|
||||
```
|
||||
|
||||
**Aligns with:**
|
||||
- Service patterns (StartService/StopService)
|
||||
- Game patterns (Start/Update/Stop)
|
||||
- Simpler verbs
|
||||
|
||||
**Trade-offs:**
|
||||
- ⚠️ "Start/Stop" breaks existing Begin/End pattern
|
||||
- ✅ More intuitive for newcomers
|
||||
- ⚠️ "Execute" is less explicit than "ProcessEvents"
|
||||
|
||||
### Why Not Modal/Show (Option 2)
|
||||
|
||||
```
|
||||
Application.ShowModal(toplevel)
|
||||
├─ Application.Activate(toplevel)
|
||||
└─ Application.Deactivate(toplevel)
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
- Terminal.Gui doesn't distinguish modal/non-modal the way WPF does
|
||||
- "Activate/Deactivate" implies window state, not execution
|
||||
- Bigger departure from current API
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Industry analysis supports Option 1 (Session-Based):**
|
||||
|
||||
1. ✅ "Session" is industry standard for bounded execution
|
||||
2. ✅ "ProcessEvents" is clear and matches WPF/WinForms
|
||||
3. ✅ Begin/End is established .NET pattern
|
||||
4. ✅ Minimal disruption to existing API
|
||||
5. ✅ Clear improvement over current "Run*" terminology
|
||||
|
||||
The proposed terminology brings Terminal.Gui in line with industry patterns while respecting its unique architecture that exposes low-level event loop control.
|
||||
|
||||
## References
|
||||
|
||||
- [WPF Application Model](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/app-development/application-management-overview)
|
||||
- [WinForms Application Class](https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.application)
|
||||
- [Avalonia Application Lifetime](https://docs.avaloniaui.net/docs/concepts/application-lifetimes)
|
||||
- [GTK Application](https://docs.gtk.org/gtk4/class.Application.html)
|
||||
- [Qt Application](https://doc.qt.io/qt-6/qapplication.html)
|
||||
- [.NET HttpContext](https://docs.microsoft.com/en-us/dotnet/api/system.web.httpcontext)
|
||||
- [Entity Framework DbContext](https://docs.microsoft.com/en-us/ef/core/dbcontext-configuration/)
|
||||
@@ -1,277 +1,306 @@
|
||||
# Application.Run Terminology Proposal
|
||||
# Application.Run Terminology Proposal (Revised)
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document proposes improved terminology for the Terminal.Gui application execution lifecycle. The current `Run` terminology is overloaded and confusing, encompassing multiple distinct concepts. This proposal introduces clearer, more precise naming that better communicates the purpose and relationships of each API.
|
||||
This proposal addresses specific terminology issues in the Terminal.Gui Application.Run lifecycle while preserving what works well. Based on maintainer feedback, we keep `Begin`, `End`, and `RequestStop` unchanged, and focus on the real sources of confusion.
|
||||
|
||||
## Problem Statement
|
||||
## What Works Well (Keep Unchanged)
|
||||
|
||||
The current terminology around `Application.Run` is confusing because:
|
||||
- ✅ **`Begin` and `End`** - Clear, concise lifecycle pairing without being wordy
|
||||
- ✅ **`RequestStop`** - Non-blocking nature is appropriately conveyed by "Request"
|
||||
- ✅ **Distinction between `RunLoop` and `RunIteration`** - `RunLoop` starts the driver's mainloop, `RunIteration` processes one iteration
|
||||
|
||||
1. **"Run" is overloaded** - It refers to both:
|
||||
- The complete lifecycle (Begin → RunLoop → End → Stop)
|
||||
- The event loop itself (RunLoop)
|
||||
- Multiple API methods (Run, RunLoop, RunIteration)
|
||||
## The Real Problems
|
||||
|
||||
2. **Relationships are unclear** - Users don't understand that:
|
||||
- `Run()` is a convenience method = `Begin()` + `RunLoop()` + `End()`
|
||||
- `RunState` is a session token, not a state object
|
||||
- `RequestStop()` affects `RunLoop()` which triggers `End()`
|
||||
### Problem 1: `RunState` Sounds Like State Data
|
||||
|
||||
3. **Inconsistent with industry patterns** - Other frameworks use clearer terms:
|
||||
- WPF: `Show()`, `ShowDialog()`, `Close()`
|
||||
- WinForms: `Show()`, `ShowDialog()`, `Application.Run()`
|
||||
- Avalonia: `Show()`, `ShowDialog()`, `StartWithClassicDesktopLifetime()`
|
||||
|
||||
## Current Terminology Analysis
|
||||
|
||||
### Current APIs and Their Actual Purposes
|
||||
|
||||
| Current Name | Actual Purpose | Confusion Point |
|
||||
|-------------|----------------|-----------------|
|
||||
| `Run()` | Complete lifecycle: Begin + Loop + End | Overloaded - means too many things |
|
||||
| `RunState` | Session token/handle for a Toplevel execution | Sounds like state data, not a handle |
|
||||
| `Begin()` | Initialize and prepare a Toplevel for execution | "Begin" what? Begin running? |
|
||||
| `RunLoop()` | Execute the event loop until stopped | Clear, but tied to "Run" |
|
||||
| `RunIteration()` | Execute one iteration of the event loop | Clear |
|
||||
| `End()` | Clean up after a Toplevel execution session | "End" what? End running? |
|
||||
| `RequestStop()` | Signal the event loop to stop | What does it stop? |
|
||||
| `EndAfterFirstIteration` | Exit after one loop iteration | Tied to "End" but affects loop |
|
||||
|
||||
### Current Flow
|
||||
|
||||
```
|
||||
Application.Run(toplevel)
|
||||
└─> Application.Begin(toplevel) → returns RunState
|
||||
└─> Initialize
|
||||
└─> Layout
|
||||
└─> Draw
|
||||
└─> Application.RunLoop(runState)
|
||||
└─> while (Running)
|
||||
└─> Application.RunIteration()
|
||||
└─> Process events
|
||||
└─> Layout (if needed)
|
||||
└─> Draw (if needed)
|
||||
└─> Application.End(runState)
|
||||
└─> Clean up
|
||||
└─> Dispose RunState
|
||||
```
|
||||
|
||||
## Proposed Terminology
|
||||
|
||||
### Option 1: Session-Based Terminology (Recommended)
|
||||
|
||||
This option emphasizes that running a Toplevel is a "session" with clear lifecycle management.
|
||||
|
||||
| Current | Proposed | Rationale |
|
||||
|---------|----------|-----------|
|
||||
| `Run()` | `Run()` | Keep for backward compatibility and familiarity |
|
||||
| `RunState` | `ToplevelSession` | Clear that it's a session token, not state |
|
||||
| `Begin()` | `BeginSession()` | Clear what is beginning |
|
||||
| `RunLoop()` | `ProcessEvents()` | Describes what it does, not abstract "run" |
|
||||
| `RunIteration()` | `ProcessEventsIteration()` | Consistent with ProcessEvents |
|
||||
| `End()` | `EndSession()` | Clear what is ending |
|
||||
| `RequestStop()` | `StopProcessingEvents()` | Clear what stops |
|
||||
| `EndAfterFirstIteration` | `StopAfterFirstIteration` | Consistent with Stop terminology |
|
||||
|
||||
**Usage Example:**
|
||||
**Current:**
|
||||
```csharp
|
||||
// High-level (unchanged)
|
||||
Application.Run(myWindow);
|
||||
|
||||
// Low-level (new names)
|
||||
ToplevelSession session = Application.BeginSession(myWindow);
|
||||
Application.ProcessEvents(session);
|
||||
Application.EndSession(session);
|
||||
RunState runState = Application.Begin(toplevel);
|
||||
Application.RunLoop(runState);
|
||||
Application.End(runState);
|
||||
```
|
||||
|
||||
### Option 2: Modal/Show Terminology
|
||||
**Issue:** The name `RunState` suggests it holds state/data about the run, but it's actually:
|
||||
- A token/handle returned by `Begin()` to pair with `End()`
|
||||
- An execution context for the Toplevel
|
||||
- Not primarily about "state" - it's about identity/scoping
|
||||
|
||||
This option aligns with WPF/WinForms patterns, emphasizing the modal/non-modal nature.
|
||||
**Proposed Options:**
|
||||
|
||||
| Current | Proposed | Rationale |
|
||||
|---------|----------|-----------|
|
||||
| `Run()` | `ShowModal()` or `Run()` | Emphasizes modal nature, or keep Run |
|
||||
| `RunState` | `ToplevelHandle` | It's a handle/token for the execution |
|
||||
| `Begin()` | `Activate()` | Activates the Toplevel for display |
|
||||
| `RunLoop()` | `EventLoop()` | Standard terminology |
|
||||
| `RunIteration()` | `ProcessEvents()` | Processes one iteration of events |
|
||||
| `End()` | `Deactivate()` | Deactivates the Toplevel |
|
||||
| `RequestStop()` | `Close()` or `RequestStop()` | Familiar to GUI developers |
|
||||
| `EndAfterFirstIteration` | `SingleIteration` | Mode rather than action |
|
||||
**Option A: `RunToken`**
|
||||
```csharp
|
||||
RunToken token = Application.Begin(toplevel);
|
||||
Application.RunLoop(token);
|
||||
Application.End(token);
|
||||
```
|
||||
- ✅ Clear it's a token, not state data
|
||||
- ✅ Concise (not wordy)
|
||||
- ✅ Industry standard pattern (CancellationToken, etc.)
|
||||
|
||||
**Usage Example:**
|
||||
**Option B: `ExecutionContext`**
|
||||
```csharp
|
||||
ExecutionContext context = Application.Begin(toplevel);
|
||||
Application.RunLoop(context);
|
||||
Application.End(context);
|
||||
```
|
||||
- ✅ Accurately describes bounded execution scope
|
||||
- ✅ Familiar from .NET (HttpContext, DbContext)
|
||||
- ⚠️ Slightly longer
|
||||
|
||||
**Option C: Keep `RunState` but clarify in docs**
|
||||
- ⚠️ Name remains misleading even with good documentation
|
||||
|
||||
### Problem 2: `EndAfterFirstIteration` Confuses "End" with Loop Control
|
||||
|
||||
**Current:**
|
||||
```csharp
|
||||
Application.EndAfterFirstIteration = true; // Controls RunLoop, not End()
|
||||
RunState rs = Application.Begin(window);
|
||||
Application.RunLoop(rs); // Stops after 1 iteration due to flag
|
||||
Application.End(rs); // This is actual "End"
|
||||
```
|
||||
|
||||
**Issue:**
|
||||
- "End" in the flag name suggests the `End()` method, but it actually controls `RunLoop()`
|
||||
- The flag stops the loop, not the lifecycle
|
||||
- Creates confusion about when `End()` gets called
|
||||
|
||||
**Proposed Options:**
|
||||
|
||||
**Option A: `StopAfterFirstIteration`**
|
||||
```csharp
|
||||
Application.StopAfterFirstIteration = true;
|
||||
```
|
||||
- ✅ "Stop" aligns with `RequestStop` which also affects the loop
|
||||
- ✅ Clearly about loop control, not lifecycle end
|
||||
- ✅ Minimal change
|
||||
|
||||
**Option B: `SingleIteration`**
|
||||
```csharp
|
||||
Application.SingleIteration = true;
|
||||
```
|
||||
- ✅ Shorter, positive framing
|
||||
- ✅ Describes the mode, not the action
|
||||
- ⚠️ Less obvious it's about stopping
|
||||
|
||||
**Option C: `RunLoopOnce`**
|
||||
```csharp
|
||||
Application.RunLoopOnce = true;
|
||||
```
|
||||
- ✅ Very explicit about what happens
|
||||
- ⚠️ Slightly awkward phrasing
|
||||
|
||||
### Problem 3: "Run" Overload (Lower Priority)
|
||||
|
||||
**Current:**
|
||||
```csharp
|
||||
Application.Run(window); // Complete lifecycle
|
||||
Application.RunLoop(state); // Starts the driver's mainloop
|
||||
Application.RunIteration(state); // One iteration
|
||||
```
|
||||
|
||||
**Issue:** Three different APIs with "Run" in the name doing different things at different levels.
|
||||
|
||||
**Note:** @tig's feedback indicates the distinction between `RunLoop` and `RunIteration` is important and understood. The "Run" prefix may not be a critical issue if the distinction is clear.
|
||||
|
||||
**Possible future consideration (not recommended now):**
|
||||
- Document the distinction more clearly
|
||||
- Keep names as-is since they work with understanding
|
||||
|
||||
## Recommended Changes
|
||||
|
||||
### Minimal Impact Recommendation
|
||||
|
||||
Change only what's most confusing:
|
||||
|
||||
1. **`RunState` → `RunToken`** (or `ExecutionContext`)
|
||||
- Clear it's a token/handle
|
||||
- Less ambiguous than "state"
|
||||
- Concise
|
||||
|
||||
2. **`EndAfterFirstIteration` → `StopAfterFirstIteration`**
|
||||
- Aligns with `RequestStop` terminology
|
||||
- Clearly about loop control
|
||||
- Minimal change
|
||||
|
||||
3. **Keep everything else:**
|
||||
- `Begin` / `End` - Perfect as-is
|
||||
- `RequestStop` - Clear non-blocking signal
|
||||
- `RunLoop` / `RunIteration` - Distinction is valuable
|
||||
- `Run()` - Familiar high-level API
|
||||
|
||||
### Usage Comparison
|
||||
|
||||
**Current (Confusing):**
|
||||
```csharp
|
||||
// High-level
|
||||
Application.ShowModal(myWindow);
|
||||
Application.Run(window);
|
||||
|
||||
// Low-level
|
||||
ToplevelHandle handle = Application.Activate(myWindow);
|
||||
while (!stopped)
|
||||
Application.ProcessEvents(handle);
|
||||
Application.Deactivate(handle);
|
||||
Application.EndAfterFirstIteration = true;
|
||||
RunState rs = Application.Begin(window);
|
||||
Application.RunLoop(rs);
|
||||
Application.End(rs);
|
||||
```
|
||||
|
||||
### Option 3: Lifecycle Terminology
|
||||
|
||||
This option uses explicit lifecycle phases.
|
||||
|
||||
| Current | Proposed | Rationale |
|
||||
|---------|----------|-----------|
|
||||
| `Run()` | `Run()` | Keep for compatibility |
|
||||
| `RunState` | `ExecutionContext` | It's a context for execution |
|
||||
| `Begin()` | `Start()` | Lifecycle: Start → Execute → Stop |
|
||||
| `RunLoop()` | `Execute()` | The execution phase |
|
||||
| `RunIteration()` | `Tick()` | Common game/event loop term |
|
||||
| `End()` | `Stop()` | Lifecycle: Start → Execute → Stop |
|
||||
| `RequestStop()` | `RequestStop()` | Keep, it's clear |
|
||||
| `EndAfterFirstIteration` | `StopAfterFirstTick` | Consistent with Tick |
|
||||
|
||||
**Usage Example:**
|
||||
**Proposed (Clearer):**
|
||||
```csharp
|
||||
// High-level (unchanged)
|
||||
Application.Run(myWindow);
|
||||
Application.Run(window);
|
||||
|
||||
// Low-level
|
||||
ExecutionContext context = Application.Start(myWindow);
|
||||
Application.Execute(context);
|
||||
Application.Stop(context);
|
||||
// Low-level (clearer)
|
||||
Application.StopAfterFirstIteration = true;
|
||||
RunToken token = Application.Begin(window);
|
||||
Application.RunLoop(token);
|
||||
Application.End(token);
|
||||
```
|
||||
|
||||
## Recommendation: Option 1 (Session-Based)
|
||||
## Understanding RunLoop vs RunIteration
|
||||
|
||||
**Recommended choice:** Option 1 - Session-Based Terminology
|
||||
It's important to preserve the distinction:
|
||||
|
||||
**Reasons:**
|
||||
- **`RunLoop(token)`** - Starts the driver's MainLoop and runs until stopped
|
||||
- This is a blocking call that manages the loop
|
||||
- Calls `RunIteration` repeatedly
|
||||
- Returns when `RequestStop()` is called or `StopAfterFirstIteration` is true
|
||||
|
||||
1. **Accuracy** - "Session" accurately describes what's happening: a bounded period of execution for a Toplevel
|
||||
2. **Clarity** - "BeginSession/EndSession" are unambiguous pairs
|
||||
3. **ProcessEvents** - Clearly communicates what the loop does
|
||||
4. **Minimal conceptual shift** - The pattern is still Begin/Loop/End, just clearer
|
||||
5. **Extensibility** - "Session" can encompass future session-related features
|
||||
- **`RunIteration(ref token)`** - Processes ONE iteration
|
||||
- Processes pending driver events
|
||||
- Does layout if needed
|
||||
- Draws if needed
|
||||
- Returns immediately
|
||||
|
||||
**Migration Strategy:**
|
||||
**Visual:**
|
||||
```
|
||||
RunLoop(token):
|
||||
┌─────────────────────┐
|
||||
│ while (Running) │
|
||||
│ RunIteration() │ ← One call
|
||||
│ RunIteration() │ ← Another call
|
||||
│ RunIteration() │ ← Another call
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
1. **Phase 1: Add new APIs with Obsolete attributes on old ones**
|
||||
```csharp
|
||||
[Obsolete("Use BeginSession instead")]
|
||||
public static RunState Begin(Toplevel toplevel)
|
||||
|
||||
public static ToplevelSession BeginSession(Toplevel toplevel)
|
||||
```
|
||||
This distinction is valuable and should be preserved.
|
||||
|
||||
2. **Phase 2: Update documentation to use new terminology**
|
||||
3. **Phase 3: Update examples to use new APIs**
|
||||
4. **Phase 4: After 2-3 releases, consider removing obsolete APIs**
|
||||
## Migration Strategy
|
||||
|
||||
## Alternative Names Considered
|
||||
### Phase 1: Add New Names with Obsolete Attributes
|
||||
|
||||
### For RunState/ToplevelSession
|
||||
- `ToplevelToken` - Too focused on the token aspect
|
||||
- `ToplevelHandle` - C/Win32 feel, less modern
|
||||
- `ExecutionSession` - Too generic
|
||||
- `ToplevelContext` - Could work, but "context" is overloaded in .NET
|
||||
- `ToplevelExecution` - Sounds like a verb, not a noun
|
||||
```csharp
|
||||
// Add new type
|
||||
public class RunToken { ... }
|
||||
|
||||
### For Begin/BeginSession
|
||||
- `StartSession` - Could work, but Begin/End is a common .NET pattern
|
||||
- `OpenSession` - Open/Close works but less common for this use
|
||||
- `InitializeSession` - Too long
|
||||
// Add conversion from old to new
|
||||
public static implicit operator RunToken(RunState state) => new RunToken(state.Toplevel);
|
||||
|
||||
### For RunLoop/ProcessEvents
|
||||
- `EventLoop` - Good, but sounds like a noun not a verb
|
||||
- `PumpEvents` - Win32 terminology, might work
|
||||
- `HandleEvents` - Similar to ProcessEvents
|
||||
- `MainLoop` - Confusing with MainLoop class
|
||||
// Mark old type obsolete
|
||||
[Obsolete("Use RunToken instead. RunState will be removed in a future version.")]
|
||||
public class RunState { ... }
|
||||
|
||||
### For End/EndSession
|
||||
- `CloseSession` - Could work with OpenSession
|
||||
- `FinishSession` - Less common
|
||||
- `TerminateSession` - Too harsh/formal
|
||||
// Add new property
|
||||
public static bool StopAfterFirstIteration { get; set; }
|
||||
|
||||
## Documentation Changes Required
|
||||
// Mark old property obsolete
|
||||
[Obsolete("Use StopAfterFirstIteration instead.")]
|
||||
public static bool EndAfterFirstIteration
|
||||
{
|
||||
get => StopAfterFirstIteration;
|
||||
set => StopAfterFirstIteration = value;
|
||||
}
|
||||
```
|
||||
|
||||
1. **API Documentation**
|
||||
- Update XML docs for all affected methods
|
||||
- Add clear examples showing lifecycle
|
||||
- Document the relationship between high-level `Run()` and low-level session APIs
|
||||
### Phase 2: Update Documentation
|
||||
|
||||
2. **Conceptual Documentation**
|
||||
- Create "Application Lifecycle" documentation page
|
||||
- Add diagrams showing the flow
|
||||
- Explain when to use `Run()` vs. low-level APIs
|
||||
- Update all docs to use new terminology
|
||||
- Add migration guide
|
||||
- Explain the distinction between RunLoop and RunIteration
|
||||
|
||||
3. **Migration Guide**
|
||||
- Create mapping table (old → new)
|
||||
- Provide before/after code examples
|
||||
- Explain the rationale for changes
|
||||
### Phase 3: Update Examples
|
||||
|
||||
## Implementation Notes
|
||||
- Examples use new APIs
|
||||
- Keep old examples in "legacy" section temporarily
|
||||
|
||||
### Backward Compatibility
|
||||
### Phase 4: Future Removal (Multiple Releases Later)
|
||||
|
||||
- All existing APIs remain functional
|
||||
- Mark old APIs with `[Obsolete]` attributes
|
||||
- Provide clear upgrade path in obsolete messages
|
||||
- Consider keeping old APIs indefinitely with internal delegation to new ones
|
||||
- After sufficient adoption period, consider removing obsolete APIs
|
||||
- Or keep them indefinitely with internal delegation
|
||||
|
||||
### Internal Implementation
|
||||
## Alternative Naming Options
|
||||
|
||||
- New APIs can delegate to existing implementation
|
||||
- Gradually refactor internals to use new terminology
|
||||
- Update variable names and comments to use new terms
|
||||
### For RunState/RunToken
|
||||
|
||||
### Testing
|
||||
| Option | Pros | Cons | Recommendation |
|
||||
|--------|------|------|----------------|
|
||||
| `RunToken` | Clear it's a token, concise | New terminology | ⭐ Best |
|
||||
| `ExecutionContext` | Industry standard | Slightly longer | Good alternative |
|
||||
| `RunHandle` | Clear it's a handle | "Handle" sounds Win32-ish | Acceptable |
|
||||
| `RunContext` | Familiar pattern | "Context" overloaded in .NET | OK |
|
||||
| Keep `RunState` | No change needed | Remains misleading | Not recommended |
|
||||
|
||||
- Keep all existing tests working
|
||||
- Add new tests using new terminology
|
||||
- Test obsolete warnings work correctly
|
||||
### For EndAfterFirstIteration
|
||||
|
||||
| Option | Pros | Cons | Recommendation |
|
||||
|--------|------|------|----------------|
|
||||
| `StopAfterFirstIteration` | Aligns with RequestStop | Slightly longer | ⭐ Best |
|
||||
| `SingleIteration` | Shorter | Less obvious meaning | Good alternative |
|
||||
| `RunLoopOnce` | Very explicit | Awkward phrasing | OK |
|
||||
| Keep `EndAfterFirstIteration` | No change | Continues confusion | Not recommended |
|
||||
|
||||
## Comparison with Other Frameworks
|
||||
|
||||
| Framework | Show View | Modal | Event Loop | Close |
|
||||
|-----------|-----------|-------|------------|-------|
|
||||
| **WPF** | `Show()` | `ShowDialog()` | `Dispatcher.Run()` | `Close()` |
|
||||
| **WinForms** | `Show()` | `ShowDialog()` | `Application.Run()` | `Close()` |
|
||||
| **Avalonia** | `Show()` | `ShowDialog()` | `Start()` | `Close()` |
|
||||
| **GTK** | `show()` | `run()` | `main()` | `close()` |
|
||||
| **Terminal.Gui v2 (current)** | `Run()` | `Run()` | `RunLoop()` | `RequestStop()` |
|
||||
| **Terminal.Gui v2 (proposed)** | `Run()` | `Run()` | `ProcessEvents()` | `StopProcessingEvents()` |
|
||||
**Token/Context Pattern:**
|
||||
- .NET: `CancellationToken` - token for cancellation scope
|
||||
- ASP.NET: `HttpContext` - context for HTTP request
|
||||
- Entity Framework: `DbContext` - context for database session
|
||||
- **Terminal.Gui:** `RunToken` (proposed) - token for execution scope
|
||||
|
||||
**Loop Control Flags:**
|
||||
- WinForms: `Application.Exit()` - stops message loop
|
||||
- WPF: `Dispatcher.InvokeShutdown()` - stops dispatcher
|
||||
- **Terminal.Gui:** `RequestStop()` (keep), `StopAfterFirstIteration` (proposed)
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Why not just keep "Run"?**
|
||||
A: "Run" is too overloaded. It doesn't distinguish between the complete lifecycle and the event loop, leading to confusion about what `RunLoop`, `RunState`, and `RunIteration` mean.
|
||||
**Q: Why not change `Begin` and `End` to `BeginSession` and `EndSession`?**
|
||||
|
||||
**Q: Why "Session" instead of "Context" or "Handle"?**
|
||||
A: "Session" best captures the bounded execution period. "Context" is overloaded in .NET (DbContext, HttpContext, etc.). "Handle" is too low-level and platform-specific.
|
||||
A: Per maintainer feedback, "Session" makes the names wordy without adding clarity. `Begin` and `End` are clear, concise, and work well as a lifecycle pair.
|
||||
|
||||
**Q: What about breaking existing code?**
|
||||
A: We maintain complete backward compatibility by keeping old APIs and using `[Obsolete]` attributes. Users can migrate at their own pace.
|
||||
**Q: Why keep `RunLoop`?**
|
||||
|
||||
A: The distinction between `RunLoop` (starts the driver's mainloop) and `RunIteration` (one iteration) is important and well-understood. The "Run" prefix is not the primary source of confusion.
|
||||
|
||||
**Q: Why change `RunState`?**
|
||||
|
||||
A: "State" implies the object holds state/data about the run. In reality, it's a token/handle for the Begin/End pairing. Calling it a "Token" or "Context" is more accurate.
|
||||
|
||||
**Q: Why change `EndAfterFirstIteration`?**
|
||||
|
||||
A: "End" in the flag name creates confusion with the `End()` method. The flag controls loop behavior, not lifecycle cleanup. "Stop" aligns better with `RequestStop` which also affects the loop.
|
||||
|
||||
**Q: Is this bikeshedding?**
|
||||
A: No. Clear terminology is essential for framework usability. The current confusion around "Run" causes real problems for users learning the framework.
|
||||
|
||||
**Q: Why not align exactly with WPF/WinForms?**
|
||||
A: Terminal.Gui has a different model - it exposes the event loop explicitly, which WPF/WinForms don't. We need terminology that fits our model while learning from established patterns.
|
||||
A: No. These specific names (`RunState`, `EndAfterFirstIteration`) cause real confusion. The changes are minimal, focused, and address documented pain points while preserving what works.
|
||||
|
||||
## Conclusion
|
||||
## Summary
|
||||
|
||||
The proposed Session-Based terminology clarifies the Application execution lifecycle while maintaining backward compatibility. The new names are:
|
||||
**Recommended Changes (Minimal Impact):**
|
||||
|
||||
- **More descriptive** - `ToplevelSession` vs `RunState`, `ProcessEvents` vs `RunLoop`
|
||||
- **More consistent** - `BeginSession`/`EndSession` pair, `ProcessEvents`/`StopProcessingEvents` pair
|
||||
- **More familiar** - Aligns with common patterns while respecting Terminal.Gui's unique architecture
|
||||
- **More maintainable** - Clear naming reduces cognitive load for contributors
|
||||
1. `RunState` → `RunToken`
|
||||
2. `EndAfterFirstIteration` → `StopAfterFirstIteration`
|
||||
|
||||
The migration path is straightforward, with minimal disruption to existing users.
|
||||
**Keep Unchanged:**
|
||||
- `Begin` / `End` - Clear and concise
|
||||
- `RequestStop` - Appropriately conveys non-blocking
|
||||
- `RunLoop` / `RunIteration` - Distinction is valuable
|
||||
- `Run()` - Familiar high-level API
|
||||
|
||||
---
|
||||
**Benefits:**
|
||||
- ✅ Eliminates the two primary sources of confusion
|
||||
- ✅ Maintains clarity of successful patterns
|
||||
- ✅ Minimal disruption (2 names only)
|
||||
- ✅ Complete backward compatibility via obsolete attributes
|
||||
- ✅ Respects maintainer feedback
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Community Feedback** - Gather feedback on this proposal from maintainers and community
|
||||
2. **Refinement** - Adjust terminology based on feedback
|
||||
3. **Implementation Plan** - Create detailed implementation plan with milestones
|
||||
4. **Documentation** - Prepare comprehensive documentation updates
|
||||
5. **Migration** - Implement changes with proper obsolete warnings and guidance
|
||||
This focused approach addresses real problems without over-engineering the solution.
|
||||
|
||||
@@ -1,258 +1,202 @@
|
||||
# Application Run Terminology - Quick Reference
|
||||
# Application.Run Terminology - Quick Reference
|
||||
|
||||
## Current State (Confusing)
|
||||
## The Problem
|
||||
|
||||
```
|
||||
Application.Run(toplevel)
|
||||
├─ Application.Begin(toplevel) → RunState
|
||||
├─ Application.RunLoop(RunState)
|
||||
│ └─ Application.RunIteration()
|
||||
└─ Application.End(RunState)
|
||||
```
|
||||
Current terminology has two specific issues:
|
||||
|
||||
**Problems:**
|
||||
- "Run" means too many things (lifecycle, loop, method names)
|
||||
- "RunState" sounds like state data, but it's a token
|
||||
- "Begin/End" - begin/end what?
|
||||
- "RunLoop" vs "RunIteration" - relationship unclear
|
||||
1. **`RunState`** sounds like state data, but it's actually a token/handle
|
||||
2. **`EndAfterFirstIteration`** uses "End" but controls loop behavior, not lifecycle
|
||||
|
||||
## Proposed (Clear) - Option 1: Session-Based ⭐
|
||||
## Recommended Solution
|
||||
|
||||
```
|
||||
Application.Run(toplevel) // High-level API (unchanged)
|
||||
├─ Application.BeginSession(toplevel) → ToplevelSession
|
||||
├─ Application.ProcessEvents(ToplevelSession)
|
||||
│ └─ Application.ProcessEventsIteration()
|
||||
└─ Application.EndSession(ToplevelSession)
|
||||
```
|
||||
### Minimal Changes
|
||||
|
||||
**Benefits:**
|
||||
- "Session" clearly indicates bounded execution period
|
||||
- "ProcessEvents" describes what the loop does
|
||||
- "BeginSession/EndSession" are unambiguous pairs
|
||||
- "ToplevelSession" clearly indicates a session token
|
||||
| Current | Proposed | Why |
|
||||
|---------|----------|-----|
|
||||
| `RunState` | `RunToken` | Clear it's a token, not state data |
|
||||
| `EndAfterFirstIteration` | `StopAfterFirstIteration` | "Stop" aligns with `RequestStop`, clearly about loop control |
|
||||
|
||||
## Proposed (Clear) - Option 2: Modal/Show
|
||||
### Keep Unchanged
|
||||
|
||||
```
|
||||
Application.ShowModal(toplevel) // or keep Run()
|
||||
├─ Application.Activate(toplevel) → ToplevelHandle
|
||||
├─ Application.EventLoop(ToplevelHandle)
|
||||
│ └─ Application.ProcessEvents()
|
||||
└─ Application.Deactivate(ToplevelHandle)
|
||||
```
|
||||
| API | Why It Works |
|
||||
|-----|--------------|
|
||||
| `Begin` / `End` | Clear, concise lifecycle pairing |
|
||||
| `RequestStop` | "Request" appropriately conveys non-blocking |
|
||||
| `RunLoop` / `RunIteration` | Distinction is important: RunLoop starts the driver's mainloop, RunIteration processes one iteration |
|
||||
|
||||
**Benefits:**
|
||||
- Aligns with WPF/WinForms patterns
|
||||
- "Activate/Deactivate" are familiar GUI concepts
|
||||
- "EventLoop" is industry standard terminology
|
||||
|
||||
## Proposed (Clear) - Option 3: Lifecycle
|
||||
|
||||
```
|
||||
Application.Run(toplevel)
|
||||
├─ Application.Start(toplevel) → ExecutionContext
|
||||
├─ Application.Execute(ExecutionContext)
|
||||
│ └─ Application.Tick()
|
||||
└─ Application.Stop(ExecutionContext)
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Explicit lifecycle phases (Start → Execute → Stop)
|
||||
- "Tick" is familiar from game development
|
||||
- Simple, clear verbs
|
||||
|
||||
## Side-by-Side Comparison
|
||||
|
||||
| Concept | Current | Option 1 (Session) ⭐ | Option 2 (Modal) | Option 3 (Lifecycle) |
|
||||
|---------|---------|---------------------|------------------|---------------------|
|
||||
| Complete lifecycle | `Run()` | `Run()` | `ShowModal()` or `Run()` | `Run()` |
|
||||
| Session token | `RunState` | `ToplevelSession` | `ToplevelHandle` | `ExecutionContext` |
|
||||
| Initialize | `Begin()` | `BeginSession()` | `Activate()` | `Start()` |
|
||||
| Event loop | `RunLoop()` | `ProcessEvents()` | `EventLoop()` | `Execute()` |
|
||||
| One iteration | `RunIteration()` | `ProcessEventsIteration()` | `ProcessEvents()` | `Tick()` |
|
||||
| Cleanup | `End()` | `EndSession()` | `Deactivate()` | `Stop()` |
|
||||
| Stop loop | `RequestStop()` | `StopProcessingEvents()` | `Close()` or `RequestStop()` | `RequestStop()` |
|
||||
| Stop mode flag | `EndAfterFirstIteration` | `StopAfterFirstIteration` | `SingleIteration` | `StopAfterFirstTick` |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### High-Level (All Options - Unchanged)
|
||||
|
||||
```csharp
|
||||
// Simple case - most users use this
|
||||
Application.Init();
|
||||
Application.Run(myWindow);
|
||||
Application.Shutdown();
|
||||
```
|
||||
|
||||
### Low-Level - Current (Confusing)
|
||||
|
||||
```csharp
|
||||
Application.Init();
|
||||
|
||||
RunState runState = Application.Begin(myWindow); // Begin what?
|
||||
Application.RunLoop(runState); // Run vs RunLoop?
|
||||
Application.End(runState); // End what?
|
||||
|
||||
Application.Shutdown();
|
||||
```
|
||||
|
||||
### Low-Level - Option 1: Session-Based ⭐
|
||||
|
||||
```csharp
|
||||
Application.Init();
|
||||
|
||||
ToplevelSession session = Application.BeginSession(myWindow); // Clear: starting a session
|
||||
Application.ProcessEvents(session); // Clear: processing events
|
||||
Application.EndSession(session); // Clear: ending the session
|
||||
|
||||
Application.Shutdown();
|
||||
```
|
||||
|
||||
### Low-Level - Option 2: Modal/Show
|
||||
|
||||
```csharp
|
||||
Application.Init();
|
||||
|
||||
ToplevelHandle handle = Application.Activate(myWindow); // Clear: activating for display
|
||||
Application.EventLoop(handle); // Clear: running event loop
|
||||
Application.Deactivate(handle); // Clear: deactivating
|
||||
|
||||
Application.Shutdown();
|
||||
```
|
||||
|
||||
### Low-Level - Option 3: Lifecycle
|
||||
|
||||
```csharp
|
||||
Application.Init();
|
||||
|
||||
ExecutionContext context = Application.Start(myWindow); // Clear: starting execution
|
||||
Application.Execute(context); // Clear: executing
|
||||
Application.Stop(context); // Clear: stopping
|
||||
|
||||
Application.Shutdown();
|
||||
```
|
||||
|
||||
## Manual Event Loop Control
|
||||
## Usage Comparison
|
||||
|
||||
### Current (Confusing)
|
||||
|
||||
```csharp
|
||||
RunState rs = Application.Begin(myWindow);
|
||||
Application.EndAfterFirstIteration = true;
|
||||
|
||||
while (!done)
|
||||
{
|
||||
Application.RunIteration(ref rs, firstIteration); // What's RunIteration vs RunLoop?
|
||||
firstIteration = false;
|
||||
// Do custom processing...
|
||||
}
|
||||
|
||||
// What is RunState? State data or a handle?
|
||||
RunState rs = Application.Begin(window);
|
||||
Application.RunLoop(rs);
|
||||
Application.End(rs);
|
||||
|
||||
// Does this call End()? No, it controls RunLoop()
|
||||
Application.EndAfterFirstIteration = true;
|
||||
```
|
||||
|
||||
### Option 1: Session-Based (Clear) ⭐
|
||||
### Proposed (Clear)
|
||||
|
||||
```csharp
|
||||
ToplevelSession session = Application.BeginSession(myWindow);
|
||||
// Clearly a token, not state data
|
||||
RunToken token = Application.Begin(window);
|
||||
Application.RunLoop(token);
|
||||
Application.End(token);
|
||||
|
||||
// Clearly controls loop stopping, aligns with RequestStop
|
||||
Application.StopAfterFirstIteration = true;
|
||||
|
||||
while (!done)
|
||||
{
|
||||
Application.ProcessEventsIteration(ref session, firstIteration); // Clear: process one iteration
|
||||
firstIteration = false;
|
||||
// Do custom processing...
|
||||
}
|
||||
|
||||
Application.EndSession(session);
|
||||
```
|
||||
|
||||
### Option 2: Modal/Show (Clear)
|
||||
## Understanding RunLoop vs RunIteration
|
||||
|
||||
**Important distinction to preserve:**
|
||||
|
||||
```
|
||||
RunLoop(token): RunIteration(token):
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Starts driver's │ │ Processes ONE │
|
||||
│ MainLoop │ │ iteration: │
|
||||
│ │ │ - Events │
|
||||
│ Loops calling: │ │ - Layout │
|
||||
│ RunIteration() │ │ - Draw │
|
||||
│ RunIteration() │ │ │
|
||||
│ ... │ │ Returns │
|
||||
│ │ │ immediately │
|
||||
│ Until stopped │ │ │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
This distinction is valuable and should be kept.
|
||||
|
||||
## Complete API Overview
|
||||
|
||||
```
|
||||
Application.Run(window) ← High-level: complete lifecycle
|
||||
├─ Application.Begin(window) → RunToken
|
||||
│ └─ Initialize, layout, draw
|
||||
├─ Application.RunLoop(token)
|
||||
│ └─ Loop: while(running) { RunIteration() }
|
||||
└─ Application.End(token)
|
||||
└─ Cleanup
|
||||
|
||||
Application.RunIteration(ref token) ← Low-level: one iteration
|
||||
|
||||
Application.RequestStop() ← Signal loop to stop
|
||||
Application.StopAfterFirstIteration ← Mode: stop after 1 iteration
|
||||
```
|
||||
|
||||
## Alternative Options Considered
|
||||
|
||||
### For RunState
|
||||
|
||||
| Option | Pros | Cons |
|
||||
|--------|------|------|
|
||||
| **RunToken** ⭐ | Clear, concise | New term |
|
||||
| ExecutionContext | Industry standard | Longer |
|
||||
| RunHandle | Clear | Win32-ish |
|
||||
|
||||
### For EndAfterFirstIteration
|
||||
|
||||
| Option | Pros | Cons |
|
||||
|--------|------|------|
|
||||
| **StopAfterFirstIteration** ⭐ | Aligns with RequestStop | Slightly longer |
|
||||
| SingleIteration | Shorter | Less obvious |
|
||||
| RunLoopOnce | Explicit | Awkward |
|
||||
|
||||
## Migration Example
|
||||
|
||||
### Backward Compatible Migration
|
||||
|
||||
```csharp
|
||||
ToplevelHandle handle = Application.Activate(myWindow);
|
||||
Application.SingleIteration = true;
|
||||
// Old code continues to work with obsolete warnings
|
||||
[Obsolete("Use RunToken instead")]
|
||||
public class RunState { ... }
|
||||
|
||||
while (!done)
|
||||
{
|
||||
Application.ProcessEvents(ref handle, firstIteration); // Clear: process events
|
||||
firstIteration = false;
|
||||
// Do custom processing...
|
||||
[Obsolete("Use StopAfterFirstIteration instead")]
|
||||
public static bool EndAfterFirstIteration
|
||||
{
|
||||
get => StopAfterFirstIteration;
|
||||
set => StopAfterFirstIteration = value;
|
||||
}
|
||||
|
||||
Application.Deactivate(handle);
|
||||
// New code uses clearer names
|
||||
public class RunToken { ... }
|
||||
public static bool StopAfterFirstIteration { get; set; }
|
||||
```
|
||||
|
||||
### Option 3: Lifecycle (Clear)
|
||||
### User Migration
|
||||
|
||||
```csharp
|
||||
ExecutionContext context = Application.Start(myWindow);
|
||||
Application.StopAfterFirstTick = true;
|
||||
// Before
|
||||
RunState rs = Application.Begin(window);
|
||||
Application.EndAfterFirstIteration = true;
|
||||
Application.RunLoop(rs);
|
||||
Application.End(rs);
|
||||
|
||||
while (!done)
|
||||
{
|
||||
Application.Tick(ref context, firstIteration); // Clear: one tick
|
||||
firstIteration = false;
|
||||
// Do custom processing...
|
||||
}
|
||||
|
||||
Application.Stop(context);
|
||||
// After (simple find/replace)
|
||||
RunToken token = Application.Begin(window);
|
||||
Application.StopAfterFirstIteration = true;
|
||||
Application.RunLoop(token);
|
||||
Application.End(token);
|
||||
```
|
||||
|
||||
## Recommendation: Option 1 (Session-Based)
|
||||
## Why These Changes?
|
||||
|
||||
**Why Session-Based wins:**
|
||||
1. ✅ Most accurate - "session" perfectly describes bounded execution
|
||||
2. ✅ Least disruptive - keeps Begin/End pattern, just clarifies it
|
||||
3. ✅ Most descriptive - "ProcessEvents" is clearer than "RunLoop"
|
||||
4. ✅ Industry standard - "session" is widely understood in software
|
||||
5. ✅ Extensible - easy to add session-related features later
|
||||
### RunState → RunToken
|
||||
|
||||
**Implementation:**
|
||||
- Add new APIs alongside existing ones
|
||||
- Mark old APIs `[Obsolete]` with helpful messages
|
||||
- Update docs to use new terminology
|
||||
- Maintain backward compatibility indefinitely
|
||||
**Problem:** Users see "State" and think it holds state data. They ask:
|
||||
- "What state does it hold?"
|
||||
- "Can I query the state?"
|
||||
- "Is it like a state machine?"
|
||||
|
||||
## Related Concepts
|
||||
**Solution:** "Token" clearly indicates it's an identity/handle for Begin/End pairing, like `CancellationToken`.
|
||||
|
||||
### Application Lifecycle
|
||||
### EndAfterFirstIteration → StopAfterFirstIteration
|
||||
|
||||
```
|
||||
Application.Init() // Initialize the application
|
||||
├─ Create driver
|
||||
├─ Setup screen
|
||||
└─ Initialize subsystems
|
||||
**Problem:** Users see "End" and think of `End()` method. They ask:
|
||||
- "Does this call `End()`?"
|
||||
- "Why is it called 'End' when it controls the loop?"
|
||||
|
||||
Application.Run(toplevel) // Run a toplevel (modal)
|
||||
├─ BeginSession
|
||||
├─ ProcessEvents
|
||||
└─ EndSession
|
||||
**Solution:** "Stop" aligns with `RequestStop` and clearly indicates loop control, not lifecycle cleanup.
|
||||
|
||||
Application.Shutdown() // Shutdown the application
|
||||
├─ Cleanup resources
|
||||
└─ Restore terminal
|
||||
```
|
||||
## What We're NOT Changing
|
||||
|
||||
### Session vs Application Lifecycle
|
||||
### Begin / End
|
||||
|
||||
| Application Lifecycle | Session Lifecycle |
|
||||
|----------------------|-------------------|
|
||||
| `Init()` - Once per app | `BeginSession()` - Per toplevel |
|
||||
| `Run()` - Can have multiple | `ProcessEvents()` - Within one session |
|
||||
| `Shutdown()` - Once per app | `EndSession()` - Per toplevel |
|
||||
✅ **Keep as-is** - Clear, concise lifecycle pairing
|
||||
- Not wordy
|
||||
- Industry standard pattern (BeginInvoke/EndInvoke, etc.)
|
||||
- Works well
|
||||
|
||||
## Events and Notifications
|
||||
### RequestStop
|
||||
|
||||
| Current | Proposed (Option 1) |
|
||||
|---------|---------------------|
|
||||
| `NotifyNewRunState` | `NotifyNewSession` |
|
||||
| `NotifyStopRunState` | `NotifyStopSession` |
|
||||
| `RunStateEventArgs` | `ToplevelSessionEventArgs` |
|
||||
✅ **Keep as-is** - Appropriately conveys non-blocking nature
|
||||
- "Request" indicates it doesn't block
|
||||
- Clear about what it does
|
||||
- Works well
|
||||
|
||||
## See Also
|
||||
### RunLoop / RunIteration
|
||||
|
||||
- [Full Proposal Document](TERMINOLOGY_PROPOSAL.md) - Detailed rationale and analysis
|
||||
- [Migration Guide](docs/migration-guide.md) - How to update your code (TODO)
|
||||
- [API Reference](docfx/api/Terminal.Gui.App.Application.yml) - API documentation
|
||||
✅ **Keep as-is** - Distinction is important and understood
|
||||
- RunLoop = starts the driver's mainloop (blocking)
|
||||
- RunIteration = processes one iteration (immediate)
|
||||
- The distinction is valuable
|
||||
- "Run" prefix is OK when the difference is clear
|
||||
|
||||
## Summary
|
||||
|
||||
**Changes (2 names only):**
|
||||
- `RunState` → `RunToken`
|
||||
- `EndAfterFirstIteration` → `StopAfterFirstIteration`
|
||||
|
||||
**Benefits:**
|
||||
- ✅ Addresses the two primary sources of confusion
|
||||
- ✅ Minimal disruption
|
||||
- ✅ Backward compatible
|
||||
- ✅ Respects maintainer feedback
|
||||
- ✅ Preserves what works well
|
||||
|
||||
See [TERMINOLOGY_PROPOSAL.md](TERMINOLOGY_PROPOSAL.md) for detailed analysis.
|
||||
|
||||
@@ -1,254 +0,0 @@
|
||||
# Application.Run Terminology Proposal - README
|
||||
|
||||
This directory contains a comprehensive proposal for improving the terminology around `Application.Run` and related APIs in Terminal.Gui.
|
||||
|
||||
## 📋 Documents
|
||||
|
||||
### 1. [TERMINOLOGY_PROPOSAL.md](TERMINOLOGY_PROPOSAL.md)
|
||||
**Complete proposal with detailed analysis**
|
||||
|
||||
Contents:
|
||||
- Executive Summary
|
||||
- Problem Statement (why current terminology is confusing)
|
||||
- Current Terminology Analysis
|
||||
- Three proposed options with pros/cons
|
||||
- Recommendation: Option 1 (Session-Based)
|
||||
- Migration strategy
|
||||
- Documentation changes required
|
||||
- FAQ
|
||||
|
||||
**Start here** for the full context and rationale.
|
||||
|
||||
### 2. [TERMINOLOGY_QUICK_REFERENCE.md](TERMINOLOGY_QUICK_REFERENCE.md)
|
||||
**Quick comparison tables and code examples**
|
||||
|
||||
Contents:
|
||||
- Current vs Proposed (all 3 options)
|
||||
- Side-by-side comparison table
|
||||
- Usage examples for each option
|
||||
- Manual event loop control examples
|
||||
- High-level vs low-level API comparison
|
||||
|
||||
**Use this** for quick lookup and comparison.
|
||||
|
||||
### 3. [TERMINOLOGY_INDUSTRY_COMPARISON.md](TERMINOLOGY_INDUSTRY_COMPARISON.md)
|
||||
**How Terminal.Gui compares to other frameworks**
|
||||
|
||||
Contents:
|
||||
- Comparison with WPF, WinForms, Avalonia, GTK, Qt
|
||||
- Web framework patterns (ASP.NET, Entity Framework)
|
||||
- Game engine patterns (Unity, Unreal)
|
||||
- Industry standard terminology analysis
|
||||
- Why "Session" is the right choice
|
||||
|
||||
**Read this** to understand industry context.
|
||||
|
||||
### 4. [TERMINOLOGY_VISUAL_GUIDE.md](TERMINOLOGY_VISUAL_GUIDE.md)
|
||||
**Visual diagrams and flowcharts**
|
||||
|
||||
Contents:
|
||||
- Visual comparison of current vs proposed
|
||||
- Lifecycle diagrams
|
||||
- Event flow diagrams
|
||||
- Nested sessions (modal dialogs)
|
||||
- Complete example flows
|
||||
- Benefits visualization
|
||||
|
||||
**Use this** for visual learners and presentations.
|
||||
|
||||
## 🎯 The Problem
|
||||
|
||||
The current `Application.Run` terminology is confusing:
|
||||
|
||||
```csharp
|
||||
// What's the difference between these "Run" methods?
|
||||
Application.Run(window); // Complete lifecycle
|
||||
Application.RunLoop(runState); // Event loop
|
||||
Application.RunIteration(); // One iteration
|
||||
|
||||
// What is RunState? State or a handle?
|
||||
RunState runState = Application.Begin(window); // Begin what?
|
||||
|
||||
// What's ending?
|
||||
Application.End(runState); // End what?
|
||||
```
|
||||
|
||||
**Result:** Confused users, steeper learning curve, unclear documentation.
|
||||
|
||||
## ✅ The Solution
|
||||
|
||||
### Option 1: Session-Based Terminology (Recommended)
|
||||
|
||||
```csharp
|
||||
// High-level API (unchanged)
|
||||
Application.Run(window); // Simple and familiar
|
||||
|
||||
// Low-level API (clearer names)
|
||||
ToplevelSession session = Application.BeginSession(window); // ✅ Clear
|
||||
Application.ProcessEvents(session); // ✅ Clear
|
||||
Application.EndSession(session); // ✅ Clear
|
||||
```
|
||||
|
||||
**Why this wins:**
|
||||
- ✅ "Session" accurately describes bounded execution
|
||||
- ✅ "ProcessEvents" is explicit about what happens
|
||||
- ✅ "BeginSession/EndSession" are unambiguous
|
||||
- ✅ Aligns with industry patterns (HttpContext, DbContext)
|
||||
- ✅ Minimal disruption to existing API
|
||||
|
||||
### Complete Mapping
|
||||
|
||||
| Current | Proposed | Why |
|
||||
|---------|----------|-----|
|
||||
| `Run()` | `Run()` | Keep - familiar |
|
||||
| `RunState` | `ToplevelSession` | Clear it's a session token |
|
||||
| `Begin()` | `BeginSession()` | Clear what's beginning |
|
||||
| `RunLoop()` | `ProcessEvents()` | Describes the action |
|
||||
| `RunIteration()` | `ProcessEventsIteration()` | Consistent |
|
||||
| `End()` | `EndSession()` | Clear what's ending |
|
||||
| `RequestStop()` | `StopProcessingEvents()` | Explicit |
|
||||
|
||||
## 📊 Comparison Matrix
|
||||
|
||||
| Criterion | Current | Proposed (Option 1) |
|
||||
|-----------|---------|---------------------|
|
||||
| **Clarity** | ⚠️ "Run" overloaded | ✅ Each term is distinct |
|
||||
| **Accuracy** | ⚠️ "State" is misleading | ✅ "Session" is accurate |
|
||||
| **Learnability** | ⚠️ Steep curve | ✅ Self-documenting |
|
||||
| **Industry Alignment** | ⚠️ Unique terminology | ✅ Standard patterns |
|
||||
| **Breaking Changes** | N/A | ✅ None (old APIs kept) |
|
||||
|
||||
## 🚀 Migration Path
|
||||
|
||||
### Phase 1: Add New APIs (Release 1)
|
||||
```csharp
|
||||
// Add new APIs
|
||||
public static ToplevelSession BeginSession(Toplevel toplevel) { ... }
|
||||
|
||||
// Mark old APIs obsolete
|
||||
[Obsolete("Use BeginSession instead. See TERMINOLOGY_PROPOSAL.md")]
|
||||
public static RunState Begin(Toplevel toplevel) { ... }
|
||||
```
|
||||
|
||||
### Phase 2: Update Documentation (Release 1-2)
|
||||
- Update all docs to use new terminology
|
||||
- Add migration guide
|
||||
- Update examples
|
||||
|
||||
### Phase 3: Community Adoption (Release 2-4)
|
||||
- Examples use new APIs
|
||||
- Community feedback period
|
||||
- Adjust based on feedback
|
||||
|
||||
### Phase 4: Consider Removal (Release 5+)
|
||||
- After 2-3 releases, consider removing `[Obsolete]` APIs
|
||||
- Or keep them indefinitely with internal delegation
|
||||
|
||||
## 💡 Key Insights
|
||||
|
||||
### 1. High-Level API Unchanged
|
||||
Most users won't be affected:
|
||||
```csharp
|
||||
Application.Init();
|
||||
Application.Run(window); // Still works exactly the same
|
||||
Application.Shutdown();
|
||||
```
|
||||
|
||||
### 2. Low-Level API Clarified
|
||||
Advanced users get clearer APIs:
|
||||
```csharp
|
||||
// Before (confusing)
|
||||
var rs = Application.Begin(window);
|
||||
Application.RunLoop(rs);
|
||||
Application.End(rs);
|
||||
|
||||
// After (clear)
|
||||
var session = Application.BeginSession(window);
|
||||
Application.ProcessEvents(session);
|
||||
Application.EndSession(session);
|
||||
```
|
||||
|
||||
### 3. Complete Backward Compatibility
|
||||
```csharp
|
||||
// Old code continues to work
|
||||
RunState rs = Application.Begin(window); // Works, but obsolete warning
|
||||
Application.RunLoop(rs); // Works, but obsolete warning
|
||||
Application.End(rs); // Works, but obsolete warning
|
||||
```
|
||||
|
||||
## 📈 Benefits
|
||||
|
||||
### For Users
|
||||
- ✅ **Faster learning** - Self-documenting APIs
|
||||
- ✅ **Less confusion** - Clear, distinct names
|
||||
- ✅ **Better understanding** - Matches mental model
|
||||
|
||||
### For Maintainers
|
||||
- ✅ **Easier to explain** - Clear terminology in docs
|
||||
- ✅ **Fewer questions** - Users understand the pattern
|
||||
- ✅ **Better code** - Internal code can use clearer names
|
||||
|
||||
### For the Project
|
||||
- ✅ **Professional** - Aligns with industry standards
|
||||
- ✅ **Accessible** - Lower barrier to entry
|
||||
- ✅ **Maintainable** - Clearer code is easier to maintain
|
||||
|
||||
## 🤔 Alternatives Considered
|
||||
|
||||
### Option 2: Modal/Show Terminology
|
||||
```csharp
|
||||
Application.ShowModal(window);
|
||||
var handle = Application.Activate(window);
|
||||
Application.EventLoop(handle);
|
||||
Application.Deactivate(handle);
|
||||
```
|
||||
**Rejected:** Doesn't fit Terminal.Gui's model well.
|
||||
|
||||
### Option 3: Lifecycle Terminology
|
||||
```csharp
|
||||
var context = Application.Start(window);
|
||||
Application.Execute(context);
|
||||
Application.Stop(context);
|
||||
```
|
||||
**Rejected:** Breaks Begin/End pattern, "Execute" less explicit.
|
||||
|
||||
See [TERMINOLOGY_PROPOSAL.md](TERMINOLOGY_PROPOSAL.md) for full analysis.
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
### Terminal.Gui Documentation
|
||||
- [Application Class](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.Application.html)
|
||||
- [Multitasking Guide](docfx/docs/multitasking.md)
|
||||
|
||||
### Related Issues
|
||||
- Issue #4329 - Original discussion about Run terminology
|
||||
|
||||
## 🗳️ Community Feedback
|
||||
|
||||
We welcome feedback on this proposal:
|
||||
|
||||
1. **Preferred option?** Session-Based, Modal/Show, or Lifecycle?
|
||||
2. **Better names?** Suggest alternatives
|
||||
3. **Migration concerns?** Share your use cases
|
||||
4. **Timeline?** How long do you need to migrate?
|
||||
|
||||
## 📞 Contact
|
||||
|
||||
For questions or feedback:
|
||||
- Open an issue in the Terminal.Gui repository
|
||||
- Comment on the PR associated with this proposal
|
||||
- Join the discussion in the community forums
|
||||
|
||||
## 📄 License
|
||||
|
||||
This proposal is part of the Terminal.Gui project and follows the same license (MIT).
|
||||
|
||||
---
|
||||
|
||||
**Status:** 📝 Proposal (awaiting community feedback)
|
||||
|
||||
**Author:** GitHub Copilot (generated based on issue #4329)
|
||||
|
||||
**Date:** 2025-10-25
|
||||
|
||||
**Version:** 1.0
|
||||
@@ -1,438 +1,319 @@
|
||||
# Application.Run Terminology - Visual Guide
|
||||
|
||||
This document provides visual representations of the Application execution lifecycle to clarify the terminology.
|
||||
## The Two Problems
|
||||
|
||||
## Current Terminology (Confusing)
|
||||
### Problem 1: RunState Sounds Like State Data
|
||||
|
||||
### The Problem: "Run" Everywhere
|
||||
```
|
||||
Current (Confusing):
|
||||
┌─────────────────────────────────────┐
|
||||
│ RunState rs = Begin(window); │ ← "State"? What state does it hold?
|
||||
│ │
|
||||
│ Application.RunLoop(rs); │
|
||||
│ │
|
||||
│ Application.End(rs); │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
Users think: "What state information does RunState contain?"
|
||||
Reality: It's a token/handle for the Begin/End pairing
|
||||
|
||||
|
||||
Proposed (Clear):
|
||||
┌─────────────────────────────────────┐
|
||||
│ RunToken token = Begin(window); │ ✅ Clear: it's a token, not state
|
||||
│ │
|
||||
│ Application.RunLoop(token); │
|
||||
│ │
|
||||
│ Application.End(token); │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
Users understand: "It's a token for the Begin/End pairing"
|
||||
```
|
||||
|
||||
### Problem 2: EndAfterFirstIteration Confuses End() with Loop Control
|
||||
|
||||
```
|
||||
Current (Confusing):
|
||||
┌──────────────────────────────────────────┐
|
||||
│ EndAfterFirstIteration = true; │ ← "End"? Like End() method?
|
||||
│ │
|
||||
│ RunState rs = Begin(window); │
|
||||
│ │
|
||||
│ RunLoop(rs); // Stops after 1 iteration│
|
||||
│ │
|
||||
│ End(rs); // This is "End" │
|
||||
└──────────────────────────────────────────┘
|
||||
|
||||
Users think: "Does EndAfterFirstIteration call End()?"
|
||||
Reality: It controls RunLoop() behavior, not End()
|
||||
|
||||
|
||||
Proposed (Clear):
|
||||
┌──────────────────────────────────────────┐
|
||||
│ StopAfterFirstIteration = true; │ ✅ Clear: controls loop stopping
|
||||
│ │
|
||||
│ RunToken token = Begin(window); │
|
||||
│ │
|
||||
│ RunLoop(token); // Stops after 1 iter │
|
||||
│ │
|
||||
│ End(token); // Cleanup │
|
||||
└──────────────────────────────────────────┘
|
||||
|
||||
Users understand: "Stop controls the loop, End cleans up"
|
||||
```
|
||||
|
||||
## Understanding RunLoop vs RunIteration
|
||||
|
||||
**This distinction is valuable and should be preserved:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Application.Run() │ ← High-level API
|
||||
│ RunLoop(token) │
|
||||
│ │
|
||||
│ "Run" means the complete lifecycle │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────┐
|
||||
│ Application.Begin(toplevel) │ ← "Begin" what?
|
||||
│ │
|
||||
│ Returns: RunState │ ← Sounds like state data
|
||||
└─────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────┐
|
||||
│ Application.RunLoop(runState) │ ← "Run" again? Run vs RunLoop?
|
||||
│ │
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │ while (running) │ │
|
||||
│ │ RunIteration() │ │ ← "Run" again? What's the difference?
|
||||
│ │ ProcessInput() │ │
|
||||
│ │ Layout/Draw() │ │
|
||||
│ └───────────────────────────┘ │
|
||||
└─────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────┐
|
||||
│ Application.End(runState) │ ← "End" what?
|
||||
└─────────────────────────────────┘
|
||||
|
||||
Issues:
|
||||
❌ "Run" appears 4 times meaning different things
|
||||
❌ RunState sounds like state, but it's a token
|
||||
❌ Begin/End don't clarify what's beginning/ending
|
||||
❌ RunLoop vs RunIteration relationship unclear
|
||||
```
|
||||
|
||||
## Proposed Terminology - Option 1: Session-Based ⭐
|
||||
|
||||
### The Solution: Clear, Explicit Names
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Application.Run() │ ← High-level (unchanged)
|
||||
│ Starts the driver's MainLoop │
|
||||
│ Loops until stopped: │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────┐ │
|
||||
│ │ while (toplevel.Running) │ │
|
||||
│ │ { │ │
|
||||
│ │ RunIteration(ref token); ←──────────┐ │ │
|
||||
│ │ RunIteration(ref token); ←──────────┤ │ │
|
||||
│ │ RunIteration(ref token); ←──────────┤ │ │
|
||||
│ │ ... │ │ │
|
||||
│ │ } │ │ │
|
||||
│ └────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Complete lifecycle: Begin + ProcessEvents + End │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Application.BeginSession(toplevel) │ ✅ Clear: starting a session
|
||||
│ │
|
||||
│ Returns: ToplevelSession │ ✅ Clear: it's a session token
|
||||
└─────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Application.ProcessEvents(session) │ ✅ Clear: processing events
|
||||
│ │
|
||||
│ ┌──────────────────────────────┐ │
|
||||
│ │ while (running) │ │
|
||||
│ │ ProcessEventsIteration() │ │ ✅ Clear: one iteration of processing
|
||||
│ │ ProcessInput() │ │
|
||||
│ │ Layout/Draw() │ │
|
||||
│ └──────────────────────────────┘ │
|
||||
└─────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Application.EndSession(session) │ ✅ Clear: ending the session
|
||||
└─────────────────────────────────────┘
|
||||
│
|
||||
│
|
||||
┌─────────────▼───────────────┐
|
||||
│ RunIteration(ref token) │
|
||||
│ │
|
||||
│ Processes ONE iteration: │
|
||||
│ 1. Process driver events │
|
||||
│ 2. Layout (if needed) │
|
||||
│ 3. Draw (if needed) │
|
||||
│ │
|
||||
│ Returns immediately │
|
||||
└─────────────────────────────┘
|
||||
|
||||
Benefits:
|
||||
✅ "Session" clearly indicates bounded execution
|
||||
✅ "ProcessEvents" describes the action
|
||||
✅ BeginSession/EndSession are unambiguous
|
||||
✅ Terminology is consistent and clear
|
||||
Key Insight:
|
||||
- RunLoop = The LOOP itself (blocking, manages iterations)
|
||||
- RunIteration = ONE iteration (immediate, processes events)
|
||||
```
|
||||
|
||||
## Lifecycle Comparison
|
||||
|
||||
### Application Lifecycle (Init/Shutdown) vs Session Lifecycle (Begin/ProcessEvents/End)
|
||||
## Complete Lifecycle Visualization
|
||||
|
||||
```
|
||||
┌────────────────────────── Application Lifetime ──────────────────────────┐
|
||||
│ │
|
||||
│ Application.Init() ← Initialize once per application │
|
||||
│ ├─ Create driver │
|
||||
│ ├─ Initialize screen │
|
||||
│ └─ Setup subsystems │
|
||||
│ │
|
||||
│ ┌──────────────────────── Session 1 ────────────────────────┐ │
|
||||
│ │ Application.BeginSession(window1) → session1 │ │
|
||||
│ │ ├─ Initialize window1 │ │
|
||||
│ │ ├─ Layout window1 │ │
|
||||
│ │ └─ Draw window1 │ │
|
||||
│ │ │ │
|
||||
│ │ Application.ProcessEvents(session1) │ │
|
||||
│ │ └─ Event loop until RequestStop() │ │
|
||||
│ │ │ │
|
||||
│ │ Application.EndSession(session1) │ │
|
||||
│ │ └─ Cleanup window1 │ │
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────── Session 2 ────────────────────────┐ │
|
||||
│ │ Application.BeginSession(dialog) → session2 │ │
|
||||
│ │ Application.ProcessEvents(session2) │ │
|
||||
│ │ Application.EndSession(session2) │ │
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Application.Shutdown() ← Cleanup once per application │
|
||||
│ ├─ Dispose driver │
|
||||
│ └─ Restore terminal │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Key Insight: Multiple sessions within one application lifetime
|
||||
```
|
||||
|
||||
## Event Flow During ProcessEvents
|
||||
|
||||
### Current (Confusing)
|
||||
|
||||
```
|
||||
RunLoop(runState)
|
||||
│
|
||||
└─> while (toplevel.Running)
|
||||
│
|
||||
├─> RunIteration(runState) ← What's the difference?
|
||||
│ │
|
||||
│ ├─> MainLoop.RunIteration()
|
||||
│ │ └─> Process driver events
|
||||
│ │
|
||||
│ ├─> Layout (if needed)
|
||||
│ └─> Draw (if needed)
|
||||
│
|
||||
└─> (repeat)
|
||||
```
|
||||
|
||||
### Proposed (Clear)
|
||||
|
||||
```
|
||||
ProcessEvents(session)
|
||||
│
|
||||
└─> while (toplevel.Running)
|
||||
│
|
||||
├─> ProcessEventsIteration(session) ✅ Clear: one iteration of event processing
|
||||
│ │
|
||||
│ ├─> MainLoop.RunIteration()
|
||||
│ │ └─> Process driver events
|
||||
│ │
|
||||
│ ├─> Layout (if needed)
|
||||
│ └─> Draw (if needed)
|
||||
│
|
||||
└─> (repeat)
|
||||
Application.Run(window)
|
||||
┌───────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ 1. Begin(window) → RunToken │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ • Initialize window │ │
|
||||
│ │ • Layout views │ │
|
||||
│ │ • Draw to screen │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 2. RunLoop(token) │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ Start driver's MainLoop │ │
|
||||
│ │ │ │
|
||||
│ │ while (Running) { │ │
|
||||
│ │ RunIteration(ref token) │ │
|
||||
│ │ ├─ Process events │ │
|
||||
│ │ ├─ Layout (if needed) │ │
|
||||
│ │ └─ Draw (if needed) │ │
|
||||
│ │ } │ │
|
||||
│ │ │ │
|
||||
│ │ Exits when: │ │
|
||||
│ │ - RequestStop() called │ │
|
||||
│ │ - StopAfterFirstIteration=true │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 3. End(token) │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ • Cleanup window │ │
|
||||
│ │ • Dispose token │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Manual Control Pattern
|
||||
|
||||
When you need fine-grained control over the event loop:
|
||||
|
||||
### Current (Confusing)
|
||||
When you need fine-grained control:
|
||||
|
||||
```
|
||||
RunState rs = Begin(toplevel); ← Begin what?
|
||||
EndAfterFirstIteration = true; ← End what?
|
||||
┌────────────────────────────────────────────┐
|
||||
│ RunToken token = Begin(window); │
|
||||
│ StopAfterFirstIteration = true; │ ✅ Clear: stop after one iter
|
||||
│ │
|
||||
│ while (!myCondition) │
|
||||
│ { │
|
||||
│ // Process one iteration │
|
||||
│ RunIteration(ref token, first); │
|
||||
│ first = false; │
|
||||
│ │
|
||||
│ // Your custom logic here │
|
||||
│ DoCustomProcessing(); │
|
||||
│ } │
|
||||
│ │
|
||||
│ End(token); │
|
||||
└────────────────────────────────────────────┘
|
||||
|
||||
while (!done)
|
||||
{
|
||||
RunIteration(ref rs, first); ← Run what? How does this relate to RunLoop?
|
||||
first = false;
|
||||
|
||||
// Custom processing
|
||||
DoMyCustomStuff();
|
||||
}
|
||||
vs Old (Confusing):
|
||||
|
||||
End(rs); ← End what?
|
||||
```
|
||||
|
||||
### Proposed (Clear)
|
||||
|
||||
```
|
||||
ToplevelSession session = BeginSession(toplevel); ✅ Clear: starting a session
|
||||
StopAfterFirstIteration = true; ✅ Clear: stop after one iteration
|
||||
|
||||
while (!done)
|
||||
{
|
||||
ProcessEventsIteration(ref session, first); ✅ Clear: process one iteration
|
||||
first = false;
|
||||
|
||||
// Custom processing
|
||||
DoMyCustomStuff();
|
||||
}
|
||||
|
||||
EndSession(session); ✅ Clear: ending the session
|
||||
┌────────────────────────────────────────────┐
|
||||
│ RunState rs = Begin(window); │
|
||||
│ EndAfterFirstIteration = true; │ ❌ Confusing: sounds like End()
|
||||
│ │
|
||||
│ while (!myCondition) │
|
||||
│ { │
|
||||
│ RunIteration(ref rs, first); │
|
||||
│ first = false; │
|
||||
│ DoCustomProcessing(); │
|
||||
│ } │
|
||||
│ │
|
||||
│ End(rs); │
|
||||
└────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## RequestStop Flow
|
||||
|
||||
### Current
|
||||
|
||||
```
|
||||
User Action (e.g., Quit Key)
|
||||
│
|
||||
▼
|
||||
Application.RequestStop(toplevel)
|
||||
│
|
||||
▼
|
||||
Sets toplevel.Running = false
|
||||
│
|
||||
▼
|
||||
RunLoop detects !Running
|
||||
│
|
||||
▼
|
||||
RunLoop exits
|
||||
│
|
||||
▼
|
||||
Application.End() cleans up
|
||||
│
|
||||
▼
|
||||
┌────────────────────────┐
|
||||
│ RequestStop(window) │ ✅ Keep: "Request" is clear
|
||||
└────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────┐
|
||||
│ window.Running=false │
|
||||
└────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────┐
|
||||
│ RunLoop exits │
|
||||
└────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────┐
|
||||
│ End() cleans up │
|
||||
└────────────────────────┘
|
||||
```
|
||||
|
||||
### Proposed (Same flow, clearer names)
|
||||
## What We're Keeping
|
||||
|
||||
```
|
||||
User Action (e.g., Quit Key)
|
||||
│
|
||||
▼
|
||||
Application.StopProcessingEvents(toplevel) ✅ Clear: stops event processing
|
||||
│
|
||||
▼
|
||||
Sets toplevel.Running = false
|
||||
│
|
||||
▼
|
||||
ProcessEvents detects !Running
|
||||
│
|
||||
▼
|
||||
ProcessEvents exits
|
||||
│
|
||||
▼
|
||||
Application.EndSession() cleans up
|
||||
✅ KEEP AS-IS:
|
||||
|
||||
Begin/End
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Begin(window) │ ... │ End(token) │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
↑ ↑
|
||||
│ │
|
||||
Clear, concise Clear, concise
|
||||
Not wordy Not wordy
|
||||
|
||||
|
||||
RequestStop
|
||||
┌─────────────────────┐
|
||||
│ RequestStop() │
|
||||
└─────────────────────┘
|
||||
↑
|
||||
│
|
||||
"Request" appropriately
|
||||
conveys non-blocking
|
||||
|
||||
|
||||
RunLoop / RunIteration
|
||||
┌─────────────────┐ ┌──────────────────┐
|
||||
│ RunLoop() │ │ RunIteration() │
|
||||
│ (the loop) │ │ (one iteration) │
|
||||
└─────────────────┘ └──────────────────┘
|
||||
↑ ↑
|
||||
│ │
|
||||
Distinction is important and valuable
|
||||
```
|
||||
|
||||
## Nested Sessions (Modal Dialogs)
|
||||
## Side-by-Side Summary
|
||||
|
||||
```
|
||||
┌────────────── Main Window Session ──────────────┐
|
||||
│ │
|
||||
│ session1 = BeginSession(mainWindow) │
|
||||
│ │
|
||||
│ ProcessEvents(session1) starts... │
|
||||
│ │ │
|
||||
│ │ User clicks "Open Dialog" button │
|
||||
│ │ │
|
||||
│ ├─> ┌──────── Dialog Session ──────┐ │
|
||||
│ │ │ │ │
|
||||
│ │ │ session2 = BeginSession(dialog) │
|
||||
│ │ │ │ │
|
||||
│ │ │ ProcessEvents(session2) │ │
|
||||
│ │ │ (blocks until dialog closes) │ │
|
||||
│ │ │ │ │
|
||||
│ │ │ EndSession(session2) │ │
|
||||
│ │ │ │ │
|
||||
│ │ └───────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ (returns to main window) │
|
||||
│ │ │
|
||||
│ ...ProcessEvents continues │
|
||||
│ │
|
||||
│ EndSession(session1) │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────┘
|
||||
|
||||
Key Insight: Sessions can be nested (modal dialogs)
|
||||
╔═══════════════════════════════════╦═══════════════════════════════════╗
|
||||
║ CURRENT ║ PROPOSED ║
|
||||
╠═══════════════════════════════════╬═══════════════════════════════════╣
|
||||
║ RunState rs = Begin(window); ║ RunToken token = Begin(window); ║
|
||||
║ EndAfterFirstIteration = true; ║ StopAfterFirstIteration = true; ║
|
||||
║ RunLoop(rs); ║ RunLoop(token); ║
|
||||
║ End(rs); ║ End(token); ║
|
||||
║ ║ ║
|
||||
║ ❌ "State" misleading ║ ✅ "Token" clear ║
|
||||
║ ❌ "End" confuses with End() ║ ✅ "Stop" aligns with RequestStop║
|
||||
╚═══════════════════════════════════╩═══════════════════════════════════╝
|
||||
```
|
||||
|
||||
## Complete Example Flow
|
||||
|
||||
### Simple Application
|
||||
## Terminology Mapping
|
||||
|
||||
```
|
||||
START
|
||||
│
|
||||
├─> Application.Init() [Application Lifecycle]
|
||||
│ └─> Initialize driver, screen
|
||||
│
|
||||
├─> window = new Window()
|
||||
│
|
||||
├─> Application.Run(window) [High-level API]
|
||||
│ │
|
||||
│ ├─> BeginSession(window) [Session begins]
|
||||
│ │ └─> Initialize, layout, draw
|
||||
│ │
|
||||
│ ├─> ProcessEvents(session) [Event processing]
|
||||
│ │ └─> Loop until stopped
|
||||
│ │
|
||||
│ └─> EndSession(session) [Session ends]
|
||||
│ └─> Cleanup
|
||||
│
|
||||
├─> window.Dispose()
|
||||
│
|
||||
└─> Application.Shutdown() [Application Lifecycle]
|
||||
└─> Restore terminal
|
||||
END
|
||||
```
|
||||
CHANGE (2 names):
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
RunState → RunToken
|
||||
EndAfterFirstIteration → StopAfterFirstIteration
|
||||
|
||||
### Application with Manual Control
|
||||
|
||||
```
|
||||
START
|
||||
│
|
||||
├─> Application.Init()
|
||||
│
|
||||
├─> window = new Window()
|
||||
│
|
||||
├─> session = Application.BeginSession(window) [Manual Session Control]
|
||||
│ └─> Initialize, layout, draw
|
||||
│
|
||||
├─> Application.StopAfterFirstIteration = true
|
||||
│
|
||||
├─> while (!done) [Custom Event Loop]
|
||||
│ │
|
||||
│ ├─> Application.ProcessEventsIteration(ref session, first)
|
||||
│ │ └─> Process one iteration
|
||||
│ │
|
||||
│ ├─> DoCustomProcessing()
|
||||
│ │
|
||||
│ └─> first = false
|
||||
│
|
||||
├─> Application.EndSession(session) [Manual Session Control]
|
||||
│ └─> Cleanup
|
||||
│
|
||||
├─> window.Dispose()
|
||||
│
|
||||
└─> Application.Shutdown()
|
||||
END
|
||||
```
|
||||
|
||||
## Terminology Mapping Summary
|
||||
|
||||
### API Name Changes
|
||||
|
||||
```
|
||||
CURRENT PROPOSED
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Application.Run() → Application.Run() (unchanged)
|
||||
|
||||
RunState → ToplevelSession ✅ Clear: session token
|
||||
|
||||
Application.Begin() → Application.BeginSession() ✅ Clear: begin a session
|
||||
|
||||
Application.RunLoop() → Application.ProcessEvents() ✅ Clear: processes events
|
||||
|
||||
Application.RunIteration() → Application.ProcessEventsIteration() ✅ Clear: one iteration
|
||||
|
||||
Application.End() → Application.EndSession() ✅ Clear: end the session
|
||||
|
||||
Application.RequestStop() → Application.StopProcessingEvents() ✅ Clear: stops processing
|
||||
|
||||
EndAfterFirstIteration → StopAfterFirstIteration ✅ Consistent naming
|
||||
|
||||
NotifyNewRunState → NotifyNewSession ✅ Consistent naming
|
||||
|
||||
NotifyStopRunState → NotifyStopSession ✅ Consistent naming
|
||||
|
||||
RunStateEventArgs → ToplevelSessionEventArgs ✅ Consistent naming
|
||||
KEEP UNCHANGED:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Begin → Begin ✅
|
||||
End → End ✅
|
||||
RequestStop → RequestStop ✅
|
||||
RunLoop → RunLoop ✅
|
||||
RunIteration → RunIteration ✅
|
||||
Run → Run ✅
|
||||
```
|
||||
|
||||
## Benefits Visualized
|
||||
|
||||
### Before: Confusion
|
||||
|
||||
```
|
||||
User thinks:
|
||||
"What's the difference between Run, RunLoop, and RunIteration?"
|
||||
"Is RunState storing state or just a handle?"
|
||||
"What am I Beginning and Ending?"
|
||||
Before:
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Users think: │
|
||||
│ • "What state does RunState hold?" │
|
||||
│ • "Does EndAfterFirstIteration call │
|
||||
│ End()?" │
|
||||
│ │
|
||||
│ Result: Confusion, questions │
|
||||
└─────────────────────────────────────────┘
|
||||
|
||||
┌─────────────┐
|
||||
│ Run() │ ← What does "Run" mean exactly?
|
||||
└─────────────┘
|
||||
│
|
||||
┌─────────────┐
|
||||
│ Begin() │ ← Begin what?
|
||||
└─────────────┘
|
||||
│
|
||||
┌─────────────┐
|
||||
│ RunLoop() │ ← Is this the same as Run?
|
||||
└─────────────┘
|
||||
│
|
||||
┌─────────────┐
|
||||
│ End() │ ← End what?
|
||||
└─────────────┘
|
||||
|
||||
Result: User confusion, slower learning curve
|
||||
After:
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Users understand: │
|
||||
│ • "RunToken is a token" │
|
||||
│ • "StopAfterFirstIteration controls │
|
||||
│ the loop" │
|
||||
│ │
|
||||
│ Result: Clear, self-documenting │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### After: Clarity
|
||||
## Summary
|
||||
|
||||
```
|
||||
User understands:
|
||||
"Run() does the complete lifecycle"
|
||||
"BeginSession/EndSession manage a session"
|
||||
"ProcessEvents processes events until stopped"
|
||||
"ToplevelSession is a token for the session"
|
||||
**2 Changes Only:**
|
||||
- `RunState` → `RunToken` (clear it's a token)
|
||||
- `EndAfterFirstIteration` → `StopAfterFirstIteration` (clear it controls loop)
|
||||
|
||||
┌─────────────────┐
|
||||
│ Run() │ ✅ Complete lifecycle
|
||||
└─────────────────┘
|
||||
│
|
||||
┌─────────────────┐
|
||||
│ BeginSession() │ ✅ Start a session
|
||||
└─────────────────┘
|
||||
│
|
||||
┌─────────────────┐
|
||||
│ ProcessEvents() │ ✅ Process events
|
||||
└─────────────────┘
|
||||
│
|
||||
┌─────────────────┐
|
||||
│ EndSession() │ ✅ End the session
|
||||
└─────────────────┘
|
||||
**Everything Else Stays:**
|
||||
- `Begin` / `End` - Clear and concise
|
||||
- `RequestStop` - Appropriately non-blocking
|
||||
- `RunLoop` / `RunIteration` - Valuable distinction
|
||||
|
||||
Result: Clear understanding, faster learning curve
|
||||
```
|
||||
**Result:**
|
||||
- ✅ Addresses confusion at the source
|
||||
- ✅ Minimal disruption (2 names)
|
||||
- ✅ Preserves what works well
|
||||
- ✅ Respects maintainer feedback
|
||||
|
||||
## See Also
|
||||
|
||||
- [TERMINOLOGY_PROPOSAL.md](TERMINOLOGY_PROPOSAL.md) - Full proposal with rationale
|
||||
- [TERMINOLOGY_QUICK_REFERENCE.md](TERMINOLOGY_QUICK_REFERENCE.md) - Quick comparison tables
|
||||
- [TERMINOLOGY_INDUSTRY_COMPARISON.md](TERMINOLOGY_INDUSTRY_COMPARISON.md) - Industry patterns
|
||||
See [TERMINOLOGY_PROPOSAL.md](TERMINOLOGY_PROPOSAL.md) for complete analysis.
|
||||
|
||||
Reference in New Issue
Block a user