Skip to content

Commit

Permalink
Merge pull request obsidian-tasks-group#3128 from obsidian-tasks-grou…
Browse files Browse the repository at this point in the history
…p/add-show-hide-children

feat: Add experimental 'show/hide tree' instruction - disabled by default
  • Loading branch information
claremacrae authored Oct 19, 2024
2 parents d216a16 + 10cf7bd commit d732bbb
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
folder includes {{query.file.folder}}
sort by function task.lineNumber
hide backlinks
show tree
```

Note: Tasks uses the due date in its default sort order,<br>so we override that by sorting by line number.
Expand All @@ -20,6 +21,7 @@ Note: Tasks uses the due date in its default sort order,<br>so we override that
folder includes {{query.file.folder}}
done
hide backlinks
show tree
```

### 2.2 Fully completed
Expand All @@ -31,6 +33,7 @@ folder includes {{query.file.folder}}
# There is no Tasks instruction for "fully done" yet
done
hide backlinks
show tree
```

### 2.3 Not completed
Expand All @@ -39,6 +42,7 @@ hide backlinks
folder includes {{query.file.folder}}
not done
hide backlinks
show tree
```

### 2.4 Not fully completed
Expand All @@ -50,6 +54,7 @@ folder includes {{query.file.folder}}
# There is no Tasks instruction for "not fully done" yet
not done
hide backlinks
show tree
```

## 3 Sorting
Expand All @@ -62,6 +67,7 @@ hide backlinks
folder includes {{query.file.folder}}
sort by function task.lineNumber
hide backlinks
show tree
```

### 3.2 Reverse Order
Expand All @@ -70,6 +76,7 @@ hide backlinks
folder includes {{query.file.folder}}
sort by function reverse task.lineNumber
hide backlinks
show tree
```

## 4 Grouping
Expand All @@ -83,6 +90,7 @@ folder includes {{query.file.folder}}
done
group by heading
hide backlinks
show tree
```

### 4.2 Fully completed
Expand All @@ -95,6 +103,7 @@ folder includes {{query.file.folder}}
done
group by heading
hide backlinks
show tree
```

### 4.3 Not completed
Expand All @@ -104,6 +113,7 @@ folder includes {{query.file.folder}}
not done
group by heading
hide backlinks
show tree
```

