Skip to content

Commit

Permalink
feat: support placeholders like '{{query.file.path}}' in queries (#2254)
Browse files Browse the repository at this point in the history
* feat: @ bring changes from bleeding-edge

* vault: Add sample file demonstrating {{query.file.path}} etc

* docs: Update docs on finding tasks in current file

* docs: Fix typo in 'How to get tasks in current file'

* test: Copy in MustacheExperiments.test.ts from claremacrae fork

Copied from https://github.com/claremacrae/obsidian-tasks/blob/ae657e0c09b6a040b9a94e81a2b6478a1828c7e6/tests/Query/MustacheExperiments.test.ts

* test: Rename MustacheExperiments.test.ts to ExpandTemplate.test.ts

* test: Generate table of query.file values, for use in docs

* docs: Fix column alignment in Quick Reference markdown source

* docs: Add {{query.file.path}} etc to Quick Reference

* docs: Interim commit of templating documentation

* fix: Query.explainQuery() reports any error message, to avoid misleading results.

* test: Show explanation of instructions using templating.

* docs: Update 'Explaining Queries.md' to explain templating

* docs: Add 'Checking template variables' to Templating.md

* docs: Remove some clutter from early experiments

* docs: Record the name of the templating library used.

* docs: Add "Comments" plugin to track notes to track my feedback

* docs: Interim commit on documentation templating code

* test: Show the output when an invalid template variable is used.

* docs: markdownlint removed stray whitespace at end of snippets

* test: Remove 'explain' instruction which is not needed where snippet is used

* docs: Document how invalid template variables are handled

* docs: Rename Templating to Placeholders in documentation

* refactor: . Rename expandMustacheTemplate() to expandPlaceholders()

* refactor: . Rename ExpandTemplate.ts to ExpandPlaceholders.ts

* test: . Rename ExpandTemplate.test.ts to ExpandPlaceholders.test.ts

* refactor: Move ExpandPlaceholders.ts to src/Scripting/

* tests: . Move ExpandPlaceholders.test.ts to tests/Scripting/

* test: - Reduce scope of a variable in ExpandPlaceholders.test.ts

* test: t Add test for expanding placeholders with no query location supplied

* fix: Replace 'template' with 'placeholder' in an error message

* test: Capture current behaviour: Query.source still has placeholders

* test: Show that filters have placeholder expanded, and rename test

* refactor: - Remove Query.rawSource as it was same as Query.source

* test: Show behaviour when invalid placeholder is used

* fix: Update vocabulary: template -> placeholder in error message.

* test: Move placeholder tests to parsing section

* fix: Remove reference to Mustache library in error messages

* docs: Update error text in Placeholders.md - via mdsnippets

* comment: Correct function name in TODO to expandPlaceholders()

* test: Remove a test that now serves no value

* docs: Convert 'templating' vocabulary to 'placeholders'

* test: Remove a reference to templating, in approved filenames

* docs: Remove a reference to templating, in approved filenames

* comment: Convert 'templating' vocabulary to 'placeholders' in Query.ts

* refactor: - Extract method Query.expandPlaceholders()

* refactor: . inline makeQueryContext()

* jsdoc: Document new functions and types

* refactor: . Move QueryContext to Scripting/ directory from lib/

* jsdoc: Delete some out-of-date comments and move mustache link to ExpandPlaceholders.ts

* test: Add comments to give 2 tests some structure

* test: Add another test showing unknown property errors are displayed

* refactor: Move the code for improving Mustache errors to ExpandPlaceholders.ts

* comment: Convert 'template' vocabulary to 'placeholders' in ExpandPlaceholders.ts

* refactor: . Extract variable source

* refactor: . Add source parameter to Query.expandPlaceholders()

* refactor: - Show user the exact line with unrecognised placeholder(s)

* refactor: - Slightly more general error text in expandPlaceholders()

* test: - Increase scope of path variable, to allow re-use

* test: - Confirm that mustache only does expansion if {{ is in the input

* refactor: - Indent user inputs in error messages, for readability

* docs: Update Error-checking section for better messages

* docs: Near finalisation of Placeholders.md

* docs: Document basic use of placeholders in Filters page

* test: Add sample file 'a/b.md' to allPathsAndHeadings() - needed to demo placeholders in docs

* test: Add examples of placeholders in custom filters

* test: Add example of placeholders in custom groups

* docs: Update machined-generated examples in docs for placeholders

* docs: Document basic use of placeholders in Grouping page

* docs: Document placeholders in custom filters and groups

* docs: Add query properties and placeholders to Introduction

* vault: Remove "Comments" plugin as no longer needed

---------

Co-authored-by: Clare Macrae <[email protected]>
  • Loading branch information
ilandikov and claremacrae authored Sep 12, 2023
1 parent f8ecd9b commit 8237ef0
Show file tree
Hide file tree
Showing 45 changed files with 911 additions and 98 deletions.
42 changes: 25 additions & 17 deletions docs/How To/How to get tasks in current file.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ publish: true

# How to get all tasks in the current file

<span class="related-pages">#plugin/dataview</span>
<span class="related-pages">#feature/scripting #plugin/dataview</span>

## Motivation and assumptions

Expand All @@ -13,37 +13,45 @@ for example to make sure no task gets accidentally missed.

This page documents ways of setting this up.

Assumptions:
## Using pure Tasks blocks - with placeholders

- We assume that you know how to install and enable the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) plugin.
> [!released]
> Placeholders were introduced in Tasks X.Y.Z.
## Using pure Tasks blocks - fragile and error-prone
We want to search for tasks in the file with the same `path` that the query is in.

Tasks does not provide an automated way to include the location of the `tasks` block in a query.
Tasks now provides an automated way to include the location of the `tasks` block in a query.

It is possible to use the `path` instruction, but unfortunately you have to insert the path to the file yourself:
We can use the `path` instruction with the placeholder text `{{query.file.path}}` which will be replaced with the path of the file containing the current query, like this:

## Summary of Tasks within this note

```tasks
not done
path includes [insert current note's name or full path]
path includes path includes {{query.file.path}}
```

For example:
The following placeholders are available:

## Summary of Tasks within this note
```text
{{query.file.path}}
{{query.file.root}}
{{query.file.folder}}
{{query.file.filename}}
```

```tasks
not done
path includes Obsidian/tasks/tasks user support/03 Done - tasks user support/1.11.0 release
```
They can be used with any text filter, not just `path`, `file`, `folder`, `filename`. For example, they might be useful with `description` and `heading` filters.

> [!warning]
> Using `path includes` to search for a particular file name or folder is error-prone, as if you rename the file,
you have to remember to manually update the location in the tasks block, and this is very error-prone.
For more information, see:

## Using Dataview to generate Tasks blocks - safe and convenient
- [[Placeholders]]
- [[Query Properties]]

## Using Dataview to generate Tasks blocks - the old way

<label class="ob-comment" title="" style=""> Assumptions <input type="checkbox"> <span style=""> Move this to a separate note<br> - but retain the original heading<br> - and link to it from here </span></label>:

- We assume that you know how to install and enable the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) plugin.

There is a nice property that the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) plugin can write out code blocks that are then processed by other plugins.

