Skip to content

Commit 68a5a74

Browse files
authored
Add underscore notation [_] for unchecked task list items (#87)
Implements support for using underscore as an alternative to space for unchecked task list items: `[_]` is now equivalent to `[ ]`. This is useful for: - Mobile devices where spaces inside brackets are hard to type - Editors without monospaced fonts where `[ ]` may look ambiguous - Visual clarity as underscore resembles an empty checkbox Related to upstream discussion: jgm/djot#305 where jgm expressed support for this feature. Changes: - Update ListItem to explicitly handle underscore as unchecked marker - Add official tests for underscore notation - Add unit test in DjotConverterTest - Update syntax.md and enhancements.md documentation
1 parent 90010e5 commit 68a5a74

File tree

5 files changed

+100
-10
lines changed

5 files changed

+100
-10
lines changed

docs/enhancements.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ They are either on the way to get incorporated upstream - or may be incorporated
1515
- [Optional Modes](#optional-modes)
1616
- [Significant Newlines Mode](#significant-newlines-mode)
1717
- [Language Features Beyond Spec](#language-features-beyond-spec)
18+
- [Task List Underscore Notation](#task-list-underscore-notation)
1819
- [List Item Attributes](#list-item-attributes)
1920
- [Table Row and Cell Attributes](#table-row-and-cell-attributes)
2021
- [Boolean Attribute Shorthand](#boolean-attribute-shorthand)
@@ -249,6 +250,38 @@ They said:
249250

250251
These are djot syntax features we've implemented that aren't yet in the upstream spec.
251252

253+
### Task List Underscore Notation
254+
255+
**Related:** [jgm/djot#305](https://github.com/jgm/djot/issues/305)
256+
257+
**Status:** Implemented in djot-php
258+
259+
The underscore `[_]` can be used as an alternative to space `[ ]` for unchecked task list items:
260+
261+
```djot
262+
- [_] unchecked with underscore
263+
- [ ] unchecked with space
264+
- [x] checked item
265+
```
266+
267+
**Output:**
268+
```html
269+
<ul class="task-list">
270+
<li><input type="checkbox" disabled> unchecked with underscore</li>
271+
<li><input type="checkbox" disabled> unchecked with space</li>
272+
<li><input type="checkbox" disabled checked> checked item</li>
273+
</ul>
274+
```
275+
276+
**Rationale:** The underscore notation is useful when:
277+
- Typing on mobile devices where spaces inside brackets can be difficult
278+
- Using editors without monospaced fonts where `[ ]` may look ambiguous
279+
- The underscore visually resembles an empty checkbox in source
280+
281+
Both notations are fully equivalent and can be mixed within the same list.
282+
283+
---
284+
252285
### List Item Attributes
253286

254287
**Related:** [jgm/djot#262](https://github.com/jgm/djot/pull/262)
@@ -811,6 +844,7 @@ vendor/bin/phpunit
811844

812845
| Feature | Upstream PR/Issue | Status |
813846
|-----------------------------------|---------------------------------------------------------------------|------------|
847+
| Task list underscore notation | [djot:305](https://github.com/jgm/djot/issues/305) | Open |
814848
| List item attributes | [djot:262](https://github.com/jgm/djot/pull/262) | Open PR |
815849
| Table row/cell attributes | [djot:250](https://github.com/jgm/djot/issues/250) | Open |
816850
| Boolean attribute shorthand | [djot:257](https://github.com/jgm/djot/issues/257) | Open |

docs/syntax.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,21 +228,23 @@ Indent with 2+ spaces for nested lists.
228228

229229
#### Task Lists
230230

231-
Use `[ ]` for unchecked and `[x]` or `[X]` for checked items.
231+
Use `[ ]` or `[_]` for unchecked and `[x]` or `[X]` for checked items.
232+
233+
The underscore notation `[_]` is useful on mobile devices or in editors without monospaced fonts, where the space in `[ ]` can be hard to type or see.
232234

233235
**Input:**
234236
```djot
235-
- [ ] Todo item
237+
- [ ] Todo item (space)
238+
- [_] Todo item (underscore)
236239
- [x] Done item
237-
- [ ] Another todo
238240
```
239241

240242
**Output:**
241243
```html
242244
<ul class="task-list">
243-
<li><input type="checkbox" disabled> Todo item</li>
245+
<li><input type="checkbox" disabled> Todo item (space)</li>
246+
<li><input type="checkbox" disabled> Todo item (underscore)</li>
244247
<li><input type="checkbox" disabled checked> Done item</li>
245-
<li><input type="checkbox" disabled> Another todo</li>
246248
</ul>
247249
```
248250

src/Node/Block/ListItem.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* List item
99
*
1010
* For task lists, stores the raw marker character from inside brackets:
11-
* - ' ' (space) = unchecked
11+
* - ' ' (space) or '_' (underscore) = unchecked
1212
* - 'x' or 'X' = checked/completed
1313
* - Extended markers (for custom rendering via events):
1414
* - '-' = cancelled/not applicable
@@ -32,7 +32,7 @@ public function __construct(protected ?string $taskMarker = null)
3232
/**
3333
* Get the raw task marker character
3434
*
35-
* Returns the character inside the brackets: ' ', 'x', 'X', '-', '/', '>', '?', etc.
35+
* Returns the character inside the brackets: ' ', '_', 'x', 'X', '-', '/', '>', '?', etc.
3636
* Returns null if this is not a task list item.
3737
*/
3838
public function getTaskMarker(): ?string
@@ -43,7 +43,7 @@ public function getTaskMarker(): ?string
4343
/**
4444
* For task lists: null = not a task, true = checked, false = unchecked
4545
*
46-
* Note: This method only recognizes standard markers (' ', 'x', 'X').
46+
* Note: This method only recognizes standard markers (' ', '_', 'x', 'X').
4747
* For extended markers, use getTaskMarker() and handle in render events.
4848
*/
4949
public function getChecked(): ?bool
@@ -52,8 +52,8 @@ public function getChecked(): ?bool
5252
return null;
5353
}
5454

55-
// Standard markers
56-
if ($this->taskMarker === ' ') {
55+
// Standard markers - space and underscore are both unchecked
56+
if ($this->taskMarker === ' ' || $this->taskMarker === '_') {
5757
return false;
5858
}
5959
if (strtolower($this->taskMarker) === 'x') {

tests/TestCase/DjotConverterTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,21 @@ public function testTaskList(): void
161161
$this->assertStringContainsString('Checked', $result);
162162
}
163163

164+
public function testTaskListUnderscoreNotation(): void
165+
{
166+
$djot = "- [_] Unchecked with underscore\n- [ ] Unchecked with space\n- [x] Checked";
167+
168+
$result = $this->converter->convert($djot);
169+
170+
$this->assertStringContainsString('task-list', $result);
171+
// Both underscore and space should render as unchecked checkboxes
172+
$this->assertSame(2, substr_count($result, '<input disabled="" type="checkbox"/>'));
173+
$this->assertSame(1, substr_count($result, 'checked=""'));
174+
$this->assertStringContainsString('Unchecked with underscore', $result);
175+
$this->assertStringContainsString('Unchecked with space', $result);
176+
$this->assertStringContainsString('Checked', $result);
177+
}
178+
164179
public function testThematicBreak(): void
165180
{
166181
$djot = "Before\n\n***\n\nAfter";

tests/official/task_lists.test

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,42 @@ baz
5959
</li>
6060
</ul>
6161
```
62+
63+
Underscore notation for unchecked items:
64+
```
65+
- [_] unchecked with underscore
66+
- [x] checked item
67+
.
68+
<ul class="task-list">
69+
<li>
70+
<input disabled="" type="checkbox"/>
71+
unchecked with underscore
72+
</li>
73+
<li>
74+
<input disabled="" type="checkbox" checked=""/>
75+
checked item
76+
</li>
77+
</ul>
78+
```
79+
80+
Mixed underscore and space notation:
81+
```
82+
- [_] underscore unchecked
83+
- [ ] space unchecked
84+
- [x] checked
85+
.
86+
<ul class="task-list">
87+
<li>
88+
<input disabled="" type="checkbox"/>
89+
underscore unchecked
90+
</li>
91+
<li>
92+
<input disabled="" type="checkbox"/>
93+
space unchecked
94+
</li>
95+
<li>
96+
<input disabled="" type="checkbox" checked=""/>
97+
checked
98+
</li>
99+
</ul>
100+
```

0 commit comments

Comments
 (0)