Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@cyrusmsk
Copy link
Contributor

@cyrusmsk cyrusmsk commented Dec 17, 2025

Port of the tcell tutorial from Go.

Maybe some polish will be required.
Let me know in case you would like to add something else.

Summary by CodeRabbit

  • Documentation
    • Added a comprehensive tutorial for using the terminal library: terminal event model (resize, key, mouse), input behaviors and modifiers, screen lifecycle (create, clear, render), text-wrapping helper, rendering helpers, demo helpers for drawing and coordinates, and a complete demo app showcasing ESC-to-exit, drag-to-draw, and redraw workflows.

✏️ Tip: You can customize this high-level summary in your review settings.

Port of the tcell tutorial
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

Walkthrough

Adds a new tutorial document demos/tutorial.md that documents Dcell's terminal API, event model (resize/key/mouse), screen management and rendering helpers, and includes an event-loop example plus a complete interactive demo application.

Changes

Cohort / File(s) Summary
New Tutorial Documentation
demos/tutorial.md
Introduces a comprehensive tutorial describing terminal initialization and events (initial/resize), key and mouse event handling, screen creation/clearing/writing/wrapping, helper functions (e.g., text rendering, box drawing), an event-loop example, and a demo app with drag-to-draw behavior and code samples.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Check that API names/signatures in examples match the current codebase.
  • Validate event semantics described (initial resize, key modifiers, mouse enablement).
  • Run the demo to ensure examples compile and helpers (e.g., renderText, drawBox) behave as documented.

Poem

I'm a rabbit with a nib so bright, 🐇
I hopped through docs into the night,
I drew some boxes, keys, and clicks,
Wrote down the steps and handy tricks,
A carrot-shaped tutorial — delight. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a new tutorial.md file. It is concise, clear, and directly reflects the primary purpose of the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between acfb4b1 and feffe9d.

📒 Files selected for processing (1)
  • demos/tutorial.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
demos/tutorial.md

[grammar] ~9-~9: Use a hyphen to join words.
Context: ...es, it may be easier to utilize a higher level framework. A number of such framew...

(QB_NEW_EN_HYPHEN)


