mirror of
https://github.com/openai/codex.git
synced 2026-11-13 21:30:47 +00:00
## Why The streaming TUI rerendered the entire mutable Markdown block whenever a newline-bearing delta arrived. For long fenced code blocks, this repeatedly parsed and syntax-highlighted the growing fence. ## What changed - Detect open, top-level, language-tagged code fences and append newly completed lines directly to the existing render. - Preserve Syntect parser state across appended lines so multiline syntax and the active theme remain consistent. - Fall back to the canonical Markdown renderer for ambiguous fence syntax, theme changes, incomplete lines, and highlighting limit transitions. ## Testing Added coverage that compares streamed output with full renders across syntax styles, Unicode, links, blank lines, fence variants, theme changes, and highlighting limits. A long-fence test also verifies that the rendered prefix is retained as new lines arrive. GitOrigin-RevId: 036db2b7bc93607083b8001f8b4fa3cbb58c713e
70 lines
2.1 KiB
Rust
70 lines
2.1 KiB
Rust
use super::OpenCodeFence;
|
|
use super::has_possible_closing_line;
|
|
use crate::render::highlight::MAX_HIGHLIGHT_LINE_BYTES;
|
|
use crate::render::highlight::syntax_theme_revision;
|
|
|
|
#[test]
|
|
fn detects_only_source_preserving_open_fences() {
|
|
for source in [
|
|
"```rust,no_run\nfn main() {}\n",
|
|
"~~~~python title=demo\nvalue = 1\n",
|
|
"```\u{b}rust\u{c}\nfn main() {}\n",
|
|
"```unknown-language\ntext\n",
|
|
] {
|
|
let fence =
|
|
OpenCodeFence::detect(source, source.len(), syntax_theme_revision()).expect(source);
|
|
assert!(fence.highlighter.is_none());
|
|
}
|
|
for source in [
|
|
" ```rust\ncode\n",
|
|
"```\ncode\n",
|
|
"```rust\r\ncode\r\n",
|
|
"```rust\n'\0'\n",
|
|
"```rust\ncode\n",
|
|
"```rust\\,no_run\ncode\n",
|
|
"```rust\npartial",
|
|
] {
|
|
assert!(
|
|
OpenCodeFence::detect(source, source.len(), syntax_theme_revision()).is_none(),
|
|
"{source:?}"
|
|
);
|
|
}
|
|
let source = format!("```{}\n", "x".repeat(MAX_HIGHLIGHT_LINE_BYTES + 1));
|
|
assert!(OpenCodeFence::detect(&source, source.len(), syntax_theme_revision()).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn every_possible_closer_returns_to_the_canonical_parser() {
|
|
let opening = "~~~~rust\n";
|
|
assert!(!has_possible_closing_line(
|
|
"~~~\n```\n",
|
|
/*marker*/ b'~',
|
|
/*marker_len*/ 4
|
|
));
|
|
for line in [
|
|
"~~~~\n",
|
|
" ~~~~~~ \n",
|
|
"~~~~\t\n",
|
|
"~~~~\u{a0}\n",
|
|
"\t~~~~\n",
|
|
" ~~~~\n",
|
|
"~~~~ trailing text\n",
|
|
] {
|
|
let source = format!("{opening}{line}");
|
|
assert!(OpenCodeFence::detect(&source, source.len(), syntax_theme_revision()).is_none());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn lazy_initialization_rejects_a_changed_theme() {
|
|
let source = "```rust\nfn first() {}\n";
|
|
let mut fence = OpenCodeFence::detect(source, source.len(), syntax_theme_revision()).unwrap();
|
|
fence.theme_revision = fence.theme_revision.wrapping_sub(1);
|
|
let appended = "fn second() {}\n";
|
|
assert!(
|
|
fence
|
|
.append(&format!("{source}{appended}"), appended)
|
|
.is_none()
|
|
);
|
|
}
|