Repository: obsidian-tasks-group/obsidian-tasks
Pull request #3028 (2024-08-12 11:50:50)

feat: Teach Auto Suggest to support  "On Completion"
# Types of changes

Changes visible to users:

- [x] **New feature** (prefix: `feat` - non-breaking change which adds functionality)
  - Issue/discussion: #2840
- [x] **Documentation** (prefix: `docs` - improvements to any documentation content **for users**)

Internal changes:

- [x] **Tests** (prefix: `test` - additions and improvements to unit tests and the smoke tests)

## Description

- Teach Auto Suggest to support the 'On Completion' feature.
- Update docs accordingly

## Motivation and Context

Getting ready to release #2840

## How has this been tested?

- Automated tests
- Exploratory testing

## Screenshots (if appropriate)



![image](https://github.com/user-attachments/assets/d66fff41-3576-4df3-aaa9-96a0d4a028ec)

![image](https://github.com/user-attachments/assets/b1dc5994-f471-4b6f-b936-4cab770403f5)


## Checklist

- [x] My code follows the code style of this project and passes `yarn run lint`.
- [x] My change requires a change to the documentation.
- [x] I have [updated the documentation](https://publish.obsidian.md/tasks-contributing/Documentation/About+Documentation) accordingly.
- [x] My change has adequate [Unit Test coverage](https://publish.obsidian.md/tasks-contributing/Testing/About+Testing).

## Terms

- [x] My contribution follows this project's [contributing guide](https://publish.obsidian.md/tasks-contributing)
- [x] I agree to follow this project's [Code of Conduct](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/CODE_OF_CONDUCT.md)



Patch:
diff --git a/docs/Editing/Auto-Suggest.md b/docs/Editing/Auto-Suggest.md
index fc716537..2bdd0c9b 100644
--- a/docs/Editing/Auto-Suggest.md
+++ b/docs/Editing/Auto-Suggest.md
@@ -11,7 +11,7 @@ aliases:
 > [!released]
 Introduced in Tasks 1.9.0.
 
-The [[Priority|Priorities]], [[Dates]], [[Recurring Tasks]] and [[Task Dependencies]] pages show various emojis and special phrases that the Tasks plugin recognises, when searching for tasks.
+The [[Priority|Priorities]], [[Dates]], [[Recurring Tasks]], [[Task Dependencies]] and [[On Completion]] pages show various emojis and special phrases that the Tasks plugin recognises, when searching for tasks.
 
 If you prefer to type your tasks, instead of using a dialog, there is now an intelligent auto-suggest completion mechanism that does a
 lot of the typing of emojis and dates for you.
@@ -242,6 +242,7 @@ Similarly, you can type some fraction of the word `start` (of whatever length is
 | ➕ created today (2022-07-11) | ➕ 2022-07-11  |
 | 🆔 id | 🆔  |
 | ⛔ depends on id | ⛔  |
+| 🏁 on completion | 🏁  |
 | every | 🔁 every  |
 | every day | 🔁 every day  |
 | every week | 🔁 every week  |
@@ -291,6 +292,8 @@ Similarly, you can type some fraction of the word `start` (of whatever length is
 | next week (2022-07-18) | 🛫 2022-07-18  |
 | next month (2022-08-11) | 🛫 2022-08-11  |
 | next year (2023-07-11) | 🛫 2023-07-11  |
+| delete | 🏁 delete  |
+| keep | 🏁 keep  |
 | generate unique id | 🆔 ******  |
 <!-- endInclude -->
 
diff --git a/docs/Getting Started/On Completion.md b/docs/Getting Started/On Completion.md
index 575ae822..bc819fe1 100644
--- a/docs/Getting Started/On Completion.md
+++ b/docs/Getting Started/On Completion.md
@@ -70,6 +70,6 @@ At present, these "On Completion" ***actions*** are supported:
 
 ## Assigning and changing a given task's "On Completion" action
 
-At present, the "On Completion" signifier and desired **Action** identifier have to be added to a task manually.
+The "On Completion" signifier and desired **Action** identifier can be added with [[Auto-Suggest]], to save typing them manually.
 
-In recognition that this could be both tedious and error-prone, we will eventually enable the [[Create or edit Task|'Create or Edit Task' modal dialog]] to edit the "On Completion" **Action**.
+We will also eventually enable the [[Create or edit Task|'Create or Edit Task' modal dialog]] to edit the "On Completion" **Action**.
diff --git a/src/Suggestor/Suggestor.ts b/src/Suggestor/Suggestor.ts
index 2471cb47..ec6de5a4 100644
--- a/src/Suggestor/Suggestor.ts
+++ b/src/Suggestor/Suggestor.ts
@@ -92,6 +92,11 @@ export function makeDefaultSuggestionBuilder(
             );
         }
 
+        // add on completion suggestions if relevant
+        suggestions = suggestions.concat(
+            addOnCompletionOptionSuggestions(symbols.onCompletionSymbol, maxGenericSuggestions, parameters),
+        );
+
         // add task property suggestions ('due', 'recurrence' etc)
         suggestions = suggestions.concat(addTaskPropertySuggestions(symbols, canSaveEdits, parameters));
 
@@ -156,6 +161,8 @@ function addTaskPropertySuggestions(
         addField(genericSuggestions, line, symbols.dependsOnSymbol, 'depends on id');
     }
 
+    addField(genericSuggestions, line, symbols.onCompletionSymbol, 'on completion');
+
     const matchingSuggestions = filterGeneralSuggestionsForWordAtCursor(genericSuggestions, parameters);
 
     // That's where we're adding all the suggestions in case there's nothing specific to match
@@ -410,6 +417,30 @@ function addRecurrenceValueSuggestions(recurrenceSymbol: string, parameters: Sug
     return results;
 }
 
+/*
+ * If the cursor is located in a section that should be followed by an OnCompletion action, suggest options
+ * for what to enter as the action.
+ */
+function addOnCompletionOptionSuggestions(
+    symbol: string,
+    maxGenericSuggestions: number,
+    parameters: SuggestorParameters,
+) {
+    const genericSuggestions = ['delete', 'keep'];
+
+    const results: SuggestInfo[] = [];
+    const regex = new RegExp(`(${symbol})\\s*([0-9a-zA-Z ]*)`, 'ug');
+    const match = matchIfCursorInRegex(regex, parameters);
+    if (match && match.length >= 2) {
+        const typedText = match[2];
+        if (typedText.length < parameters.settings.autoSuggestMinMatch) return [];
+
+        const genericMatches = filterGenericSuggestions(genericSuggestions, typedText, maxGenericSuggestions, true);
+        constructSuggestions(parameters, match, genericMatches, defaultExtractor, results);
+    }
+    return results;
+}
+
 function addIDSuggestion(idSymbol: string, allTasks: Task[], parameters: SuggestorParameters) {
     const results: SuggestInfo[] = [];
     const idRegex = new RegExp(`(${idSymbol})\\s*(${taskIdRegex.source})?`, 'ug');


Test patch:
diff --git a/tests/Suggestor/Suggestor.test.auto-complete_with__dataview__symbols_offers_basic_completion_options_for_an_empty_task.approved.json b/tests/Suggestor/Suggestor.test.auto-complete_with__dataview__symbols_offers_basic_completion_options_for_an_empty_task.approved.json
index 88230c45..2ea89e20 100644
--- a/tests/Suggestor/Suggestor.test.auto-complete_with__dataview__symbols_offers_basic_completion_options_for_an_empty_task.approved.json
+++ b/tests/Suggestor/Suggestor.test.auto-complete_with__dataview__symbols_offers_basic_completion_options_for_an_empty_task.approved.json
@@ -53,5 +53,9 @@
   {
     "displayText": "dependsOn:: depends on id",
     "appendText": "dependsOn:: "
+  },
+  {
+    "displayText": "onCompletion:: on completion",
+    "appendText": "onCompletion:: "
   }
 ]
diff --git a/tests/Suggestor/Suggestor.test.auto-complete_with__dataview__symbols_show_all_suggested_text.approved.md b/tests/Suggestor/Suggestor.test.auto-complete_with__dataview__symbols_show_all_suggested_text.approved.md
index 11543075..6610ae58 100644
--- a/tests/Suggestor/Suggestor.test.auto-complete_with__dataview__symbols_show_all_suggested_text.approved.md
+++ b/tests/Suggestor/Suggestor.test.auto-complete_with__dataview__symbols_show_all_suggested_text.approved.md
@@ -12,6 +12,7 @@
 | created:: created today (2022-07-11) | created:: 2022-07-11]  |
 | id:: id | id::  |
 | dependsOn:: depends on id | dependsOn::  |
+| onCompletion:: on completion | onCompletion::  |
 | every | repeat:: every]  |
 | every day | repeat:: every day]  |
 | every week | repeat:: every week]  |
@@ -61,4 +62,6 @@
 | next week (2022-07-18) | start:: 2022-07-18]  |
 | next month (2022-08-11) | start:: 2022-08-11]  |
 | next year (2023-07-11) | start:: 2023-07-11]  |