[grammar] ~38-~38: Ensure spelling is correct
Context: ...set toKey.esc` is dispatched. When other key is pressed, it is available as the ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
demos/tutorial.md

45-45: Hard tabs
Column: 5

(MD010, no-hard-tabs)

Copy link

@dejlek dejlek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

cyrusmsk and others added 2 commits December 18, 2025 00:22
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (6)
demos/tutorial.md (6)

33-33: Correct enum case: use lowercase key for event type.

In Dcell, all enum members are lowercase. Use EventType.key instead of EventType.Key.

-When a key is pressed, applications receive an event of type `EventType.Key`.
+When a key is pressed, applications receive an event of type `EventType.key`.

Based on learnings, dcell enums consistently use lowercase naming.


45-45: Replace hard tabs with spaces.

Hard tabs detected on line 45. Use spaces for consistent indentation throughout the document.

-    		info(i"Esc key was pressed");
+        info(i"Esc key was pressed");

38-38: Fix grammar: use "another" instead of "other" for singular.

When used with a singular noun, use "another" instead of "other".

-When other key is pressed, it is available as the `Key.graph` of the event.
+When another key is pressed, it is available as the `Key.graph` of the event.

20-29: Fix logic error: resize event accessing undefined mouse position.

EventType.resize events don't contain mouse data. Accessing ev.mouse.pos causes undefined behavior. Either omit the position info or use s.size() to report the new dimensions.

Apply one of these diffs:

Option 1: Remove position info entirely

case EventType.resize:
    s.resize();
    s.sync();
-   info(i"Resized to $(ev.mouse.pos)");
+   info("Resized");
    break;

Option 2: Report dimensions using s.size()

case EventType.resize:
    s.resize();
    s.sync();
-   info(i"Resized to $(ev.mouse.pos)");
+   auto newSize = s.size();
+   info(i"Resized to $(newSize)");
    break;

Based on learnings, the second approach provides more useful feedback to users.


338-347: Fix logic error: first condition swallows unreachable Ctrl+C branch.

The unconditional check for (ev.key.ch == 'C' || ev.key.ch == 'c') on line 338 matches all c/C keypresses, making the Ctrl+C check on line 343 unreachable. Test the modifier first, or restructure to avoid shadowing.

 case Key.graph:
-    if (ev.key.ch == 'C' || ev.key.ch == 'c')
+    if ((ev.key.ch == 'C' || ev.key.ch == 'c') && ev.key.mod == Modifiers.ctrl)
     {
         s.style = def;
         s.clear();
+    }
+    else if (ev.key.ch == 'C' || ev.key.ch == 'c')
+    {
+        s.stop();
+        exit(0);
     }
-    else if ((ev.key.ch == 'C' || ev.key.ch == 'c') && ev.key.mod == Modifiers.ctrl)
-    {
-        s.stop();
-        exit(0);
-    }
     // Ctrl-L (without other modifiers) is used to redraw (UNIX convention)
     else if (ev.key.ch == 'l' && ev.key.mod == Modifiers.ctrl)
     {

Wait, re-reading the intent: the first block clears, the second block should exit. Let me correct:

 case Key.graph:
-    if (ev.key.ch == 'C' || ev.key.ch == 'c')
+    if ((ev.key.ch == 'C' || ev.key.ch == 'c') && ev.key.mod == Modifiers.ctrl)
     {
-        s.style = def;
-        s.clear();
+        s.stop();
+        exit(0);
     }
-    else if ((ev.key.ch == 'C' || ev.key.ch == 'c') && ev.key.mod == Modifiers.ctrl)
+    else if (ev.key.ch == 'C' || ev.key.ch == 'c')
     {
-        s.stop();
-        exit(0);
+        s.style = def;
+        s.clear();
     }
     // Ctrl-L (without other modifiers) is used to redraw (UNIX convention)
     else if (ev.key.ch == 'l' && ev.key.mod == Modifiers.ctrl)

This way, Ctrl+C exits (modifier-first check), and plain C/c clears (fallback check).


99-119: Add missing s.start() call after screen creation.

The screen must be initialized with s.start() before calling any other screen methods. This is currently missing from the usage example, though correctly included in the demo application below.

 auto s = newScreen();
 assert(s !is null);
+s.start();
 scope (exit)
 {
     s.stop();
 }

Based on learnings, s.start() must be called after creating the screen and before any terminal interactions like enableMouse() or enablePaste().

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between feffe9d and 8567855.

📒 Files selected for processing (1)
  • demos/tutorial.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-17T22:06:23.076Z
Learnt from: dejlek
Repo: gdamore/dcell PR: 60
File: demos/tutorial.md:26-26
Timestamp: 2025-12-17T22:06:23.076Z
Learning: In Dcell (D language), when handling EventType.resize events, do not access ev.mouse properties. To get the new terminal dimensions after a resize event, call s.size() instead.

Applied to files:

  • demos/tutorial.md
📚 Learning: 2025-12-15T05:12:35.344Z
Learnt from: gdamore
Repo: gdamore/dcell PR: 56
File: source/dcell/vt.d:2-2
Timestamp: 2025-12-15T05:12:35.344Z
Learning: In D language (used in gdamore/dcell), when you have a variable of enum type (e.g., `Attr attr`), both `attr.EnumMember` and `Attr.EnumMember` are aliased to the same enum value. This means using the lowercase variable name instead of the uppercase type name in case statements is not a compile error, though using the type name is preferred for consistency.

Applied to files:

  • demos/tutorial.md
🪛 LanguageTool
demos/tutorial.md

[grammar] ~38-~38: Ensure spelling is correct
Context: ...set toKey.esc` is dispatched. When other key is pressed, it is available as the ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
demos/tutorial.md

45-45: Hard tabs
Column: 5

(MD010, no-hard-tabs)

Fixes from review
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
demos/tutorial.md (1)

45-45: Replace hard tab with spaces.

Line 45 uses a hard tab for indentation. Convert it to spaces to match the rest of the file.

case Key.esc:
    {
-   	info("Esc key was pressed");
+    info("Esc key was pressed");
        s.stop();
        exit(0);
    }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8567855 and c55f6a2.

📒 Files selected for processing (1)
  • demos/tutorial.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-17T22:06:23.076Z