Expand Down
1 change: 1 addition & 0 deletions docs/Introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ publish: true

## What's New?

- X.Y.Z: 🔥 Use [[Query Properties]] and [[Placeholders]] to filter and group with the query's file path, root, folder and name.
- 4.6.0: 🔥 Add `on or before` and `on or after` to [[Filters#Date search options|date search options]]
- 4.6.0: 🔥 Add `in or before` and `in or after` to [[Filters#Date range options|date range search search options]]
- 4.5.0: 🔥 Support task in list items starting with [[Getting Started#Finding tasks in your vault|`+` signs]]
Expand Down
33 changes: 33 additions & 0 deletions docs/Queries/Explaining Queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,39 @@ due next week =>
```
<!-- endSnippet -->

### Template values are expanded

> [!released]
> Templating was introduced in Tasks X.Y.Z.
For example, when the following query with [[Query Properties]] in [[Placeholders|placeholders]] is placed in a tasks query block in the file `some/sample/file path.md`:

<!-- snippet: DocsSamplesForExplain.test.explain_placeholders.approved.query.text -->
```text
explain
path includes {{query.file.path}}
root includes {{query.file.root}}
folder includes {{query.file.folder}}
filename includes {{query.file.filename}}
```
<!-- endSnippet -->

the results begin with the following:

<!-- snippet: DocsSamplesForExplain.test.explain_placeholders.approved.explanation.text -->
```text
Explanation of this Tasks code block query:
path includes some/sample/file path.md
root includes some/
folder includes some/sample/
filename includes file path.md
```
<!-- endSnippet -->

## Styling explain results

### Default style
Expand Down
35 changes: 30 additions & 5 deletions docs/Queries/Filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -975,12 +975,17 @@ Note that the path includes the `.md` extension.

- `path (includes|does not include) <path>`
- Matches case-insensitive (disregards capitalization).
- Use `{{query.file.path}}` as a placeholder for the path of the file containing the current query.
- For example, `path equals {{query.file.path}}`
- Useful reading: [[Query Properties]] and [[Placeholders]]
- `path (regex matches|regex does not match) /<JavaScript-style Regex>/`
- Does regular expression match (case-sensitive by default).
- Essential reading: [[Regular Expressions|Regular Expression Searches]].

> [!released]
`regex matches` and `regex does not match` were introduced in Tasks 1.12.0.
>
> - `regex matches` and `regex does not match` were introduced in Tasks 1.12.0.
> - Placeholders were released in Tasks X.Y.Z.
Since Tasks 4.2.0, **[[Custom Filters|custom filtering]] by file path** is now possible, using `task.file.path`.

Expand All @@ -1000,12 +1005,17 @@ Since Tasks 4.2.0, **[[Custom Filters|custom filtering]] by file path** is now p
### Root

> [!released]
> Introduced in Tasks 3.4.0.
>
> - Introduced in Tasks 3.4.0.
> - Placeholders were released in Tasks X.Y.Z.
The `root` is the top-level folder of the file that contains the task, that is, the first directory in the path, which will be `/` for files in the root of the vault.

- `root (includes|does not include) <root>`
- Matches case-insensitive (disregards capitalization).
- Use `{{query.file.root}}` as a placeholder for the root of the file containing the current query.
- For example, `root includes {{query.file.root}}`
- Useful reading: [[Query Properties]] and [[Placeholders]]
- `root (regex matches|regex does not match) /<JavaScript-style Regex>/`
- Does regular expression match (case-sensitive by default).
- Essential reading: [[Regular Expressions|Regular Expression Searches]].
Expand All @@ -1026,12 +1036,17 @@ Since Tasks 4.2.0, **[[Custom Filters|custom filtering]] by root folder** is now
### Folder

> [!released]
> Introduced in Tasks 3.4.0.
>
> - Introduced in Tasks 3.4.0.
> - Placeholders were released in Tasks X.Y.Z.
This is the `folder` to the file that contains the task, which will be `/` for files in root of the vault.

- `folder (includes|does not include) <folder>`
- Matches case-insensitive (disregards capitalization).
- Use `{{query.file.folder}}` as a placeholder for the folder of the file containing the current query.
- For example, `folder includes {{query.file.folder}}`, which will match tasks in the folder containing the query **and all sub-folders**.
- Useful reading: [[Query Properties]] and [[Placeholders]]
- `folder (regex matches|regex does not match) /<JavaScript-style Regex>/`
- Does regular expression match (case-sensitive by default).
- Essential reading: [[Regular Expressions|Regular Expression Searches]].
Expand All @@ -1044,7 +1059,12 @@ Since Tasks 4.2.0, **[[Custom Filters|custom filtering]] by folder** is now poss
- Find tasks in files in any file in the given folder **only**, and not any sub-folders.
- The equality test, `===`, requires that the trailing slash (`/`) be included.
- ```filter by function task.file.folder.includes("Work/Projects/")```
- Find tasks in files in any folder **and any sub-folders**.
- Find tasks in files in a specific folder **and any sub-folders**.
- ```filter by function task.file.folder.includes( '{{query.file.folder}}' )```
- Find tasks in files in the folder that contains the query **and any sub-folders**.
- Note that the placeholder text is expanded to a raw string, so needs to be inside quotes.
- ```filter by function task.file.folder === '{{query.file.folder}}'```
- Find tasks in files in the folder that contains the query only (**not tasks in any sub-folders**).
- ```filter by function task.file.folder.includes("Work/Projects")```
- By leaving off the trailing slash (`/`) this would also find tasks in any file inside folders such as:
- `Work/Projects 2023/`
Expand All @@ -1055,12 +1075,17 @@ Since Tasks 4.2.0, **[[Custom Filters|custom filtering]] by folder** is now poss
### File Name

> [!released]
Introduced in Tasks 1.13.0.
>
> - Introduced in Tasks 3.4.0.
> - Placeholders were released in Tasks X.Y.Z.
Note that the file name includes the `.md` extension.

- `filename (includes|does not include) <filename>`
- Matches case-insensitive (disregards capitalization).
- Use `{{query.file.filename}}` as a placeholder for the file name of the file containing the current query.
- For example, `filename includes {{query.file.filename}}`
- Useful reading: [[Query Properties]] and [[Placeholders]]
- `filename (regex matches|regex does not match) /<JavaScript-style Regex>/`
- Does regular expression match (case-sensitive by default).
- Essential reading: [[Regular Expressions|Regular Expression Searches]].
Expand Down
29 changes: 29 additions & 0 deletions docs/Queries/Grouping.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,20 @@ Since Tasks 4.0.0, **[[Custom Grouping|custom grouping]] by file path** is now p

- ```group by function task.file.path```
- Like 'group by path' but includes the file extension.
- ```group by function task.file.path.replace('{{query.file.folder}}', '')```
- Group by the task's file path, but remove the query's folder from the group.
- For tasks in the query's folder or a sub-folder, this is a nice way of seeing shortened paths.
- Note that the placeholder text is expanded to a raw string, so needs to be inside quotes.
- This is provided to give ideas: it's a bit of a lazy implementation, as it doesn't check that `'{{query.file.folder}}'` is at the start of the line.

<!-- placeholder to force blank line after included text --><!-- endInclude -->

Since Tasks X.Y.Z, the query's file path can be used in custom groups.

- It must be quoted: `'{{query.file.folder}}'`
- Beware if using placeholder text in regular expressions: Any special characters in filenames would need to be escaped.
- Useful reading: [[Query Properties]] and [[Placeholders]].

### Root

- `group by root` (the top-level folder of the file that contains the task, that is, the first directory in the path, which will be `/` for files in root of the vault)
Expand All @@ -541,6 +552,12 @@ Since Tasks 4.0.0, **[[Custom Grouping|custom grouping]] by root folder** is now

<!-- placeholder to force blank line after included text --><!-- endInclude -->

Since Tasks X.Y.Z, the query's file root can be used in custom groups.

- It must be quoted: `'{{query.file.root}}'`
- Beware if using placeholder text in regular expressions: Any special characters in filenames would need to be escaped.
- Useful reading: [[Query Properties]] and [[Placeholders]].

### Folder

- `group by folder` (the folder to the file that contains the task, which always ends in `/` and will be exactly `/` for files in root of the vault)
Expand All @@ -561,6 +578,12 @@ Since Tasks 4.0.0, **[[Custom Grouping|custom grouping]] by folder** is now poss

<!-- placeholder to force blank line after included text --><!-- endInclude -->

Since Tasks X.Y.Z, the query's folder can be used in custom groups.

- It must be quoted: `'{{query.file.folder}}'`
- Beware if using placeholder text in regular expressions: Any special characters in filenames would need to be escaped.
- Useful reading: [[Query Properties]] and [[Placeholders]].

### File Name

- `group by filename` (the link to the file that contains the task, without the `.md` extension)
Expand All @@ -577,6 +600,12 @@ Since Tasks 4.0.0, **[[Custom Grouping|custom grouping]] by file name** is now p

<!-- placeholder to force blank line after included text --><!-- endInclude -->

Since Tasks X.Y.Z, the query's file name can be used in custom groups.

- It must be quoted: `'{{query.file.filename}}'`
- Beware if using placeholder text in regular expressions: Any special characters in filenames would need to be escaped.
- Useful reading: [[Query Properties]] and [[Placeholders]].

### Backlink

- `group by backlink` (the text that would be shown in the task's [[Backlinks|backlink]], combining the task's file name and heading, but with no link added)
Expand Down
Loading

0 comments on commit 8237ef0

Please sign in to comment.