tui: drop citation rendering (#4855)
We don't instruct the model to use citations, so it never emits them. Further, ratatui [doesn't currently support rendering links into the terminal with OSC 8](https://github.com/ratatui/ratatui/issues/1028), so even if we did parse citations, we can't correctly render them. So, remove all the code related to rendering them.
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
use codex_core::config::Config;
|
||||
use ratatui::text::Line;
|
||||
|
||||
use crate::markdown;
|
||||
@@ -33,7 +32,7 @@ impl MarkdownStreamCollector {
|
||||
/// Render the full buffer and return only the newly completed logical lines
|
||||
/// since the last commit. When the buffer does not end with a newline, the
|
||||
/// final rendered line is considered incomplete and is not emitted.
|
||||
pub fn commit_complete_lines(&mut self, config: &Config) -> Vec<Line<'static>> {
|
||||
pub fn commit_complete_lines(&mut self) -> Vec<Line<'static>> {
|
||||
let source = self.buffer.clone();
|
||||
let last_newline_idx = source.rfind('\n');
|
||||
let source = if let Some(last_newline_idx) = last_newline_idx {
|
||||
@@ -42,7 +41,7 @@ impl MarkdownStreamCollector {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut rendered: Vec<Line<'static>> = Vec::new();
|
||||
markdown::append_markdown(&source, self.width, &mut rendered, config);
|
||||
markdown::append_markdown(&source, self.width, &mut rendered);
|
||||
let mut complete_line_count = rendered.len();
|
||||
if complete_line_count > 0
|
||||
&& crate::render::line_utils::is_blank_line_spaces_only(
|
||||
@@ -67,7 +66,7 @@ impl MarkdownStreamCollector {
|
||||
/// If the buffer does not end with a newline, a temporary one is appended
|
||||
/// for rendering. Optionally unwraps ```markdown language fences in
|
||||
/// non-test builds.
|
||||
pub fn finalize_and_drain(&mut self, config: &Config) -> Vec<Line<'static>> {
|
||||
pub fn finalize_and_drain(&mut self) -> Vec<Line<'static>> {
|
||||
let raw_buffer = self.buffer.clone();
|
||||
let mut source: String = raw_buffer.clone();
|
||||
if !source.ends_with('\n') {
|
||||
@@ -83,7 +82,7 @@ impl MarkdownStreamCollector {
|
||||
tracing::trace!("markdown finalize (raw source):\n---\n{source}\n---");
|
||||
|
||||
let mut rendered: Vec<Line<'static>> = Vec::new();
|
||||
markdown::append_markdown(&source, self.width, &mut rendered, config);
|
||||
markdown::append_markdown(&source, self.width, &mut rendered);
|
||||
|
||||
let out = if self.committed_line_count >= rendered.len() {
|
||||
Vec::new()
|
||||
@@ -101,18 +100,17 @@ impl MarkdownStreamCollector {
|
||||
pub(crate) fn simulate_stream_markdown_for_tests(
|
||||
deltas: &[&str],
|
||||
finalize: bool,
|
||||
config: &Config,
|
||||
) -> Vec<Line<'static>> {
|
||||
let mut collector = MarkdownStreamCollector::new(None);
|
||||
let mut out = Vec::new();
|
||||
for d in deltas {
|
||||
collector.push_delta(d);
|
||||
if d.contains('\n') {
|
||||
out.extend(collector.commit_complete_lines(config));
|
||||
out.extend(collector.commit_complete_lines());
|
||||
}
|
||||
}
|
||||
if finalize {
|
||||
out.extend(collector.finalize_and_drain(config));
|
||||
out.extend(collector.finalize_and_drain());
|
||||
}
|
||||
out
|
||||
}
|
||||
@@ -120,45 +118,30 @@ pub(crate) fn simulate_stream_markdown_for_tests(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::ConfigOverrides;
|
||||
use ratatui::style::Color;
|
||||
|
||||
async fn test_config() -> Config {
|
||||
let overrides = ConfigOverrides {
|
||||
cwd: std::env::current_dir().ok(),
|
||||
..Default::default()
|
||||
};
|
||||
Config::load_with_cli_overrides(vec![], overrides)
|
||||
.await
|
||||
.expect("load test config")
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn no_commit_until_newline() {
|
||||
let cfg = test_config().await;
|
||||
let mut c = super::MarkdownStreamCollector::new(None);
|
||||
c.push_delta("Hello, world");
|
||||
let out = c.commit_complete_lines(&cfg);
|
||||
let out = c.commit_complete_lines();
|
||||
assert!(out.is_empty(), "should not commit without newline");
|
||||
c.push_delta("!\n");
|
||||
let out2 = c.commit_complete_lines(&cfg);
|
||||
let out2 = c.commit_complete_lines();
|
||||
assert_eq!(out2.len(), 1, "one completed line after newline");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn finalize_commits_partial_line() {
|
||||
let cfg = test_config().await;
|
||||
let mut c = super::MarkdownStreamCollector::new(None);
|
||||
c.push_delta("Line without newline");
|
||||
let out = c.finalize_and_drain(&cfg);
|
||||
let out = c.finalize_and_drain();
|
||||
assert_eq!(out.len(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn e2e_stream_blockquote_simple_is_green() {
|
||||
let cfg = test_config().await;
|
||||
let out = super::simulate_stream_markdown_for_tests(&["> Hello\n"], true, &cfg);
|
||||
let out = super::simulate_stream_markdown_for_tests(&["> Hello\n"], true);
|
||||
assert_eq!(out.len(), 1);
|
||||
let l = &out[0];
|
||||
assert_eq!(
|
||||
@@ -171,9 +154,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn e2e_stream_blockquote_nested_is_green() {
|
||||
let cfg = test_config().await;
|
||||
let out =
|
||||
super::simulate_stream_markdown_for_tests(&["> Level 1\n>> Level 2\n"], true, &cfg);
|
||||
let out = super::simulate_stream_markdown_for_tests(&["> Level 1\n>> Level 2\n"], true);
|
||||
// Filter out any blank lines that may be inserted at paragraph starts.
|
||||
let non_blank: Vec<_> = out
|
||||
.into_iter()
|
||||
@@ -196,9 +177,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn e2e_stream_blockquote_with_list_items_is_green() {
|
||||
let cfg = test_config().await;
|
||||
let out =
|
||||
super::simulate_stream_markdown_for_tests(&["> - item 1\n> - item 2\n"], true, &cfg);
|
||||
let out = super::simulate_stream_markdown_for_tests(&["> - item 1\n> - item 2\n"], true);
|
||||
assert_eq!(out.len(), 2);
|
||||
assert_eq!(out[0].style.fg, Some(Color::Green));
|
||||
assert_eq!(out[1].style.fg, Some(Color::Green));
|
||||
@@ -206,7 +185,6 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn e2e_stream_nested_mixed_lists_ordered_marker_is_light_blue() {
|
||||
let cfg = test_config().await;
|
||||
let md = [
|
||||
"1. First\n",
|
||||
" - Second level\n",
|
||||
@@ -214,7 +192,7 @@ mod tests {
|
||||
" - Fourth level (bullet)\n",
|
||||
" - Fifth level to test indent consistency\n",
|
||||
];
|
||||
let out = super::simulate_stream_markdown_for_tests(&md, true, &cfg);
|
||||
let out = super::simulate_stream_markdown_for_tests(&md, true);
|
||||
// Find the line that contains the third-level ordered text
|
||||
let find_idx = out.iter().position(|l| {
|
||||
l.spans
|
||||
@@ -238,9 +216,8 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn e2e_stream_blockquote_wrap_preserves_green_style() {
|
||||
let cfg = test_config().await;
|
||||
let long = "> This is a very long quoted line that should wrap across multiple columns to verify style preservation.";
|
||||
let out = super::simulate_stream_markdown_for_tests(&[long, "\n"], true, &cfg);
|
||||
let out = super::simulate_stream_markdown_for_tests(&[long, "\n"], true);
|
||||
// Wrap to a narrow width to force multiple output lines.
|
||||
let wrapped =
|
||||
crate::wrapping::word_wrap_lines(out.iter(), crate::wrapping::RtOptions::new(24));
|
||||
@@ -274,13 +251,11 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn heading_starts_on_new_line_when_following_paragraph() {
|
||||
let cfg = test_config().await;
|
||||
|
||||
// Stream a paragraph line, then a heading on the next line.
|
||||
// Expect two distinct rendered lines: "Hello." and "Heading".
|
||||
let mut c = super::MarkdownStreamCollector::new(None);
|
||||
c.push_delta("Hello.\n");
|
||||
let out1 = c.commit_complete_lines(&cfg);
|
||||
let out1 = c.commit_complete_lines();
|
||||
let s1: Vec<String> = out1
|
||||
.iter()
|
||||
.map(|l| {
|
||||
@@ -300,7 +275,7 @@ mod tests {
|
||||
);
|
||||
|
||||
c.push_delta("## Heading\n");
|
||||
let out2 = c.commit_complete_lines(&cfg);
|
||||
let out2 = c.commit_complete_lines();
|
||||
let s2: Vec<String> = out2
|
||||
.iter()
|
||||
.map(|l| {
|
||||
@@ -331,19 +306,17 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn heading_not_inlined_when_split_across_chunks() {
|
||||
let cfg = test_config().await;
|
||||
|
||||
// Paragraph without trailing newline, then a chunk that starts with the newline
|
||||
// and the heading text, then a final newline. The collector should first commit
|
||||
// only the paragraph line, and later commit the heading as its own line.
|
||||
let mut c = super::MarkdownStreamCollector::new(None);
|
||||
c.push_delta("Sounds good!");
|
||||
// No commit yet
|
||||
assert!(c.commit_complete_lines(&cfg).is_empty());
|
||||
assert!(c.commit_complete_lines().is_empty());
|
||||
|
||||
// Introduce the newline that completes the paragraph and the start of the heading.
|
||||
c.push_delta("\n## Adding Bird subcommand");
|
||||
let out1 = c.commit_complete_lines(&cfg);
|
||||
let out1 = c.commit_complete_lines();
|
||||
let s1: Vec<String> = out1
|
||||
.iter()
|
||||
.map(|l| {
|
||||
@@ -362,7 +335,7 @@ mod tests {
|
||||
|
||||
// Now finish the heading line with the trailing newline.
|
||||
c.push_delta("\n");
|
||||
let out2 = c.commit_complete_lines(&cfg);
|
||||
let out2 = c.commit_complete_lines();
|
||||
let s2: Vec<String> = out2
|
||||
.iter()
|
||||
.map(|l| {
|
||||
@@ -381,7 +354,7 @@ mod tests {
|
||||
|
||||
// Sanity check raw markdown rendering for a simple line does not produce spurious extras.
|
||||
let mut rendered: Vec<ratatui::text::Line<'static>> = Vec::new();
|
||||
crate::markdown::append_markdown("Hello.\n", None, &mut rendered, &cfg);
|
||||
crate::markdown::append_markdown("Hello.\n", None, &mut rendered);
|
||||
let rendered_strings: Vec<String> = rendered
|
||||
.iter()
|
||||
.map(|l| {
|
||||
@@ -423,8 +396,6 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn utf8_boundary_safety_and_wide_chars() {
|
||||
let cfg = test_config().await;
|
||||
|
||||
// Emoji (wide), CJK, control char, digit + combining macron sequences
|
||||
let input = "🙂🙂🙂\n汉字漢字\nA\u{0003}0\u{0304}\n";
|
||||
let deltas = vec![
|
||||
@@ -439,11 +410,11 @@ mod tests {
|
||||
"\n",
|
||||
];
|
||||
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true, &cfg);
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true);
|
||||
let streamed_str = lines_to_plain_strings(&streamed);
|
||||
|
||||
let mut rendered_all: Vec<ratatui::text::Line<'static>> = Vec::new();
|
||||
crate::markdown::append_markdown(input, None, &mut rendered_all, &cfg);
|
||||
crate::markdown::append_markdown(input, None, &mut rendered_all);
|
||||
let rendered_all_str = lines_to_plain_strings(&rendered_all);
|
||||
|
||||
assert_eq!(
|
||||
@@ -454,9 +425,8 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn e2e_stream_deep_nested_third_level_marker_is_light_blue() {
|
||||
let cfg = test_config().await;
|
||||
let md = "1. First\n - Second level\n 1. Third level (ordered)\n - Fourth level (bullet)\n - Fifth level to test indent consistency\n";
|
||||
let streamed = super::simulate_stream_markdown_for_tests(&[md], true, &cfg);
|
||||
let streamed = super::simulate_stream_markdown_for_tests(&[md], true);
|
||||
let streamed_strs = lines_to_plain_strings(&streamed);
|
||||
|
||||
// Locate the third-level line in the streamed output; avoid relying on exact indent.
|
||||
@@ -504,11 +474,10 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn empty_fenced_block_is_dropped_and_separator_preserved_before_heading() {
|
||||
let cfg = test_config().await;
|
||||
// An empty fenced code block followed by a heading should not render the fence,
|
||||
// but should preserve a blank separator line so the heading starts on a new line.
|
||||
let deltas = vec!["```bash\n```\n", "## Heading\n"]; // empty block and close in same commit
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true, &cfg);
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true);
|
||||
let texts = lines_to_plain_strings(&streamed);
|
||||
assert!(
|
||||
texts.iter().all(|s| !s.contains("```")),
|
||||
@@ -523,9 +492,8 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn paragraph_then_empty_fence_then_heading_keeps_heading_on_new_line() {
|
||||
let cfg = test_config().await;
|
||||
let deltas = vec!["Para.\n", "```\n```\n", "## Title\n"]; // empty fence block in one commit
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true, &cfg);
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true);
|
||||
let texts = lines_to_plain_strings(&streamed);
|
||||
let para_idx = match texts.iter().position(|s| s == "Para.") {
|
||||
Some(i) => i,
|
||||
@@ -543,17 +511,16 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn loose_list_with_split_dashes_matches_full_render() {
|
||||
let cfg = test_config().await;
|
||||
// Minimized failing sequence discovered by the helper: two chunks
|
||||
// that still reproduce the mismatch.
|
||||
let deltas = vec!["- item.\n\n", "-"];
|
||||
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true, &cfg);
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true);
|
||||
let streamed_strs = lines_to_plain_strings(&streamed);
|
||||
|
||||
let full: String = deltas.iter().copied().collect();
|
||||
let mut rendered_all: Vec<ratatui::text::Line<'static>> = Vec::new();
|
||||
crate::markdown::append_markdown(&full, None, &mut rendered_all, &cfg);
|
||||
crate::markdown::append_markdown(&full, None, &mut rendered_all);
|
||||
let rendered_all_strs = lines_to_plain_strings(&rendered_all);
|
||||
|
||||
assert_eq!(
|
||||
@@ -564,7 +531,6 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn loose_vs_tight_list_items_streaming_matches_full() {
|
||||
let cfg = test_config().await;
|
||||
// Deltas extracted from the session log around 2025-08-27T00:33:18.216Z
|
||||
let deltas = vec![
|
||||
"\n\n",
|
||||
@@ -636,13 +602,13 @@ mod tests {
|
||||
"\n\n",
|
||||
];
|
||||
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true, &cfg);
|
||||
let streamed = simulate_stream_markdown_for_tests(&deltas, true);
|
||||
let streamed_strs = lines_to_plain_strings(&streamed);
|
||||
|
||||
// Compute a full render for diagnostics only.
|
||||
let full: String = deltas.iter().copied().collect();
|
||||
let mut rendered_all: Vec<ratatui::text::Line<'static>> = Vec::new();
|
||||
crate::markdown::append_markdown(&full, None, &mut rendered_all, &cfg);
|
||||
crate::markdown::append_markdown(&full, None, &mut rendered_all);
|
||||
|
||||
// Also assert exact expected plain strings for clarity.
|
||||
let expected = vec![
|
||||
@@ -665,12 +631,11 @@ mod tests {
|
||||
|
||||
// Targeted tests derived from fuzz findings. Each asserts streamed == full render.
|
||||
async fn assert_streamed_equals_full(deltas: &[&str]) {
|
||||
let cfg = test_config().await;
|
||||
let streamed = simulate_stream_markdown_for_tests(deltas, true, &cfg);
|
||||
let streamed = simulate_stream_markdown_for_tests(deltas, true);
|
||||
let streamed_strs = lines_to_plain_strings(&streamed);
|
||||
let full: String = deltas.iter().copied().collect();
|
||||
let mut rendered: Vec<ratatui::text::Line<'static>> = Vec::new();
|
||||
crate::markdown::append_markdown(&full, None, &mut rendered, &cfg);
|
||||
crate::markdown::append_markdown(&full, None, &mut rendered);
|
||||
let rendered_strs = lines_to_plain_strings(&rendered);
|
||||
assert_eq!(streamed_strs, rendered_strs, "full:\n---\n{full}\n---");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user