build(rag): add duckdb dependency and pin comfy-table to 7.1.4

Adds the duckdb crate with the bundled feature ahead of any provider
code, so the dependency and build surface can be proven on every CI
target on its own.

duckdb constrains comfy-table to ~7.1, so comfy-table moves from 7.2.2
to 7.1.4 while keeping custom_styling. That feature swaps
measure_text_width for an ANSI-stripping implementation that
render_table's pre-styled cells depend on; dropping it still compiles
and still passes every other test, and only corrupts column widths. A
regression test now renders a styled table at a fixed wrap width and
asserts every line has an equal ANSI-stripped display width.

comfy-table 7.1.4 pins crossterm 0.28 while coyote pins 0.29, so both
now build side by side. comfy_table::Color, Attribute and Cell are
consequently crossterm 0.28 types and must not be used; table styling
stays ANSI-string based.

Caches the DuckDB extension directory in CI, keyed on the runner OS and
the DuckDB version, so vss and fts survive an upstream outage.

Also switches merge_vector_results to f32::total_cmp. The previous
partial_cmp().unwrap_or(Equal) comparator is not total under NaN, which
sort_by is permitted to answer with a panic in release builds.
This commit is contained in:
2026-08-10 11:59:57 -06:00
parent 5049143fcc
commit d734276927
5 changed files with 522 additions and 23 deletions
+6
View File
@@ -36,6 +36,12 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: Cache DuckDB Extensions
uses: actions/cache@v4
with:
path: ~/.duckdb/extensions
key: duckdb-ext-${{ matrix.os }}-v1.5.5
- name: Test
run: cargo test --all
Generated
+422 -21
View File
@@ -34,6 +34,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
"const-random",
"getrandom 0.3.4",
"once_cell",
"version_check",
"zerocopy",
@@ -244,6 +246,169 @@ version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
[[package]]
name = "arrow"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cfdd0833e32a9874d2b55089333ad310c0be208aafa277385ce2461dec90be3"
dependencies = [
"arrow-arith",
"arrow-array",
"arrow-buffer",
"arrow-cast",
"arrow-data",
"arrow-ord",
"arrow-row",
"arrow-schema",
"arrow-select",
"arrow-string",
]
[[package]]
name = "arrow-arith"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a41203398f0eaa6f7ec8e62c0da742a21abf282c148fc157f6c35c90e29981a"
dependencies = [
"arrow-array",
"arrow-buffer",
"arrow-data",
"arrow-schema",
"chrono",
"num-traits",
]
[[package]]
name = "arrow-array"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae33dad492b7df00a217563a7b0ef2874df68a0deea1b1a3acf628152f7f7a69"
dependencies = [
"ahash",
"arrow-buffer",
"arrow-data",
"arrow-schema",
"chrono",
"half",
"hashbrown 0.17.1",
"num-complex",
"num-integer",
"num-traits",
]
[[package]]
name = "arrow-buffer"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9552f96391c005e6ab449fa941420935e7e062489b12b8b1b08879b2163f5b5"
dependencies = [
"bytes",
"half",
"num-bigint",
"num-traits",
]
[[package]]
name = "arrow-cast"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a8a327c9649f30d8406995f27642b68df354713cca3baaaf100f076f18d5f34"
dependencies = [
"arrow-array",
"arrow-buffer",
"arrow-data",
"arrow-ord",
"arrow-schema",
"arrow-select",
"atoi",
"base64",
"chrono",
"comfy-table",
"half",
"lexical-core",
"num-traits",
"ryu",
]
[[package]]
name = "arrow-data"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b24852db04738907e06c04ea61e42fe7fda962a34513022dc0d0e754fb7976b"
dependencies = [
"arrow-buffer",
"arrow-schema",
"half",
"num-integer",
"num-traits",
]
[[package]]
name = "arrow-ord"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63a083ec750f5c043f02946b4baf05fcdbb55f4560a3277055caca5cc99f3eb0"
dependencies = [
"arrow-array",
"arrow-buffer",
"arrow-data",
"arrow-schema",
"arrow-select",
]
[[package]]
name = "arrow-row"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514ba0ef0d4c5896202dae736251ce415abb43a950bed570fb7981b8716c0e4c"
dependencies = [
"arrow-array",
"arrow-buffer",
"arrow-data",
"arrow-schema",
"half",
]
[[package]]
name = "arrow-schema"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21ca356ad6425cecb6eb7b28e4f659f1ee7880fbb1a16127de7dd62901efee9e"
dependencies = [
"bitflags 2.13.1",
]
[[package]]
name = "arrow-select"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c58da39eb3d8350ad4a549e5c2bc49284dac554016c69829310350f1731b0aad"
dependencies = [
"ahash",
"arrow-array",
"arrow-buffer",
"arrow-data",
"arrow-schema",
"num-traits",
]
[[package]]
name = "arrow-string"
version = "58.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6789b388467525e3271326b6b4915666ecfdf5142aef09779445c954b67543c"
dependencies = [
"arrow-array",
"arrow-buffer",
"arrow-data",
"arrow-schema",
"arrow-select",
"memchr",
"num-traits",
"regex",
"regex-syntax",
]
[[package]]
name = "async-compression"
version = "0.4.43"
@@ -289,6 +454,15 @@ dependencies = [
"syn 3.0.3",
]
[[package]]
name = "atoi"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
dependencies = [
"num-traits",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
@@ -1096,6 +1270,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.4.0"
@@ -1314,13 +1494,13 @@ dependencies = [
[[package]]
name = "comfy-table"
version = "7.2.2"
version = "7.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47"
checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a"
dependencies = [
"ansi-str",
"console",
"crossterm",
"console 0.15.11",
"crossterm 0.28.1",
"unicode-segmentation",
"unicode-width",
]
@@ -1355,6 +1535,19 @@ dependencies = [
"thiserror 2.0.19",
]
[[package]]
name = "console"
version = "0.15.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
dependencies = [
"encode_unicode",
"libc",
"once_cell",
"unicode-width",
"windows-sys 0.59.0",
]
[[package]]
name = "console"
version = "0.16.4"
@@ -1379,6 +1572,26 @@ version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom 0.2.17",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "convert_case"
version = "0.10.0"
@@ -1465,8 +1678,9 @@ dependencies = [
"clap_complete_nushell",
"colored",
"comfy-table",
"crossterm",
"crossterm 0.29.0",
"dirs",
"duckdb",
"duct",
"dunce",
"eventsource-stream",
@@ -1595,6 +1809,19 @@ version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
[[package]]
name = "crossterm"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
dependencies = [
"bitflags 2.13.1",
"crossterm_winapi",
"parking_lot",
"rustix 0.38.44",
"winapi",
]
[[package]]
name = "crossterm"
version = "0.29.0"
@@ -1608,7 +1835,7 @@ dependencies = [
"filedescriptor",
"mio",
"parking_lot",
"rustix",
"rustix 1.1.4",
"serde",
"signal-hook",
"signal-hook-mio",
@@ -1624,6 +1851,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "crunchy"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "crypto-common"
version = "0.1.7"
@@ -1886,7 +2119,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96"
dependencies = [
"console",
"console 0.16.4",
"shell-words",
"tempfile",
"zeroize",
@@ -1993,6 +2226,23 @@ dependencies = [
"dtoa",
]
[[package]]
name = "duckdb"
version = "1.10505.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "970e05eedd3f55c435194d9104f90a9b4a79a80d6e73251bc9ff43e178130c4e"
dependencies = [
"arrow",
"cast",
"comfy-table",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libduckdb-sys",
"num-integer",
"strum",
]
[[package]]
name = "duct"
version = "1.1.1"
@@ -2168,6 +2418,18 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "fallible-iterator"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "fancy-regex"
version = "0.14.0"
@@ -2192,7 +2454,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
dependencies = [
"cfg-if",
"rustix",
"rustix 1.1.4",
"windows-sys 0.59.0",
]
@@ -2448,7 +2710,7 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
dependencies = [
"rustix",
"rustix 1.1.4",
"windows-link",
]
@@ -2526,7 +2788,7 @@ dependencies = [
"clap_complete",
"confy",
"crc32c",
"crossterm",
"crossterm 0.29.0",
"dialoguer",
"dirs",
"futures",
@@ -2590,6 +2852,18 @@ dependencies = [
"tracing",
]
[[package]]
name = "half"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
dependencies = [
"cfg-if",
"crunchy",
"num-traits",
"zerocopy",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -2613,6 +2887,15 @@ version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "hashlink"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
dependencies = [
"hashbrown 0.15.5",
]
[[package]]
name = "heck"
version = "0.5.0"
@@ -3122,7 +3405,7 @@ version = "0.18.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9433806cd6b4ec1aba79c021c7e4c58fb4c3b9977c085062e611ac929998fb0c"
dependencies = [
"console",
"console 0.16.4",
"portable-atomic",
"unicode-width",
"unit-prefix",
@@ -3154,7 +3437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6654738b8024300cf062d04a1c13c10c8e2cea598ec1c47dc9b6641159429756"
dependencies = [
"bitflags 2.13.1",
"crossterm",
"crossterm 0.29.0",
"dyn-clone",
"fuzzy-matcher",
"unicode-segmentation",
@@ -3387,12 +3670,86 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lexical-core"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594"
dependencies = [
"lexical-parse-float",
"lexical-parse-integer",
"lexical-util",
"lexical-write-float",
"lexical-write-integer",
]
[[package]]
name = "lexical-parse-float"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56"
dependencies = [
"lexical-parse-integer",
"lexical-util",
]
[[package]]
name = "lexical-parse-integer"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34"
dependencies = [
"lexical-util",
]
[[package]]
name = "lexical-util"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17"
[[package]]
name = "lexical-write-float"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361"
dependencies = [
"lexical-util",
"lexical-write-integer",
]
[[package]]
name = "lexical-write-integer"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df"
dependencies = [
"lexical-util",
]
[[package]]
name = "libc"
version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "libduckdb-sys"
version = "1.10505.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cb514dab5e271e849235c1cb98bd65a2ae107fbd619a6740219319c54a71d95"
dependencies = [
"cc",
"flate2",
"pkg-config",
"serde",
"serde_json",
"tar",
"ureq",
"vcpkg",
"zip",
]
[[package]]
name = "libloading"
version = "0.8.9"
@@ -3403,6 +3760,12 @@ dependencies = [
"windows-link",
]
[[package]]
name = "libm"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.19"
@@ -3412,6 +3775,12 @@ dependencies = [
"libc",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.12.1"
@@ -3744,6 +4113,15 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.2.2"
@@ -3766,6 +4144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
"libm",
]
[[package]]
@@ -4717,7 +5096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2066729dce9fecd28d1c6850a159ee68719130f149b22467c362353e16994e90"
dependencies = [
"chrono",
"crossterm",
"crossterm 0.29.0",
"fd-lock",
"itertools 0.13.0",
"nu-ansi-term",
@@ -5032,6 +5411,19 @@ dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.13.1",
"errno",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.1.4"
@@ -5041,7 +5433,7 @@ dependencies = [
"bitflags 2.13.1",
"errno",
"libc",
"linux-raw-sys",
"linux-raw-sys 0.12.1",
"windows-sys 0.61.2",
]
@@ -5952,7 +6344,7 @@ dependencies = [
"fastrand",
"getrandom 0.4.3",
"once_cell",
"rustix",
"rustix 1.1.4",
"windows-sys 0.61.2",
]
@@ -5999,7 +6391,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
dependencies = [
"rustix",
"rustix 1.1.4",
"windows-sys 0.61.2",
]
@@ -6114,6 +6506,15 @@ dependencies = [
"time-core",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinystr"
version = "0.8.3"
@@ -6845,7 +7246,7 @@ checksum = "016ccf01d1c58b6f8999612813e17c9b2390f7d70671428869913310f83f54b8"
dependencies = [
"cc",
"downcast-rs",
"rustix",
"rustix 1.1.4",
"smallvec",
"wayland-sys",
]
@@ -6857,7 +7258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073"
dependencies = [
"bitflags 2.13.1",
"rustix",
"rustix 1.1.4",
"wayland-backend",
"wayland-scanner",
]
@@ -7347,7 +7748,7 @@ dependencies = [
"libc",
"log",
"os_pipe",
"rustix",
"rustix 1.1.4",
"thiserror 2.0.19",
"tree_magic_mini",
"wayland-backend",
@@ -7369,7 +7770,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
dependencies = [
"gethostname",
"rustix",
"rustix 1.1.4",
"x11rb-protocol",
]
@@ -7386,7 +7787,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
dependencies = [
"libc",
"rustix",
"rustix 1.1.4",
]
[[package]]
+2 -1
View File
@@ -17,8 +17,9 @@ exclude = [".github", "CONTRIBUTING.md"]
anyhow = "1.0.69"
bytes = "1.4.0"
clap = { version = "4.5.40", features = ["cargo", "derive", "wrap_help"] }
comfy-table = { version = "7.2.2", features = ["custom_styling"] }
comfy-table = { version = "7.1.4", features = ["custom_styling"] }
dirs = "6.0.0"
duckdb = { version = "1.10505.0", features = ["bundled"] }
dunce = "1.0.5"
futures-util = "0.3.29"
inquire = "0.9.4"
+1 -1
View File
@@ -1630,7 +1630,7 @@ fn merge_vector_results(mut results: Vec<(DocumentId, f32)>) -> Vec<(DocumentId,
results.iter().all(|(_, score)| score.is_finite()),
"provider returned a non-finite score; NaN silently degrades sort order"
);
results.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
results.sort_by(|a, b| b.1.total_cmp(&a.1));
let mut seen = IndexSet::new();
results
.into_iter()
+91
View File
@@ -1749,6 +1749,97 @@ std::error::Error>> {
);
}
/// Removes CSI escape sequences so only printable content is measured.
///
/// Deliberately tolerant of malformed input: a sequence that was sliced
/// mid-escape swallows the following characters, which is precisely the
/// corruption `render_table_pads_columns_by_display_width` exists to catch.
fn strip_ansi(text: &str) -> String {
let mut out = String::with_capacity(text.len());
let mut chars = text.chars();
while let Some(c) = chars.next() {
if c != '\u{1b}' {
out.push(c);
continue;
}
if chars.next() == Some('[') {
for c in chars.by_ref() {
if ('\u{40}'..='\u{7e}').contains(&c) {
break;
}
}
}
}
out
}
#[test]
fn strip_ansi_removes_sgr_and_keeps_text() {
assert_eq!(strip_ansi("\x1b[1mbold\x1b[0m"), "bold");
assert_eq!(strip_ansi("\x1b[38;5;120mx\x1b[39m"), "x");
assert_eq!(strip_ansi("plain"), "plain");
}
/// `render_table` hands comfy-table pre-styled cells that already contain
/// ANSI escapes, and `colorize_box_chars` adds more afterwards. Column
/// widths are therefore only correct if the escapes are excluded from the
/// width calculation. When they are not, the table still renders and every
/// other assertion in this file still passes -- only the alignment silently
/// degrades -- so this is the sole guard over that behaviour.
#[test]
fn render_table_pads_columns_by_display_width() {
use unicode_width::UnicodeWidthStr;
const WRAP_WIDTH: u16 = 80;
let options = RenderOptions::default();
let mut render = MarkdownRender::init(options).unwrap();
render.wrap_width = Some(WRAP_WIDTH);
let header = vec![
"**Setting**".into(),
"*Default*".into(),
"`Description`".into(),
];
let alignments = vec![
CellAlignment::Left,
CellAlignment::Right,
CellAlignment::Center,
];
let rows = vec![
vec![
"**temperature**".into(),
"`0.7`".into(),
"Controls how *random* the sampled reply is allowed to be".into(),
],
vec![
"**top_p**".into(),
"`1.0`".into(),
"Nucleus sampling cutoff, applied **after** temperature".into(),
],
];
let output = render.render_table(header, alignments, rows);
assert!(
output.contains('\u{1b}'),
"fixture must actually contain ANSI escapes: {output:?}",
);
let widths: Vec<usize> = output
.lines()
.map(|line| strip_ansi(line).width())
.collect();
assert!(!widths.is_empty(), "table rendered no lines");
for (index, width) in widths.iter().enumerate() {
assert_eq!(
*width, WRAP_WIDTH as usize,
"line {index} display width; all widths were {widths:?} in output:\n{output}",
);
}
}
#[test]
fn state_machine_renders_full_table_and_flushes_on_paragraph() {
let options = RenderOptions::default();