Skip to content

Add configurable context tag prefix with documentation#45

Merged
tavva merged 5 commits intobetafrom
feature/configurable-context-tag-prefix
Feb 19, 2026
Merged

Add configurable context tag prefix with documentation#45
tavva merged 5 commits intobetafrom
feature/configurable-context-tag-prefix

Conversation

@tavva
Copy link
Owner

@tavva tavva commented Feb 19, 2026

Summary

  • Context tag prefix (#context/...) is now configurable via Settings — users can change it to #at/..., #ctx/..., or any other prefix
  • extractContexts() accepts a prefix parameter, threaded through from settings at all call sites
  • WaitingForScanner now receives PluginSettings in its constructor to access the prefix
  • New "Context Tags" section in README explains the feature with examples
  • Settings UI field with description that serves as inline documentation

Addresses feedback from @DanValnicek in #37 — context tags are now documented and the prefix is configurable.

Test plan

  • 4 new tests for custom prefix extraction (case-insensitive, multiple tags, ignores other prefixes)
  • All 862 tests pass
  • Build passes with no type errors
  • Manual: change context tag prefix in settings, verify sphere/waiting-for views use the new prefix

Summary by CodeRabbit

  • New Features

    • Added configurable context tag prefix setting in preferences, allowing users to customize the prefix used for context tags (defaults to "context").
  • Documentation

    • Added Context Tags section to README with usage examples and explanation of how context tags appear as filters.
  • Tests

    • Added test coverage for context tag extraction with custom prefixes.

The context tag prefix (#context/...) is now configurable via settings,
so users can change it to #at/..., #ctx/..., or any other prefix.

Adds a Context Tags section to the README explaining the feature.
Addresses feedback from @DanValnicek in #37 (second item).
@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/configurable-context-tag-prefix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/waiting-for-view.test.ts (1)

1-5: ⚠️ Potential issue | 🟡 Minor

Add ABOUTME header for this test file.

Please prepend two ABOUTME lines describing the test file’s purpose.

✅ Proposed fix
+// ABOUTME: Tests WaitingForView behaviors and state handling.
+// ABOUTME: Validates grouping, completion flow, and filtering logic.
 import { WaitingForView, WAITING_FOR_VIEW_TYPE } from "../src/waiting-for-view";
 import { WorkspaceLeaf, TFile } from "obsidian";
 import { WaitingForScanner, WaitingForItem } from "../src/waiting-for-scanner";
 import { WaitingForValidator } from "../src/waiting-for-validator";
 import { PluginSettings, DEFAULT_SETTINGS } from "../src/types";

As per coding guidelines, Start all source files with two ABOUTME comment lines explaining file purpose.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/waiting-for-view.test.ts` around lines 1 - 5, Prepend two ABOUTME
comment lines at the top of the test file describing its purpose: that it
contains unit tests for WaitingForView behavior (covering WaitingForView and
WAITING_FOR_VIEW_TYPE interactions with WaitingForScanner/WaitingForItem and
WaitingForValidator) and any high-level intent (e.g., verifying view-waiting
logic in various scanner/validator states); add these two single-line comments
immediately before the existing imports so the file begins with two ABOUTME
lines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/context-tags.ts`:
- Around line 4-10: The extractContexts function constructs a RegExp from an
unsanitized user-provided prefix; escape the prefix before interpolation to
prevent invalid regexes or unintended matches. Update extractContexts to
sanitize the prefix (e.g., implement or call an escapeRegExp utility that
escapes all regex metacharacters) and use the escapedPrefix when creating the
RegExp (keeping the same flags and pattern structure
`#${escapedPrefix}\\/([^\\s]+)`). Ensure the escape utility is used anywhere
else user prefixes are interpolated into RegExp to avoid similar issues.

In `@src/waiting-for-scanner.ts`:
- Around line 112-113: extractContexts is constructing a RegExp directly from
the user-configured contextTagPrefix (settings.contextTagPrefix) which can
contain regex metacharacters; update extractContexts to escape the prefix before
building the pattern by running the prefix through
.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") (i.e., let safePrefix =
prefix.replace(...)) and use safePrefix when creating the RegExp so all call
sites (e.g., where extractContexts is invoked from waiting-for-scanner,
sphere-view, sphere-data-loader, someday-scanner) no longer throw or mis-match
on special characters.

In `@tests/waiting-for-scanner.test.ts`:
- Around line 1-3: This test file is missing the required two ABOUTME header
comment lines; open the file containing the WaitingForScanner test (the module
that imports WaitingForScanner, App, TFile, Vault, MetadataCache, CachedMetadata
and DEFAULT_SETTINGS) and prepend two comment lines starting with ABOUTME that
succinctly describe the file’s purpose (e.g., what the test covers and its
scope) so the test file begins with the two ABOUTME header comments as per
coding guidelines.

---

Outside diff comments:
In `@tests/waiting-for-view.test.ts`:
- Around line 1-5: Prepend two ABOUTME comment lines at the top of the test file
describing its purpose: that it contains unit tests for WaitingForView behavior
(covering WaitingForView and WAITING_FOR_VIEW_TYPE interactions with
WaitingForScanner/WaitingForItem and WaitingForValidator) and any high-level
intent (e.g., verifying view-waiting logic in various scanner/validator states);
add these two single-line comments immediately before the existing imports so
the file begins with two ABOUTME lines.

Comment on lines +4 to 10
export function extractContexts(text: string, prefix: string = "context"): string[] {
const pattern = new RegExp(`#${prefix}\\/([^\\s]+)`, "gi");
const contexts: string[] = [];
let match;

while ((match = CONTEXT_TAG_PATTERN.exec(text)) !== null) {
while ((match = pattern.exec(text)) !== null) {
const context = match[1].toLowerCase();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n "contextTagPrefix" -S

Repository: tavva/flow

Length of output: 1422


🏁 Script executed:

rg -n "extractContexts\(" -S

Repository: tavva/flow

Length of output: 4381


🏁 Script executed:

fd "context-tags" --type f

Repository: tavva/flow

Length of output: 183


🏁 Script executed:

cat -n src/context-tags.ts | head -20

Repository: tavva/flow

Length of output: 710


🏁 Script executed:

cat -n tests/context-tags.test.ts

Repository: tavva/flow

Length of output: 2459


🏁 Script executed:

cat -n src/settings-tab.ts | sed -n '270,290p'

Repository: tavva/flow

Length of output: 1009


Escape the user-defined prefix before building the RegExp.

Line 5 interpolates the unsanitized prefix into a RegExp constructor. Users can enter regex metacharacters (e.g., ., (, [) in settings.ts line 280, causing invalid regex or unintended matches. For example, a prefix of context. would match any character before the slash, and context( would throw "Invalid regular expression." Escape or validate the prefix before constructing the pattern.

Proposed fix
 export function extractContexts(text: string, prefix: string = "context"): string[] {
-  const pattern = new RegExp(`#${prefix}\\/([^\\s]+)`, "gi");
+  const safePrefix = prefix.trim().replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+  const pattern = new RegExp(`#${safePrefix}\\/([^\\s]+)`, "gi");
   const contexts: string[] = [];
   let match;
🧰 Tools
🪛 ast-grep (0.40.5)

[warning] 4-4: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(#${prefix}\\/([^\\s]+), "gi")
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/context-tags.ts` around lines 4 - 10, The extractContexts function
constructs a RegExp from an unsanitized user-provided prefix; escape the prefix
before interpolation to prevent invalid regexes or unintended matches. Update
extractContexts to sanitize the prefix (e.g., implement or call an escapeRegExp
utility that escapes all regex metacharacters) and use the escapedPrefix when
creating the RegExp (keeping the same flags and pattern structure
`#${escapedPrefix}\\/([^\\s]+)`). Ensure the escape utility is used anywhere
else user prefixes are interpolated into RegExp to avoid similar issues.

Comment on lines +112 to 113
contexts: extractContexts(lineContent, this.settings.contextTagPrefix),
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether contextTagPrefix is validated or escaped elsewhere
echo "=== Searching for contextTagPrefix usage ==="
rg -n "contextTagPrefix" -S src tests

echo -e "\n=== Searching for extractContexts usage ==="
rg -n "extractContexts" -S src

echo -e "\n=== Searching for existing escape/sanitize functions ==="
rg -n "escapeRegExp|sanitize|validate.*prefix" -S src

Repository: tavva/flow

Length of output: 3451


🏁 Script executed:

cat -n src/context-tags.ts

Repository: tavva/flow

Length of output: 710


Escape contextTagPrefix in extractContexts before building RegExp.

The function in src/context-tags.ts (line 5) builds a RegExp directly from the user-configured prefix without escaping. Since the settings tab only applies .trim() validation (src/settings-tab.ts:280), metacharacters like [, (, +, \ can cause RegExp syntax errors or unintended matching behavior at runtime. This affects all five call sites: src/waiting-for-scanner.ts (lines 112, 157), src/sphere-view.ts (line 819), src/sphere-data-loader.ts (lines 180, 211, 218), and src/someday-scanner.ts (line 99).

Escape the prefix using .replace(/[.*+?^${}()|[\]\\]/g, "\\$&") in extractContexts before building the pattern:

Suggested fix
export function extractContexts(text: string, prefix: string = "context"): string[] {
+  const safePrefix = prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
-  const pattern = new RegExp(`#${prefix}\\/([^\\s]+)`, "gi");
+  const pattern = new RegExp(`#${safePrefix}\\/([^\\s]+)`, "gi");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/waiting-for-scanner.ts` around lines 112 - 113, extractContexts is
constructing a RegExp directly from the user-configured contextTagPrefix
(settings.contextTagPrefix) which can contain regex metacharacters; update
extractContexts to escape the prefix before building the pattern by running the
prefix through .replace(/[.*+?^${}()|[\]\\]/g, "\\$&") (i.e., let safePrefix =
prefix.replace(...)) and use safePrefix when creating the RegExp so all call
sites (e.g., where extractContexts is invoked from waiting-for-scanner,
sphere-view, sphere-data-loader, someday-scanner) no longer throw or mis-match
on special characters.

Comment on lines 1 to +3
import { WaitingForScanner } from "../src/waiting-for-scanner";
import { App, TFile, Vault, MetadataCache, CachedMetadata } from "obsidian";
import { DEFAULT_SETTINGS } from "../src/types";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add ABOUTME header for this test file.

Please prepend two ABOUTME lines describing the test file’s purpose.

✅ Proposed fix
+// ABOUTME: Tests WaitingForScanner scanning for waiting-for items.
+// ABOUTME: Covers sphere/context extraction and text normalization.
 import { WaitingForScanner } from "../src/waiting-for-scanner";
 import { App, TFile, Vault, MetadataCache, CachedMetadata } from "obsidian";
 import { DEFAULT_SETTINGS } from "../src/types";

As per coding guidelines, Start all source files with two ABOUTME comment lines explaining file purpose.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { WaitingForScanner } from "../src/waiting-for-scanner";
import { App, TFile, Vault, MetadataCache, CachedMetadata } from "obsidian";
import { DEFAULT_SETTINGS } from "../src/types";
// ABOUTME: Tests WaitingForScanner scanning for waiting-for items.
// ABOUTME: Covers sphere/context extraction and text normalization.
import { WaitingForScanner } from "../src/waiting-for-scanner";
import { App, TFile, Vault, MetadataCache, CachedMetadata } from "obsidian";
import { DEFAULT_SETTINGS } from "../src/types";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/waiting-for-scanner.test.ts` around lines 1 - 3, This test file is
missing the required two ABOUTME header comment lines; open the file containing
the WaitingForScanner test (the module that imports WaitingForScanner, App,
TFile, Vault, MetadataCache, CachedMetadata and DEFAULT_SETTINGS) and prepend
two comment lines starting with ABOUTME that succinctly describe the file’s
purpose (e.g., what the test covers and its scope) so the test file begins with
the two ABOUTME header comments as per coding guidelines.

Prevents invalid regex or unintended matches when users enter
metacharacters like '.' or '(' in the prefix setting.
Adds missing ABOUTME to waiting-for-scanner test file.
The sphere view strips #sphere/X tags from action text before display.
When other tags (e.g. #ctx/test) follow the sphere tag, the stripped
text is no longer a contiguous substring of the original line, so
ActionLineFinder.findActionLine() couldn't match it.

Fix: strip sphere tags from lines before substring comparison.
@tavva tavva merged commit 1e33d5d into beta Feb 19, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant