Skip to content

Strip ANSI color codes from output file while keeping console colors#2293

Merged
Mzack9999 merged 4 commits intoprojectdiscovery:devfrom
ayanrajpoot10:dev
Oct 20, 2025
Merged

Strip ANSI color codes from output file while keeping console colors#2293
Mzack9999 merged 4 commits intoprojectdiscovery:devfrom
ayanrajpoot10:dev

Conversation

@ayanrajpoot10
Copy link
Contributor

@ayanrajpoot10 ayanrajpoot10 commented Oct 16, 2025

This PR adds support for removing ANSI color codes from output files while still allowing colored output in the console.

  • Users now get clean output files without "garbage" ANSI codes, improving readability.
  • Console output retains colors, so users can still see colorized results in real time.
  • Before, users had to use the -nc flag to remove ANSI codes, but this also turned off console colors. There was no way to remove the codes while keeping colored console output.
  • Minimal performance impact: users with -nc see zero impact, and stripping ANSI codes adds only a small cost for colored lines.

Summary by CodeRabbit

  • Bug Fixes
    • Plain-text outputs no longer include stray ANSI escape sequences when color is disabled, improving readability across primary output paths.
    • Colored output remains unchanged when enabled; JSON and CSV outputs are unaffected.

@coderabbitai
Copy link

coderabbitai bot commented Oct 16, 2025

Walkthrough

Adds an internal ANSI escape-code remover to the runner package and uses a conditional wrapper to strip ANSI sequences from plain text output when the NoColor option is set; JSON/CSV outputs and public APIs are unchanged. (33 words)

Changes

Cohort / File(s) Summary
ANSI handling / runner
runner/runner.go
Added package-level precompiled regex ansiRegex; added stripANSI(str string) string; added wrapper handleStripAnsiCharacters(data string, skip bool) string that conditionally strips based on the NoColor flag; replaced direct plain-output writes of resp.str with handleStripAnsiCharacters(resp.str, r.options.NoColor).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Runner
    participant Formatter
    participant Handler as handleStripAnsiCharacters()
    participant stripANSI as stripANSI()
    participant Output

    Runner->>Formatter: Prepare response (resp.str)
    alt Plain text output (NoColor=true)
        Formatter->>Handler: handleStripAnsiCharacters(resp.str, true)
        Handler->>stripANSI: stripANSI(resp.str)
        stripANSI-->>Handler: cleaned string
        Handler-->>Formatter: cleaned string
        Formatter->>Output: write cleaned string
    else Plain text output (NoColor=false)
        Formatter->>Handler: handleStripAnsiCharacters(resp.str, false)
        Handler-->>Formatter: original resp.str
        Formatter->>Output: write original resp.str
    else JSON/CSV output path
        Formatter->>Output: write raw resp.str (no stripping)
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰
I hop through lines and nibble ANSI away,
A tidy regex clearing colors from play.
When plain is required I quietly mend,
Leaving outputs neat from end to end. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Strip ANSI color codes from output file while keeping console colors" is fully related to the main change in the changeset. The summary shows the PR adds functionality to remove ANSI escape codes from output files (via the stripANSI utility and handleStripAnsiCharacters wrapper) while preserving console colors. The title is concise, clear, and accurately captures the primary objective without being vague or misleading. A developer scanning the repository history would immediately understand that this change addresses output file formatting while maintaining console color output.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 0

🧹 Nitpick comments (2)
runner/runner.go (2)

104-105: LGTM! Efficient use of precompiled regex.

The precompiled ANSI regex pattern correctly matches standard SGR (Select Graphic Rendition) escape sequences for color codes, which is appropriate for the stated use case of removing colors from file output.

Optional enhancement: Consider adding a comment explaining the regex pattern for maintainability:

+// ansiRegex matches ANSI SGR (Select Graphic Rendition) escape sequences
+// Pattern: ESC [ <params> m where params are digits/semicolons
 var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`)

Note: The current pattern covers standard color codes but doesn't match cursor movement or other non-SGR sequences, which is acceptable for this use case.


2710-2713: LGTM! Clean implementation with efficient regex usage.

The stripANSI function correctly uses the precompiled regex for optimal performance. The implementation is straightforward and thread-safe.

Recommended enhancement: Add unit tests to verify ANSI stripping behavior:

func TestStripANSI(t *testing.T) {
    tests := []struct {
        input    string
        expected string
    }{
        {"plain text", "plain text"},
        {"\x1b[31mred text\x1b[0m", "red text"},
        {"\x1b[1;32mbold green\x1b[0m", "bold green"},
        {"mixed \x1b[31mred\x1b[0m text", "mixed red text"},
    }
    for _, tt := range tests {
        if got := stripANSI(tt.input); got != tt.expected {
            t.Errorf("stripANSI(%q) = %q, want %q", tt.input, got, tt.expected)
        }
    }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f94f72d and 6d38be3.

📒 Files selected for processing (1)
  • runner/runner.go (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Test Builds (macOS-latest)
  • GitHub Check: Test Builds (windows-latest)
  • GitHub Check: Test Builds (ubuntu-latest)
  • GitHub Check: Functional Test (windows-latest)
  • GitHub Check: Analyze (go)
  • GitHub Check: Functional Test (ubuntu-latest)
  • GitHub Check: Functional Test (macOS-latest)
  • GitHub Check: release-test
🔇 Additional comments (1)
runner/runner.go (1)

1186-1190: LGTM! Logic correctly handles ANSI stripping for file output.

The conditional logic properly achieves the PR objective:

  • When colors are enabled (NoColor=false): Console output remains colorized via resp.str, while file output is cleaned by stripping ANSI codes
  • When colors are disabled (NoColor=true): Both console and file output contain no ANSI codes (no stripping needed)

This implementation successfully addresses the issue where users previously had to disable console colors to get clean file output.

@Mzack9999 Mzack9999 self-requested a review October 19, 2025 15:47
@ayanrajpoot10
Copy link
Contributor Author

@Mzack9999
If we keep this if condition:

if r.options.NoColor {
    plainFile.WriteString(resp.str + "\n")
} else {
    plainFile.WriteString(stripANSI(resp.str) + "\n")
}

it saves an unnecessary call to stripANSI when the user is using the -nc flag.

@Mzack9999
Copy link
Member

@ayanrajpoot10 Thanks for pointing out the optimization. I've summarized it into an helper function

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: 0

🧹 Nitpick comments (1)
runner/runner.go (1)

1351-1356: Consider improving clarity with better naming or inlining.

The logic is correct and implements the optimization from the PR comments. However, the function and parameter names could be clearer:

  • handleStripAnsiCharactersstripANSIConditionally or maybeStripANSI
  • skipnoColor or skipStripping

Alternatively, you could inline this at the call site as originally suggested in the PR comments, which would be equally clear:

-				plainFile.WriteString(handleStripAnsiCharacters(resp.str, r.options.NoColor) + "\n")
+				if r.options.NoColor {
+					plainFile.WriteString(resp.str + "\n")
+				} else {
+					plainFile.WriteString(stripANSI(resp.str) + "\n")
+				}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d1a326 and dfcc970.

📒 Files selected for processing (1)
  • runner/runner.go (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Test Builds (windows-latest)
  • GitHub Check: Test Builds (ubuntu-latest)
  • GitHub Check: Test Builds (macOS-latest)
  • GitHub Check: Analyze (go)
  • GitHub Check: Functional Test (windows-latest)
  • GitHub Check: Functional Test (macOS-latest)
  • GitHub Check: Functional Test (ubuntu-latest)
🔇 Additional comments (3)
runner/runner.go (3)

104-105: LGTM! Good use of package-level precompiled regex.

The ANSI regex pattern correctly matches SGR color codes and is precompiled for efficient reuse across all file writes.


1186-1186: Correct implementation with optimization in place.

The ANSI stripping is properly applied only to file output while preserving console colors. The optimization suggested in the PR comments (skipping the strip operation when -nc is used) is correctly implemented here.


2713-2716: LGTM! Clean implementation.

The function correctly uses the precompiled regex to strip ANSI codes. The implementation is simple, efficient, and well-documented.

@Mzack9999 Mzack9999 merged commit e069771 into projectdiscovery:dev Oct 20, 2025
14 checks passed
@Mzack9999 Mzack9999 linked an issue Oct 20, 2025 that may be closed by this pull request
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.

Strip ANSI color codes from output file while keeping console colors

2 participants