Skip to content

Fix Rich markup issues with square brackets in user content#137

Merged
holmboe merged 1 commit intomasterfrom
fix/rich-markup-escape-user-content
Mar 2, 2026
Merged

Fix Rich markup issues with square brackets in user content#137
holmboe merged 1 commit intomasterfrom
fix/rich-markup-escape-user-content

Conversation

@holmboe
Copy link
Contributor

@holmboe holmboe commented Feb 21, 2026

Summary

Fixes two related issues where Rich library incorrectly interprets square brackets in user-provided content as markup syntax:

Problem

Rich library treats square brackets [...] as markup syntax for styling/formatting. When user content contains literal square brackets:

  1. Pattern [/text] → Interpreted as closing tag → Crashes with MarkupError
  2. Pattern [word] → Interpreted as invalid tag → Silently removed from display

Example Issues

T525 - Contains file path [/source/kubespray/...]:

Before: Crashed with MarkupError: closing tag '[/source/...]' doesn't match any open tag
After: Displays correctly with literal brackets

T2163 - Title has [bug] prefix:

Before: ' opensearch-operator-controller-manager OOMKilled '  (missing [bug])
After: '[bug] opensearch-operator-controller-manager OOMKilled '  (correct)

Solution

Use rich.markup.escape() to escape all user-provided content while keeping Rich markup enabled for intentional formatting (hyperlinks, bold labels, etc.).

Implementation

  1. Import markup.escape from Rich

  2. Add helper method _escape() to safely escape content:

    • Returns empty string for None
    • Preserves Text objects (already safe Rich objects like hyperlinks)
    • Escapes all other content using escape(str(content))
  3. Escape user content in 30 locations across 2 display methods:

_display_task_yaml() method (15 locations):

  • Task fields (Name, Description, etc.)
  • Board/Project names
  • Column names
  • History transitions
  • Comments
  • Metadata values

_display_task_tree() method (15 locations):

  • Same content types as YAML format
  1. Preserve intentional formatting:

    • Hyperlinks created by self.format_link() return Text objects
    • _escape() checks isinstance(content, Text) and doesn't escape them
    • Rich markup in phabfive's own formatting (bold labels, etc.) still works
  2. Handle combined escaping:

    • Some values need both YAML quote escaping ('') and Rich markup escaping
    • Applied in correct order: YAML escape first, then Rich escape

Testing

# Issue #135 - Should not crash
uv run phabfive --format=rich maniphest show T525
✅ Displays successfully with [/path] patterns visible

# Issue #136 - Should show [bug] prefix  
uv run phabfive --format=rich maniphest show T2163
✅ Shows full title: '[bug] opensearch-operator-controller-manager OOMKilled '

# Search results
uv run phabfive --format=rich maniphest search --tag DYN127-arkitektur
✅ All tasks display correctly with square brackets preserved

# Strict format still works
uv run phabfive --format=strict maniphest show T525
✅ No regression in strict YAML output

Files Changed

  • phabfive/maniphest.py: +55 insertions, -27 deletions
    • Import escape from rich.markup
    • Add _escape() helper method (26 lines)
    • Update 30 print/add statements to escape user content

Impact

Fixes:

Preserves:

  • ✅ Hyperlinks still work (Text objects not escaped)
  • ✅ Rich formatting in phabfive's UI (bold, colors) still works
  • --format=strict unaffected (uses different code path)

Related Issues

Closes #135
Closes #136

🤖 Generated with Claude Code

Fixes #135: MarkupError crash on [/path] patterns
Fixes #136: Silent stripping of [bug] tags from titles

Uses rich.markup.escape() to escape user-provided content while
keeping Rich markup enabled for intentional formatting (hyperlinks,
bold labels, etc.).

Changes:
- Import markup.escape from rich library
- Add _escape() helper method to safely escape user content
- Escape all user content in _display_task_yaml() (15 locations):
  * Task fields (Name, Description, etc.)
  * Board/Column names
  * History transitions
  * Comments
  * Metadata values
- Escape all user content in _display_task_tree() (15 locations):
  * Task fields
  * Board/Column names
  * History transitions
  * Comments
  * Metadata values
- Preserve Text objects (hyperlinks) without escaping
- Combine YAML quote escaping with Rich markup escaping where needed

Testing:
- T525 now displays without crashing (had [/path] patterns)
- T2163 now shows full title with [bug] prefix (was being stripped)
- Search results display correctly
- --format=strict still works as expected

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@holmboe holmboe requested a review from Timpan4 February 21, 2026 00:12
@holmboe holmboe merged commit 47f28e5 into master Mar 2, 2026
15 checks passed
@holmboe holmboe deleted the fix/rich-markup-escape-user-content branch March 2, 2026 12:08
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.

Rich format silently strips square bracket tags from task titles Rich MarkupError when task description contains square brackets

2 participants