+| delete | onCompletion:: delete]  |
+| keep | onCompletion:: keep]  |
 | generate unique id | id:: ******]  |
diff --git a/tests/Suggestor/Suggestor.test.auto-complete_with__emoji__symbols_offers_basic_completion_options_for_an_empty_task.approved.json b/tests/Suggestor/Suggestor.test.auto-complete_with__emoji__symbols_offers_basic_completion_options_for_an_empty_task.approved.json
index 1c0567b9..ef887cd4 100644
--- a/tests/Suggestor/Suggestor.test.auto-complete_with__emoji__symbols_offers_basic_completion_options_for_an_empty_task.approved.json
+++ b/tests/Suggestor/Suggestor.test.auto-complete_with__emoji__symbols_offers_basic_completion_options_for_an_empty_task.approved.json
@@ -52,5 +52,9 @@
   {
     "displayText": "⛔ depends on id",
     "appendText": "⛔ "
+  },
+  {
+    "displayText": "🏁 on completion",
+    "appendText": "🏁 "
   }
 ]
diff --git a/tests/Suggestor/Suggestor.test.auto-complete_with__emoji__symbols_show_all_suggested_text.approved.md b/tests/Suggestor/Suggestor.test.auto-complete_with__emoji__symbols_show_all_suggested_text.approved.md
index 0b42b9d6..1e84f272 100644
--- a/tests/Suggestor/Suggestor.test.auto-complete_with__emoji__symbols_show_all_suggested_text.approved.md
+++ b/tests/Suggestor/Suggestor.test.auto-complete_with__emoji__symbols_show_all_suggested_text.approved.md
@@ -13,6 +13,7 @@
 | ➕ created today (2022-07-11) | ➕ 2022-07-11  |
 | 🆔 id | 🆔  |
 | ⛔ depends on id | ⛔  |
