Skip to content

Commit

Permalink
Merge pull request #3245 from obsidian-tasks-group/multi-line-placeho…
Browse files Browse the repository at this point in the history
…lders

fix: Allow multi-line properties in {{query.file.property('...')}}
  • Loading branch information
claremacrae authored Dec 22, 2024
2 parents c684472 + 9c78154 commit 09fcd31
Show file tree
Hide file tree
Showing 6 changed files with 370 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ task_instruction: group by filename
task_instructions: |
group by root
group by folder
group by filename
group by filename
# a comment
# an indented comment
task_instructions_with_continuation_line: |
path \
includes query_using_properties
task_instruction_with_spaces: " path includes query_using_properties "
---

# query_using_properties
Expand All @@ -24,15 +30,41 @@ ignore global query
limit 10
```

## Use a one-line property: task_instruction_with_spaces

Read a Tasks instruction **that is surrounded by extra spaces** from a property in this file, and embed it in to any number of queries in the file:

```tasks
explain
ignore global query
{{query.file.property('task_instruction_with_spaces')}}
limit 10
```

## Use a multi-line property: task_instructions

This fails as the `task_instructions` contains multiple lines , and placeholders are applied after the query is split at line-endings...
Read multiple Tasks instructions from a property in this file, and embed them in to any number of queries in the file:

```tasks
ignore global query
folder includes Test Data
explain
{{query.file.property('task_instructions')}}
limit 10
```

## Use a multi-line property: task_instructions_with_continuation_line

Read multiple Tasks instructions with a continuation line from a property in this file, and embed them in to any number of queries in the file.

Continuation lines are currently unsupported in placeholders.

```tasks
ignore global query
folder includes Test Data
explain
{{query.file.property('task_instructions_with_continuation_line')}}
limit 10
```

## Use a list property in a custom filter: root_dirs_to_search
Expand Down
56 changes: 44 additions & 12 deletions src/Query/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,24 @@ export class Query implements IQuery {

this.debug(`Creating query: ${this.formatQueryForLogging()}`);

continueLines(source).forEach((statement: Statement) => {
const line = this.expandPlaceholders(statement, tasksFile);
const anyContinuationLinesRemoved = continueLines(source);

const anyPlaceholdersExpanded: Statement[] = [];
for (const statement of anyContinuationLinesRemoved) {
const expandedStatements = this.expandPlaceholders(statement, tasksFile);
if (this.error !== undefined) {
// There was an error expanding placeholders.
return;
}
anyPlaceholdersExpanded.push(...expandedStatements);
}

for (const statement of anyPlaceholdersExpanded) {
try {
this.parseLine(line, statement);
this.parseLine(statement);
if (this.error !== undefined) {
return;
}
} catch (e) {
let message;
if (e instanceof Error) {
Expand All @@ -77,7 +86,7 @@ export class Query implements IQuery {
this.setError(message, statement);
return;
}
});
}
}

public get filePath(): string | undefined {
Expand All @@ -88,7 +97,8 @@ export class Query implements IQuery {
return this._queryId;
}

private parseLine(line: string, statement: Statement) {
private parseLine(statement: Statement) {
const line = statement.anyPlaceholdersExpanded;
switch (true) {
case this.shortModeRegexp.test(line):
this._queryLayoutOptions.shortMode = true;
Expand Down Expand Up @@ -126,20 +136,19 @@ export class Query implements IQuery {
return `[${this.source.split('\n').join(' ; ')}]`;
}

private expandPlaceholders(statement: Statement, tasksFile: OptionalTasksFile) {
private expandPlaceholders(statement: Statement, tasksFile: OptionalTasksFile): Statement[] {
const source = statement.anyContinuationLinesRemoved;
if (source.includes('{{') && source.includes('}}')) {
if (this.tasksFile === undefined) {
this._error = `The query looks like it contains a placeholder, with "{{" and "}}"
but no file path has been supplied, so cannot expand placeholder values.
The query is:
${source}`;
return source;
return [statement];
}
}

// TODO Do not complain about any placeholder errors in comment lines
// TODO Show the original and expanded text in explanations
// TODO Give user error info if they try and put a string in a regex search
let expandedSource: string = source;
if (tasksFile) {
Expand All @@ -152,13 +161,36 @@ ${source}`;
} else {
this._error = 'Internal error. expandPlaceholders() threw something other than Error.';
}
return source;
return [statement];
}
}

// Save any expanded text back in to the statement:
statement.recordExpandedPlaceholders(expandedSource);
return expandedSource;
return this.createStatementsFromExpandedPlaceholders(expandedSource, statement);
}

private createStatementsFromExpandedPlaceholders(expandedSource: string, statement: Statement) {
// Trim and filter empty lines in one step.
const expandedSourceLines = expandedSource
.split('\n')
.map((line) => line.trim())
.filter((line) => line.length > 0);

if (expandedSourceLines.length === 1) {
// Save the single expanded line back into the statement.
statement.recordExpandedPlaceholders(expandedSourceLines[0]);
return [statement];
}

// Handle multiple-line placeholders.
return expandedSourceLines.map((expandedSourceLine, index) => {
const counter = `: statement ${index + 1} after expansion of placeholder`;
const newStatement = new Statement(
statement.rawInstruction + counter,
statement.anyContinuationLinesRemoved + counter,
);
newStatement.recordExpandedPlaceholders(expandedSourceLine);
return newStatement;
});
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Renderer/QueryRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ export class QueryRenderer {
// not yet available, so empty.
// - It does not listen out for edits the properties, so if a property is edited,
// the user needs to close and re-open the file.
// - Only single-line properties work. Multiple-line properties give an error message
// 'do not understand query'.
// - Multi-line properties are supported, but they cannot contain
// continuation lines.
const app = this.app;
const filePath = context.sourcePath;
const tFile = app.vault.getAbstractFileByPath(filePath);
Expand Down
Loading

0 comments on commit 09fcd31

Please sign in to comment.