Skip to content

Latest commit

 

History

History
158 lines (133 loc) · 5.06 KB

File metadata and controls

158 lines (133 loc) · 5.06 KB

Plan: Fix Whitespace Stripping and Add Syntax Highlighting for Read/Write Output

Problem Statement

  1. Whitespace stripping: When displaying read/write tool output, leading whitespace is being stripped via trim_start() in render_read_output (line 1435 of messages.rs)
  2. No syntax highlighting: The read/write output is displayed with plain styling (theme.code_style()) without language-aware syntax highlighting

Solution

1. Fix Whitespace Stripping (messages.rs)

In render_read_output at line 1434-1438:

// Current (strips whitespace):
let content = if let Some(idx) = line.find('|') {
    line[idx + 1..].trim_start().to_string()  // <-- removes indentation!
} else {
    line.to_string()
};

Change to:

// Fixed (preserves whitespace after the tab separator):
let content = if let Some(idx) = line.find('|') {
    // Skip the '|' and the single tab that follows it, but preserve the rest
    let after_pipe = &line[idx + 1..];
    if after_pipe.starts_with('\t') {
        after_pipe[1..].to_string()
    } else {
        after_pipe.to_string()
    }
} else {
    line.to_string()
};

2. Add Syntax Highlighting for Read/Write Output

2a. Add helper function to extract file extension (syntax.rs)

Add a new function to get language from file path:

/// Get the language/extension from a file path for syntax highlighting.
pub fn language_from_path(path: &str) -> &str {
    std::path::Path::new(path)
        .extension()
        .and_then(|ext| ext.to_str())
        .unwrap_or("")
}

2b. Modify render_read_output to use syntax highlighting (messages.rs)

  1. Extract file path from tool input
  2. Determine language from file extension
  3. Build the content string (without line numbers)
  4. Apply syntax highlighting using highlight_code
  5. Render the highlighted lines with the tool border prefix
fn render_read_output(
    &self,
    lines: &mut Vec<Line<'static>>,
    output_lines: &[&str],
    tool: &DisplayToolCall,
    theme: &Theme,
) {
    let max_lines = if tool.expanded { 100 } else { 10 };
    let total = output_lines.len();

    // Extract file path from input to determine language
    let input: serde_json::Value = tool
        .input
        .as_deref()
        .and_then(|s| serde_json::from_str(s).ok())
        .unwrap_or(serde_json::Value::Null);
    
    let file_path = input.get("filePath").and_then(|v| v.as_str()).unwrap_or("");
    let language = crate::widgets::syntax::language_from_path(file_path);

    // Extract content lines (stripping line number prefix but preserving whitespace)
    let content_lines: Vec<String> = output_lines
        .iter()
        .take(max_lines)
        .map(|line| {
            if let Some(idx) = line.find('|') {
                let after_pipe = &line[idx + 1..];
                if after_pipe.starts_with('\t') {
                    after_pipe[1..].to_string()
                } else {
                    after_pipe.to_string()
                }
            } else {
                line.to_string()
            }
        })
        .collect();

    // Apply syntax highlighting if language is detected
    if !language.is_empty() {
        let code = content_lines.join("\n");
        let highlighted = crate::widgets::syntax::highlight_code(&code, language, theme);
        
        for line in highlighted {
            let mut new_line = vec![Span::styled("  │ ", theme.tool_border_style())];
            new_line.extend(line.spans);
            lines.push(Line::from(new_line));
        }
    } else {
        // Fallback to plain code style
        for content in content_lines {
            let truncated = if content.len() > 70 && !tool.expanded {
                format!("{}...", &content[..67])
            } else {
                content
            };
            lines.push(Line::from(vec![
                Span::styled("  │ ", theme.tool_border_style()),
                Span::styled(truncated, theme.code_style()),
            ]));
        }
    }

    // Show "more lines" indicator
    if total > max_lines {
        lines.push(Line::from(vec![
            Span::styled("  │ ", theme.tool_border_style()),
            Span::styled(
                format!("... {} more lines", total - max_lines),
                theme.dim_style(),
            ),
        ]));
    }

    self.render_expand_hint(lines, tool, total, theme);
}

2c. Similarly update render_write_output (messages.rs)

Apply the same syntax highlighting to write tool preview output.

Files to Modify

  1. crates/wonopcode-tui/src/widgets/syntax.rs

    • Add language_from_path() function
  2. crates/wonopcode-tui/src/widgets/messages.rs

    • Fix whitespace stripping in render_read_output
    • Add syntax highlighting to render_read_output
    • Add syntax highlighting to render_write_output

Testing

After implementation:

  1. Read a file with indentation (e.g., a Rust or Python file) and verify indentation is preserved
  2. Read files of different types (.rs, .py, .js, .json, .yaml) and verify syntax highlighting is applied
  3. Write a file and verify the preview shows syntax highlighting