+| 🏁 on completion | 🏁  |
 | every | 🔁 every  |
 | every day | 🔁 every day  |
 | every week | 🔁 every week  |
@@ -62,4 +63,6 @@
 | next week (2022-07-18) | 🛫 2022-07-18  |
 | next month (2022-08-11) | 🛫 2022-08-11  |
 | next year (2023-07-11) | 🛫 2023-07-11  |
+| delete | 🏁 delete  |
+| keep | 🏁 keep  |
 | generate unique id | 🆔 ******  |
diff --git a/tests/Suggestor/Suggestor.test.ts b/tests/Suggestor/Suggestor.test.ts
index 1d1eae8a..f7755b3a 100644
--- a/tests/Suggestor/Suggestor.test.ts
+++ b/tests/Suggestor/Suggestor.test.ts
@@ -219,6 +219,7 @@ ${JSON.stringify(suggestions[0], null, 4)}
         recurrenceSymbol,
         idSymbol,
         dependsOnSymbol,
+        onCompletionSymbol,
     } = symbols;
 
     it('offers basic completion options for an empty task', () => {
@@ -271,6 +272,11 @@ ${JSON.stringify(suggestions[0], null, 4)}
         verifyFirstSuggestions(lines, 'How due date suggestions are affected by what the user has typed:');
     });
 
+    it('offers OnCompletion completions', () => {
+        const line = `- [ ] some task ${onCompletionSymbol}`;
+        shouldStartWithSuggestionsEqualling(line, ['delete', 'keep']);
+    });
+
     it('respects the minimal match setting', () => {
         // Arrange
         const originalSettings = getSettings();
@@ -473,12 +479,15 @@ ${JSON.stringify(suggestions[0], null, 4)}
         const originalSettings = getSettings();
         originalSettings.autoSuggestMaxItems = 200;
 
+        // NEW_TASK_FIELD_EDIT_REQUIRED
+
         const lines = [
             '- [ ] some task',
             `- [ ] some task ${recurrenceSymbol} `,
             `- [ ] some task ${dueDateSymbol} `,
             `- [ ] some task ${scheduledDateSymbol} `,
             `- [ ] some task ${startDateSymbol} `,
+            `- [ ] some task ${onCompletionSymbol} `,
         ];
         if (global.SHOW_DEPENDENCY_SUGGESTIONS) {
             lines.push(`- [ ] some task ${idSymbol} `);