### 4.4 Not fully completed
Expand All @@ -116,4 +126,5 @@ folder includes {{query.file.folder}}
not done
group by heading
hide backlinks
show tree
```
1 change: 1 addition & 0 deletions src/Layout/QueryLayoutOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export class QueryLayoutOptions {
hideBacklinks: boolean = false;
hideEditButton: boolean = false;
hideUrgency: boolean = true;
hideTree: boolean = true; // WARNING: undocumented, and not yet ready for release.
shortMode: boolean = false;
explainQuery: boolean = false;
}
6 changes: 5 additions & 1 deletion src/Query/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class Query implements IQuery {
private _ignoreGlobalQuery: boolean = false;

private readonly hideOptionsRegexp =
/^(hide|show) (task count|backlink|priority|cancelled date|created date|start date|scheduled date|done date|due date|recurrence rule|edit button|postpone button|urgency|tags|depends on|id|on completion)/i;
/^(hide|show) (task count|backlink|priority|cancelled date|created date|start date|scheduled date|done date|due date|recurrence rule|edit button|postpone button|urgency|tags|depends on|id|on completion|tree)/i;
private readonly shortModeRegexp = /^short/i;
private readonly fullModeRegexp = /^full/i;
private readonly explainQueryRegexp = /^explain/i;
Expand Down Expand Up @@ -309,6 +309,10 @@ ${statement.explainStatement(' ')}
const option = hideOptionsMatch[2].toLowerCase();

switch (option) {
case 'tree':
// WARNING: undocumented, and not yet ready for release.
this._queryLayoutOptions.hideTree = hide;
break;
case 'task count':
this._queryLayoutOptions.hideTaskCount = hide;
break;
Expand Down
86 changes: 64 additions & 22 deletions src/Renderer/QueryResultsRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,28 +220,36 @@ export class QueryResultsRenderer {
});

for (const [taskIndex, task] of tasks.entries()) {
if (this.alreadyRendered(task, renderedTasks)) {
continue;
}

if (this.willBeRenderedLater(task, renderedTasks, tasks)) {
continue;
}

const listItem = await this.addTaskOrListItem(
taskList,
taskLineRenderer,
task,
taskIndex,
queryRendererParameters,
);
renderedTasks.add(task);

if (task.children.length > 0) {
await this.createTaskList(task.children, listItem, queryRendererParameters, renderedTasks);
task.children.forEach((childTask) => {
renderedTasks.add(childTask);
});
if (this.query.queryLayoutOptions.hideTree) {
/* Old-style rendering of tasks:
* - What is rendered:
* - Only task lines that match the query are rendered, as a flat list
* - The order that lines are rendered:
* - Tasks are rendered in the order specified in 'sort by' instructions and default sort order.
*/
if (task instanceof Task) {
await this.addTask(taskList, taskLineRenderer, task, taskIndex, queryRendererParameters);
}
} else {
/* New-style rendering of tasks:
* - What is rendered:
* - Task lines that match the query are rendered, as a tree.
* - Currently, all child tasks and list items of the found tasks are shown,
* including any child tasks that did not match the query.
* - The order that lines are rendered:
* - The top-level/outermost tasks are sorted in the order specified in 'sort by'
* instructions and default sort order.
* - Child tasks (and list items) are shown in their original order in their Markdown file.
*/
await this.addTaskOrListItemAndChildren(
taskList,
taskLineRenderer,
task,
taskIndex,
queryRendererParameters,
tasks,
renderedTasks,
);
}
}

Expand Down Expand Up @@ -274,6 +282,40 @@ export class QueryResultsRenderer {
return renderedTasks.has(task);
}

private async addTaskOrListItemAndChildren(
taskList: HTMLUListElement,
taskLineRenderer: TaskLineRenderer,
task: ListItem,
taskIndex: number,
queryRendererParameters: QueryRendererParameters,
tasks: ListItem[],
renderedTasks: Set<ListItem>,
) {
if (this.alreadyRendered(task, renderedTasks)) {
return;
}

if (this.willBeRenderedLater(task, renderedTasks, tasks)) {
return;
}

const listItem = await this.addTaskOrListItem(
taskList,
taskLineRenderer,
task,
taskIndex,
queryRendererParameters,
);
renderedTasks.add(task);

if (task.children.length > 0) {
await this.createTaskList(task.children, listItem, queryRendererParameters, renderedTasks);
task.children.forEach((childTask) => {
renderedTasks.add(childTask);
});
}
}

private async addTaskOrListItem(
taskList: HTMLUListElement,
taskLineRenderer: TaskLineRenderer,
Expand Down
7 changes: 7 additions & 0 deletions tests/Query/Query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ describe('Query parsing', () => {
'hide start date',
'hide tags',
'hide task count',
'hide tree',
'hide urgency',
'ignore global query',
'limit 42',
Expand All @@ -489,6 +490,7 @@ describe('Query parsing', () => {
'show start date',
'show tags',
'show task count',
'show tree',
'show urgency',
];
test.concurrent.each<string>(filters)('recognises %j', (filter) => {
Expand Down Expand Up @@ -1302,6 +1304,11 @@ describe('Query', () => {
const query = new Query('hide on completion');
expect(query.taskLayoutOptions.isShown(TaskLayoutComponent.OnCompletion)).toEqual(false);
});

it('should hide "tree" by default', () => {
const query = new Query('');
expect(query.queryLayoutOptions.hideTree).toEqual(true);
});
});

describe('sorting', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<div>
<ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
<li
class="task-list-item plugin-tasks-list-item"
data-task-priority="normal"
data-task=""
data-line="0"
data-task-status-name="Todo"
data-task-status-type="TODO">
<input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="0" />
<span class="tasks-list-text">
<span class="task-description"><span>parent 1</span></span>
</span>
<span class="task-extras">
<span class="tasks-backlink">
(
<a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
)
</span>
<a class="tasks-edit" title="Edit task" href="#"></a>
</span>
</li>
<li
class="task-list-item plugin-tasks-list-item"
data-task-priority="normal"
data-task=""
data-line="1"
data-task-status-name="Todo"
data-task-status-type="TODO">
<input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="1" />
<span class="tasks-list-text">
<span class="task-description"><span>child 1</span></span>
</span>
<span class="task-extras">
<span class="tasks-backlink">
(
<a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
)
</span>
<a class="tasks-edit" title="Edit task" href="#"></a>
</span>
</li>
<li
class="task-list-item plugin-tasks-list-item"
data-task-priority="normal"
data-task=""
data-line="2"
data-task-status-name="Todo"
data-task-status-type="TODO">
<input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="2" />
<span class="tasks-list-text">
<span class="task-description"><span>grandchild 1</span></span>
</span>
<span class="task-extras">
<span class="tasks-backlink">
(
<a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
)
</span>
<a class="tasks-edit" title="Edit task" href="#"></a>
</span>
</li>
<li
class="task-list-item plugin-tasks-list-item"
data-task-priority="normal"
data-task=""
data-line="3"
data-task-status-name="Todo"
data-task-status-type="TODO">
<input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="3" />
<span class="tasks-list-text">
<span class="task-description"><span>child 2</span></span>
</span>
<span class="task-extras">
<span class="tasks-backlink">
(
<a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
)
</span>
<a class="tasks-edit" title="Edit task" href="#"></a>
</span>
</li>
<li
class="task-list-item plugin-tasks-list-item"
data-task-priority="normal"
data-task=""
data-line="4"
data-task-status-name="Todo"
data-task-status-type="TODO">
<input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="4" />
<span class="tasks-list-text">
<span class="task-description"><span>grand grand child</span></span>
</span>
<span class="task-extras">
<span class="tasks-backlink">
(
<a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
)
</span>
<a class="tasks-edit" title="Edit task" href="#"></a>
</span>
</li>
<li
class="task-list-item plugin-tasks-list-item"
data-task-priority="normal"
data-task=""
data-line="5"
data-task-status-name="Todo"
data-task-status-type="TODO">
<input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="5" />
<span class="tasks-list-text">
<span class="task-description"><span>parent 2</span></span>
</span>
<span class="task-extras">
<span class="tasks-backlink">
(
<a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
)
</span>
<a class="tasks-edit" title="Edit task" href="#"></a>
</span>
</li>
</ul>
<div class="task-count">6 tasks</div>
</div>
14 changes: 11 additions & 3 deletions tests/Renderer/QueryResultsRenderer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,27 @@ describe('QueryResultsRenderer tests', () => {
await verifyRenderedTasksHTML(allTasks);
});

const showTree = 'show tree\n';
const hideTree = 'hide tree\n';

it('parent-child items hidden', async () => {
const allTasks = readTasksFromSimulatedFile(inheritance_rendering_sample);
await verifyRenderedTasksHTML(allTasks, hideTree + 'sort by function task.lineNumber');
});

it('parent-child items', async () => {
const allTasks = readTasksFromSimulatedFile(inheritance_rendering_sample);
await verifyRenderedTasksHTML(allTasks, 'sort by function task.lineNumber');
await verifyRenderedTasksHTML(allTasks, showTree + 'sort by function task.lineNumber');
});

it('parent-child items reverse sorted', async () => {
const allTasks = readTasksFromSimulatedFile(inheritance_rendering_sample);
await verifyRenderedTasksHTML(allTasks, 'sort by function reverse task.lineNumber');
await verifyRenderedTasksHTML(allTasks, showTree + 'sort by function reverse task.lineNumber');
});

it('should render tasks without their parents', async () => {
// example chosen to match subtasks whose parents do not match the query
const allTasks = readTasksFromSimulatedFile(inheritance_task_2listitem_3task);
await verifyRenderedTasksHTML(allTasks, 'description includes grandchild');
await verifyRenderedTasksHTML(allTasks, showTree + 'description includes grandchild');
});
});

0 comments on commit d732bbb

Please sign in to comment.