Learnt from: dejlek
Repo: gdamore/dcell PR: 60
File: demos/tutorial.md:26-26
Timestamp: 2025-12-17T22:06:23.076Z
Learning: In Dcell (D language), when handling EventType.resize events, do not access ev.mouse properties. To get the new terminal dimensions after a resize event, call s.size() instead.

Applied to files:

  • demos/tutorial.md
📚 Learning: 2025-12-15T05:12:35.344Z
Learnt from: gdamore
Repo: gdamore/dcell PR: 56
File: source/dcell/vt.d:2-2
Timestamp: 2025-12-15T05:12:35.344Z
Learning: In D language (used in gdamore/dcell), when you have a variable of enum type (e.g., `Attr attr`), both `attr.EnumMember` and `Attr.EnumMember` are aliased to the same enum value. This means using the lowercase variable name instead of the uppercase type name in case statements is not a compile error, though using the type name is preferred for consistency.

Applied to files:

  • demos/tutorial.md
🪛 markdownlint-cli2 (0.18.1)
demos/tutorial.md

45-45: Hard tabs
Column: 5

(MD010, no-hard-tabs)

🔇 Additional comments (4)
demos/tutorial.md (4)

26-26: Correctly uses s.size() for resize event reporting.

Good fix—the code avoids accessing ev.mouse.pos on resize events and properly calls s.size() to report dimensions.


297-304: Verify s.start() is called before terminal interactions.

Line 304 calls s.start(), which is correct. However, ensure this pattern is consistent: newScreen()start() → then showCursor(), enableMouse(), etc. The current code order looks good.


343-352: Logic correctly prioritizes Ctrl+C before plain C/c.

The condition checks for Ctrl+C first (line 343), then falls through to plain C/c (line 348). This avoids unreachable code and preserves the intended behavior.


85-97: Mouse button enum names are correct.

The table correctly shows lowercase camelCase enum members (button1, button2, etc.) and their lowercase aliases (primary, secondary, middle), matching dcell's naming conventions.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
demos/tutorial.md (1)

45-45: Replace hard tab with spaces.

Static analysis flagged a hard tab character at line 45. Replace it with spaces to match the indentation style used throughout the rest of the file.

 case Key.esc:
     {
-	info("Esc key was pressed");
+    info("Esc key was pressed");
         s.stop();
         exit(0);
     }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c55f6a2 and a8ba3d3.

📒 Files selected for processing (1)
  • demos/tutorial.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-17T22:06:23.076Z
Learnt from: dejlek
Repo: gdamore/dcell PR: 60
File: demos/tutorial.md:26-26
Timestamp: 2025-12-17T22:06:23.076Z
Learning: In Dcell (D language), when handling EventType.resize events, do not access ev.mouse properties. To get the new terminal dimensions after a resize event, call s.size() instead.

Applied to files:

  • demos/tutorial.md
📚 Learning: 2025-12-15T05:12:35.344Z
Learnt from: gdamore
Repo: gdamore/dcell PR: 56
File: source/dcell/vt.d:2-2
Timestamp: 2025-12-15T05:12:35.344Z
Learning: In D language (used in gdamore/dcell), when you have a variable of enum type (e.g., `Attr attr`), both `attr.EnumMember` and `Attr.EnumMember` are aliased to the same enum value. This means using the lowercase variable name instead of the uppercase type name in case statements is not a compile error, though using the type name is preferred for consistency.

Applied to files:

  • demos/tutorial.md
🪛 markdownlint-cli2 (0.18.1)
demos/tutorial.md

45-45: Hard tabs
Column: 5

(MD010, no-hard-tabs)

🔇 Additional comments (1)
demos/tutorial.md (1)

1-395: Approve the tutorial content and structure.

The tutorial is well-organized and comprehensively covers Dcell's event model, screen management, rendering, and includes a complete working demo application. All major logic issues from previous review rounds have been correctly addressed: resize events now use s.size(), key event modifiers are checked first, enum names use lowercase camelCase, and s.start() is properly called before mouse/paste setup. The code examples are clear and follow the library's conventions.

@gdamore gdamore merged commit 347a8b1 into gdamore:main Dec 18, 2025
5 checks passed
@cyrusmsk cyrusmsk deleted the d_tutorial branch December 20, 2025 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants