zsh/ported/zle/zle_h.rs
1//! Direct port of `Src/Zle/zle.h` — line-editor type / constant
2//! header.
3//!
4//! Original C copyright: Paul Falstad 1992-1997.
5//!
6//! Hosts the type aliases (`Widget` / `Thingy` / `Keymap` /
7//! `Cutbuffer` / etc.), enum / `#define` constants used across the
8//! ZLE port, and the `struct widget` / `struct thingy` /
9//! `struct modifier` / `struct change` / `struct vichange` /
10//! `struct cutbuffer` / `struct brinfo` / `struct compldat` /
11//! `struct region_highlight` / `struct watch_fd` / `REFRESH_ELEMENT`
12//! shapes the C source uses.
13//!
14//! Multibyte note: zshrs uses native UTF-8 throughout, so the C
15//! `#ifdef MULTIBYTE_SUPPORT` (zle.h:30-105) `wchar_t` types collapse
16//! onto Rust `char` / `String`. The non-multibyte fallback (`char`
17//! / `int`) is the parallel C path; the type aliases below pick
18//! the shape that maps cleanly onto Rust.
19
20#![allow(non_camel_case_types, non_snake_case, dead_code)]
21
22use crate::ported::zsh_h::{HashNode, zattr};
23
24// =====================================================================
25// Wide-character types — `Src/Zle/zle.h:30-110`.
26// =====================================================================
27//
28// C dispatches between `wchar_t` (MULTIBYTE_SUPPORT, zle.h:30-104)
29// and `char` (non-multibyte, zle.h:105-181). Rust uses `char` for
30// code-points and `String` for owned text — those primitives cover
31// both C paths.
32
33/// Port of `ZLE_CHAR_T` from zle.h:31 / zle.h:107.
34
35// --- AUTO: cross-zle hoisted-fn use glob ---
36#[allow(unused_imports)]
37// (was: use crate::ported::zle::widget::*; — widget.rs deleted)
38#[allow(unused_imports)]
39use crate::ported::zle::zle_main::*;
40#[allow(unused_imports)]
41use crate::ported::zle::zle_misc::*;
42#[allow(unused_imports)]
43use crate::ported::zle::zle_hist::*;
44#[allow(unused_imports)]
45use crate::ported::zle::zle_move::*;
46#[allow(unused_imports)]
47use crate::ported::zle::zle_word::*;
48#[allow(unused_imports)]
49use crate::ported::zle::zle_params::*;
50#[allow(unused_imports)]
51use crate::ported::zle::zle_vi::*;
52#[allow(unused_imports)]
53use crate::ported::zle::zle_utils::*;
54#[allow(unused_imports)]
55use crate::ported::zle::zle_refresh::*;
56#[allow(unused_imports)]
57use crate::ported::zle::zle_tricky::*;
58#[allow(unused_imports)]
59use crate::ported::zle::textobjects::*;
60#[allow(unused_imports)]
61use crate::ported::zle::deltochar::*;
62
63pub type ZLE_CHAR_T = char; // c:31
64
65/// Port of `ZLE_STRING_T` from zle.h:32 / zle.h:108.
66pub type ZLE_STRING_T = String; // c:32
67
68/// Port of `ZLE_INT_T` from zle.h:33 / zle.h:109.
69pub type ZLE_INT_T = i32; // c:33
70
71/// Port of `ZLE_CHAR_SIZE` from zle.h:34. Rust `char` is always 4
72/// bytes (USVs); the C `wchar_t` is 4 on every supported host.
73pub const ZLE_CHAR_SIZE: usize = 4; // c:34
74
75/// Port of `ZLEEOF` from zle.h:37 / zle.h:112.
76pub const ZLEEOF: i32 = -1; // c:37 WEOF
77
78/// Port of `Th(X)` macro from zle.h:316. `#define Th(X) (&thingies[X])`.
79/// Resolves a fixed-thingy index into its Thingy reference.
80///
81/// In C, `thingies[]` is auto-generated by `mkbltnmlst.sh` from the
82/// `mod_export Thingy` declarations sprinkled across `zle.h`/`zle_*.c`.
83/// Each `t_<name>` constant indexes one slot. zshrs hasn't ported
84/// that build-time auto-gen, so this helper uses the manually-kept
85/// index→name table in `T_THINGY_NAMES` below and forwards to
86/// `lookup_thingy(name)` — same observable contract as the C macro.
87#[inline]
88pub fn Th(index: i32) -> Option<crate::ported::zle::zle_thingy::Thingy> { // c:316
89 let i: usize = (index as i64).try_into().ok()?;
90 let name = T_THINGY_NAMES.get(i)?;
91 crate::ported::zle::zle_thingy::gethashnode2(name)
92}
93
94/// Fixed-thingy index table. Order matches the `mod_export Thingy
95/// t_<name>` declaration order in `Src/Zle/zle.h` so callers can use
96/// `Th(t_acceptline as i32)` exactly as they would in C. Add new
97/// entries here when `t_<name>` constants get back-ported; the
98/// indices are stable per zsh ABI.
99pub const T_THINGY_NAMES: &[&str] = &[
100 "accept-and-hold", // t_acceptandhold = 0
101 "accept-line", // t_acceptline = 1
102 "accept-line-and-down-history", // t_acceptlineanddownhistory
103 "accept-search", // t_acceptsearch
104 "auto-suffix-remove", // t_autosuffixremove
105 "auto-suffix-retain", // t_autosuffixretain
106 "backward-char", // t_backwardchar
107 "backward-delete-char", // t_backwarddeletechar
108 "beep", // t_beep
109 "clear-screen", // t_clearscreen
110 "complete-word", // t_completeword
111 "describe-key-briefly", // t_describekeybriefly
112 "down-line-or-history", // t_downlineorhistory
113 "execute-named-cmd", // t_executenamedcmd
114 "exit", // t_exit
115 "forward-char", // t_forwardchar
116 "history-incremental-search-backward", // t_historyincrementalsearchbackward
117 "history-incremental-search-forward", // t_historyincrementalsearchforward
118 "list-choices", // t_listchoices
119 "menu-complete", // t_menucomplete
120 "menu-expand-or-complete", // t_menuexpandorcomplete
121 "redisplay", // t_redisplay
122 "self-insert", // t_selfinsert
123 "self-insert-unmeta", // t_selfinsertunmeta
124 "send-break", // t_sendbreak
125 "undefined-key", // t_undefinedkey
126 "undo", // t_undo
127 "up-line-or-history", // t_uplineorhistory
128 "vi-cmd-mode", // t_vicmdmode
129 "yank", // t_yank
130];
131
132/// Port of `invicmdmode()` macro from zle.h:324.
133/// `#define invicmdmode() (!strcmp(curkeymapname, "vicmd"))`.
134/// True when the current keymap is the vi command-mode keymap.
135/// The Rust `in_vi_cmd_mode()` free fn (zle_main.rs:815) is the
136/// state-bound counterpart; this free-fn uses the global keymap name.
137#[inline] pub fn invicmdmode(curkeymapname: &str) -> bool { // c:324
138 curkeymapname == "vicmd"
139}
140
141// =====================================================================
142// `ZS_*` wide-string macros — `Src/Zle/zle.h:40-51`.
143// C #defines route to wmemcpy/wcslen/etc. on MULTIBYTE_SUPPORT builds
144// and to the memcpy/strlen counterparts otherwise. Rust uses `char` /
145// `[char]` directly so each macro maps to a slice operation.
146// =====================================================================
147
148/// Port of `ZS_memcpy` from zle.h:40 (`#define ZS_memcpy wmemcpy`).
149/// Copies `n` chars from `src` into `dst`.
150#[inline] pub fn ZS_memcpy(dst: &mut [ZLE_CHAR_T], src: &[ZLE_CHAR_T], n: usize) { // c:40
151 dst[..n].copy_from_slice(&src[..n]);
152}
153
154/// Port of `ZS_memmove` from zle.h:41 (`#define ZS_memmove wmemmove`).
155/// Same as ZS_memcpy but tolerates overlapping ranges (vec move
156/// semantics handle overlap).
157#[inline] pub fn ZS_memmove(dst: &mut [ZLE_CHAR_T], src: &[ZLE_CHAR_T], n: usize) { // c:41
158 let v: Vec<ZLE_CHAR_T> = src[..n].to_vec();
159 dst[..n].copy_from_slice(&v);
160}
161
162/// Port of `ZS_memset` from zle.h:42 (`#define ZS_memset wmemset`).
163/// Fills `dst[..n]` with `c`.
164#[inline] pub fn ZS_memset(dst: &mut [ZLE_CHAR_T], c: ZLE_CHAR_T, n: usize) { // c:42
165 for slot in dst.iter_mut().take(n) {
166 *slot = c;
167 }
168}
169
170/// Port of `ZS_memcmp` from zle.h:43 (`#define ZS_memcmp wmemcmp`).
171/// Returns Ordering of the first `n` chars.
172#[inline] pub fn ZS_memcmp(a: &[ZLE_CHAR_T], b: &[ZLE_CHAR_T], n: usize) -> std::cmp::Ordering { // c:43
173 a[..n].cmp(&b[..n])
174}
175
176/// Port of `ZS_strlen` from zle.h:44 (`#define ZS_strlen wcslen`).
177/// Returns the length to the first NUL char (or full slice length
178/// if no NUL found).
179#[inline] pub fn ZS_strlen(s: &[ZLE_CHAR_T]) -> usize { // c:44
180 s.iter().position(|&c| c == '\0').unwrap_or(s.len())
181}
182
183/// Port of `ZS_strcpy` from zle.h:45 (`#define ZS_strcpy wcscpy`).
184/// Copies `src` (up to first NUL or end) into `dst`, NUL-terminates
185/// when there's room.
186#[inline] pub fn ZS_strcpy(dst: &mut [ZLE_CHAR_T], src: &[ZLE_CHAR_T]) { // c:45
187 let n = ZS_strlen(src);
188 let limit = dst.len().min(n);
189 dst[..limit].copy_from_slice(&src[..limit]);
190 if limit < dst.len() {
191 dst[limit] = '\0';
192 }
193}
194
195/// Port of `ZS_strncpy` from zle.h:46 (`#define ZS_strncpy wcsncpy`).
196/// Copies up to `n` chars; pads remainder with NUL if `src` is shorter.
197#[inline] pub fn ZS_strncpy(dst: &mut [ZLE_CHAR_T], src: &[ZLE_CHAR_T], n: usize) { // c:46
198 let s_len = ZS_strlen(src).min(n);
199 let limit = dst.len().min(n);
200 let copy = s_len.min(limit);
201 dst[..copy].copy_from_slice(&src[..copy]);
202 for slot in dst.iter_mut().take(limit).skip(copy) {
203 *slot = '\0';
204 }
205}
206
207/// Port of `ZS_strncmp` from zle.h:47 (`#define ZS_strncmp wcsncmp`).
208/// Returns Ordering of up to `n` chars (stops at NUL).
209#[inline] pub fn ZS_strncmp(a: &[ZLE_CHAR_T], b: &[ZLE_CHAR_T], n: usize) -> std::cmp::Ordering { // c:47
210 let a_n = ZS_strlen(a).min(n);
211 let b_n = ZS_strlen(b).min(n);
212 let limit = a_n.min(b_n);
213 let cmp = a[..limit].cmp(&b[..limit]);
214 if cmp != std::cmp::Ordering::Equal {
215 return cmp;
216 }
217 a_n.cmp(&b_n)
218}
219
220/// Port of `ZS_strchr` from zle.h:50 (`#define ZS_strchr wcschr`).
221/// Returns the index of the first occurrence of `c` in `s`, or `None`.
222#[inline] pub fn ZS_strchr(s: &[ZLE_CHAR_T], c: ZLE_CHAR_T) -> Option<usize> { // c:50
223 s.iter().position(|&x| x == c)
224}
225
226/// Port of `ZS_memchr` from zle.h:51 (`#define ZS_memchr wmemchr`).
227/// Returns the index of the first occurrence of `c` in `s[..n]`.
228#[inline] pub fn ZS_memchr(s: &[ZLE_CHAR_T], c: ZLE_CHAR_T, n: usize) -> Option<usize> { // c:51
229 s[..n.min(s.len())].iter().position(|&x| x == c)
230}
231
232/// Port of `ZS_width` from zle.h:49 (`#define ZS_width wcslen`).
233/// Returns the display width of a string (collapses to char count
234/// for the non-multibyte path; in zshrs we treat each char as 1 col).
235#[inline] pub fn ZS_width(s: &[ZLE_CHAR_T]) -> usize { // c:49
236 ZS_strlen(s)
237}
238
239// =====================================================================
240// `ZC_*` wide-character classification macros — `Src/Zle/zle.h:60-73`.
241// C #defines route to `iswalpha`/`iswalnum`/etc. on MULTIBYTE_SUPPORT
242// builds and to the `<ctype.h>` counterparts otherwise. Rust's
243// `char::is_*` methods cover both paths uniformly.
244// =====================================================================
245
246/// Port of `ZC_ialpha` from zle.h:60.
247#[inline] pub fn ZC_ialpha(c: ZLE_CHAR_T) -> bool { c.is_alphabetic() } // c:60
248/// Port of `ZC_ialnum` from zle.h:61.
249#[inline] pub fn ZC_ialnum(c: ZLE_CHAR_T) -> bool { c.is_alphanumeric() } // c:61
250/// Port of `ZC_iblank` from zle.h:62 (`wcsiblank`). True for blank
251/// chars excluding newline (matches zsh's `iblank` predicate).
252#[inline] pub fn ZC_iblank(c: ZLE_CHAR_T) -> bool { c == ' ' || c == '\t' } // c:62
253/// Port of `ZC_icntrl` from zle.h:63.
254#[inline] pub fn ZC_icntrl(c: ZLE_CHAR_T) -> bool { c.is_control() } // c:63
255/// Port of `ZC_idigit` from zle.h:64.
256#[inline] pub fn ZC_idigit(c: ZLE_CHAR_T) -> bool { c.is_ascii_digit() } // c:64
257/// Port of `ZC_iident` from zle.h:65 (`wcsitype(c, IIDENT)`). Identifier
258/// char per zsh's IIDENT class: alphanumeric or `_`.
259#[inline] pub fn ZC_iident(c: ZLE_CHAR_T) -> bool { c.is_alphanumeric() || c == '_' } // c:65
260/// Port of `ZC_ilower` from zle.h:66.
261#[inline] pub fn ZC_ilower(c: ZLE_CHAR_T) -> bool { c.is_lowercase() } // c:66
262/// Port of `ZC_inblank` from zle.h:67 (`iswspace`). True for any
263/// whitespace char (incl. newline).
264#[inline] pub fn ZC_inblank(c: ZLE_CHAR_T) -> bool { c.is_whitespace() } // c:67
265/// Port of `ZC_iupper` from zle.h:68.
266#[inline] pub fn ZC_iupper(c: ZLE_CHAR_T) -> bool { c.is_uppercase() } // c:68
267/// Port of `ZC_iword` from zle.h:69 (`wcsitype(c, IWORD)`). Word
268/// char per zsh's IWORD class: alphanumeric or `_`.
269#[inline] pub fn ZC_iword(c: ZLE_CHAR_T) -> bool { c.is_alphanumeric() || c == '_' } // c:69
270/// Port of `ZC_ipunct` from zle.h:70.
271#[inline] pub fn ZC_ipunct(c: ZLE_CHAR_T) -> bool { c.is_ascii_punctuation() } // c:70
272
273/// Port of `ZC_tolower` from zle.h:72.
274#[inline] pub fn ZC_tolower(c: ZLE_CHAR_T) -> ZLE_CHAR_T { // c:72
275 c.to_lowercase().next().unwrap_or(c)
276}
277/// Port of `ZC_toupper` from zle.h:73.
278#[inline] pub fn ZC_toupper(c: ZLE_CHAR_T) -> ZLE_CHAR_T { // c:73
279 c.to_uppercase().next().unwrap_or(c)
280}
281
282// =====================================================================
283// `LASTFULLCHAR` — `Src/Zle/zle.h:75-76`. Macro alias resolving to
284// `lastchar_wide` (the most-recent fully-decoded codepoint). Lives
285// as a field on `Zle` (`lastchar_wide: ZleInt`); the macro name is
286// kept here as an alias for searchability.
287// =====================================================================
288
289// =====================================================================
290// Widget — `Src/Zle/zle.h:184-220`.
291// =====================================================================
292
293/// Port of `typedef struct widget *Widget` from zle.h:184.
294pub type WidgetPtr = Box<widget>; // c:184
295
296/// Port of `typedef struct thingy *Thingy` from zle.h:185.
297pub type ThingyPtr = Box<thingy>; // c:185
298
299/// Port of `ZleIntFunc` from zle.h:189. C: `int (*)(char **)` —
300/// every internal widget conforms to this signature.
301pub type ZleIntFunc = fn(args: &[String]) -> i32; // c:189
302
303/// Port of `struct widget` from `Src/Zle/zle.h:191-203`.
304/// ```c
305/// struct widget {
306/// int flags; /* WIDGET_* / ZLE_* flag bitset */
307/// Thingy first; /* `first` thingy that names this widget */
308/// union {
309/// ZleIntFunc fn; /* internal widget */
310/// char *fnnam; /* shell-function name for user-defined */
311/// struct { ZleIntFunc fn; char *wid; char *func; } comp;
312/// } u;
313/// };
314/// ```
315// Legacy aliases preserved for back-compat with files that historically
316// imported `Widget` / `WidgetFunc` (PascalCase) from the deleted
317// `widget.rs` shim. New code should use `widget` / `WidgetImpl`
318// directly.
319pub use self::WidgetImpl as WidgetFunc;
320pub type Widget = widget;
321
322pub struct widget { // c:191
323 /// flags (see below).
324 pub flags: i32, // c:192
325 /// `first' thingy that names this widget.
326 pub first: Option<ThingyPtr>, // c:193
327 /// Tagged equivalent of the C anonymous union (zle.h:194-202).
328 pub u: WidgetImpl, // c:194
329}
330
331impl Clone for widget {
332 fn clone(&self) -> Self {
333 widget {
334 flags: self.flags,
335 first: None, // ThingyPtr is Box<thingy>, intentionally not deep-cloned.
336 u: match &self.u {
337 WidgetImpl::Internal(f) => WidgetImpl::Internal(*f),
338 WidgetImpl::UserFunc(s) => WidgetImpl::UserFunc(s.clone()),
339 WidgetImpl::Comp { fn_, wid, func } => WidgetImpl::Comp {
340 fn_: *fn_,
341 wid: wid.clone(),
342 func: func.clone(),
343 },
344 },
345 }
346 }
347}
348
349impl std::fmt::Debug for widget {
350 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351 f.debug_struct("widget")
352 .field("flags", &self.flags)
353 .field("u", &match &self.u {
354 WidgetImpl::Internal(_) => "Internal(<fn>)".to_string(),
355 WidgetImpl::UserFunc(s) => format!("UserFunc({})", s),
356 WidgetImpl::Comp { .. } => "Comp{..}".to_string(),
357 })
358 .finish()
359 }
360}
361
362impl widget {
363 /// Build a widget that points at a Rust function pointer with the
364 /// supplied ZLE flags. Equivalent to the WIDGET_INT branch of
365 /// `zalloc(sizeof(*w))` + `w->u.fn = ...` in `addzlefunction()` at
366 /// Src/Zle/zle_thingy.c:281.
367 pub fn internal(name: &str, func: ZleIntFunc, flags: i32) -> Self {
368 let _ = name;
369 widget { flags: flags | WIDGET_INT, first: None, u: WidgetImpl::Internal(func) }
370 }
371
372 /// Resolve a built-in widget name to its canonical fn pointer
373 /// via `zle_bindings::iwidget_lookup`. Mirrors the dispatch C
374 /// achieves at `Src/Zle/zle_bindings.c:55-60` through the
375 /// generated `widgets[]` static table; the Rust port uses a
376 /// name → fn-pointer match keyed off the same `iwidgets.list`
377 /// canonical names. Unknown widget names get a no-op fn
378 /// pointer (matches what `t_undefinedkey` resolves to).
379 pub fn builtin(name: &str) -> Self {
380 let f = super::zle_bindings::iwidget_lookup(name)
381 .unwrap_or(|_args: &[String]| 0i32);
382 widget { flags: WIDGET_INT, first: None, u: WidgetImpl::Internal(f) }
383 }
384
385 /// Build a widget that wraps a user-defined shell function.
386 /// Equivalent to `bin_zle_new()` from Src/Zle/zle_thingy.c:584.
387 pub fn user_defined(name: &str, func_name: &str) -> Self {
388 let _ = name;
389 widget { flags: 0i32, first: None, u: WidgetImpl::UserFunc(func_name.to_string()) }
390 }
391}
392
393/// Tagged port of the `widget.u` union from `Src/Zle/zle.h:194-202`.
394/// C uses an inline anonymous union; Rust enum tags the active
395/// variant.
396pub enum WidgetImpl { // c:194
397 /// `u.fn` — pointer to internally implemented widget.
398 Internal(ZleIntFunc), // c:195
399 /// `u.fnnam` — name of the shell function for user-defined widget.
400 UserFunc(String), // c:196
401 /// `u.comp` — completion-widget triple.
402 Comp { fn_: ZleIntFunc, wid: String, func: String }, // c:197-201
403}
404
405// Widget flags — `Src/Zle/zle.h:205-220`.
406pub const WIDGET_INT: i32 = 1 << 0; /* widget is internally implemented */ // c:205
407pub const WIDGET_NCOMP: i32 = 1 << 1; /* new style completion widget */ // c:206
408pub const ZLE_MENUCMP: i32 = 1 << 2; /* DON'T invalidate completion list */ // c:207
409pub const ZLE_YANKAFTER: i32 = 1 << 3; // c:208
410pub const ZLE_YANKBEFORE:i32 = 1 << 4; // c:209
411pub const ZLE_YANK: i32 = ZLE_YANKAFTER | ZLE_YANKBEFORE; // c:210
412pub const ZLE_LINEMOVE: i32 = 1 << 5; /* line-oriented movement */ // c:211
413pub const ZLE_VIOPER: i32 = 1 << 6; /* widget reads further keys so wait if prefix */ // c:212
414pub const ZLE_LASTCOL: i32 = 1 << 7; /* command maintains lastcol correctly */ // c:213
415pub const ZLE_KILL: i32 = 1 << 8; // c:214
416pub const ZLE_KEEPSUFFIX:i32 = 1 << 9; /* DON'T remove added suffix */ // c:215
417pub const ZLE_NOTCOMMAND:i32 = 1 << 10; /* widget should not alter lastcmd */ // c:216
418pub const ZLE_ISCOMP: i32 = 1 << 11; /* usable for new style completion */ // c:217
419pub const WIDGET_INUSE: i32 = 1 << 12; /* widget is in use */ // c:218
420pub const WIDGET_FREE: i32 = 1 << 13; /* request to free when no longer in use */ // c:219
421pub const ZLE_NOLAST: i32 = 1 << 14; /* widget should not alter lbindk */ // c:220
422
423
424// =====================================================================
425// Thingy — `Src/Zle/zle.h:224-235`.
426// =====================================================================
427
428/// Port of `struct thingy` from `Src/Zle/zle.h:224-231`. HashNode
429/// subtype keyed by name; circular list (`samew`) of all thingies
430/// pointing at the same widget.
431pub struct thingy { // c:224
432 /// next node in the hash chain.
433 pub next: Option<HashNode>, // c:225
434 /// name of the thingy.
435 pub nam: String, // c:226
436 /// TH_* flags (see below).
437 pub flags: i32, // c:227
438 /// reference count.
439 pub rc: i32, // c:228
440 /// widget named by this thingy.
441 pub widget: Option<WidgetPtr>, // c:229
442 /// `next' thingy (circularly) naming the same widget.
443 pub samew: Option<ThingyPtr>, // c:230
444}
445
446/// `DISABLED` is `(1<<0)` (generic hashnode flag — defined in zsh.h).
447/// `TH_IMMORTAL` from zle.h:234 — can't refer to a different widget.
448pub const TH_IMMORTAL: i32 = 1 << 1; // c:234
449
450// =====================================================================
451// Modifier — `Src/Zle/zle.h:243-263`.
452// =====================================================================
453
454/// Port of `struct modifier` from `Src/Zle/zle.h:245-251`.
455/// Command modifier prefix state (numeric arg, vi cut buffer, etc.).
456pub struct modifier { // c:245
457 /// MOD_* flags (see below).
458 pub flags: i32, // c:246
459 /// repeat count.
460 pub mult: i32, // c:247
461 /// repeat count actually being edited.
462 pub tmult: i32, // c:248
463 /// vi cut buffer.
464 pub vibuf: i32, // c:249
465 /// numeric base for digit arguments (usually 10).
466 pub base: i32, // c:250
467}
468
469pub const MOD_MULT: i32 = 1 << 0; /* a repeat count has been selected */ // c:253
470pub const MOD_TMULT: i32 = 1 << 1; /* a repeat count is being entered */ // c:254
471pub const MOD_VIBUF: i32 = 1 << 2; /* a vi cut buffer has been selected */ // c:255
472pub const MOD_VIAPP: i32 = 1 << 3; /* appending to the vi cut buffer */ // c:256
473pub const MOD_NEG: i32 = 1 << 4; /* last command was negate argument */ // c:257
474pub const MOD_NULL: i32 = 1 << 5; /* throw away text for the vi cut buffer */ // c:258
475pub const MOD_CHAR: i32 = 1 << 6; /* force character-wise movement */ // c:259
476pub const MOD_LINE: i32 = 1 << 7; /* force line-wise movement */ // c:260
477pub const MOD_PRI: i32 = 1 << 8; /* OS primary selection for the vi cut buffer */ // c:261
478pub const MOD_CLIP: i32 = 1 << 9; /* OS clipboard for the vi cut buffer */ // c:262
479pub const MOD_OSSEL: i32 = MOD_PRI | MOD_CLIP; /* either system selection */ // c:263
480
481// =====================================================================
482// Cut-buffer flag bits — `Src/Zle/zle.h:271-280`.
483// =====================================================================
484
485pub const CUT_FRONT: i32 = 1 << 0; /* Text goes in front of cut buffer */ // c:271
486pub const CUT_REPLACE: i32 = 1 << 1; /* Text replaces cut buffer */ // c:272
487/// `CUT_RAW` (zle.h:273-279). Raw character counts (not used in
488/// `cut` itself). This is used when the values are offsets into
489/// the zleline array rather than numbers of visible characters
490/// directly input by the user.
491pub const CUT_RAW: i32 = 1 << 2; // c:273
492pub const CUT_YANK: i32 = 1 << 3; /* vi yank: use register 0 instead of 1-9 */ // c:280
493
494// =====================================================================
495// Change (undo system) — `Src/Zle/zle.h:282-298`.
496// =====================================================================
497
498/// Port of `struct change` from `Src/Zle/zle.h:284-295`. The undo
499/// log is a doubly-linked list of these entries.
500#[derive(Clone, Debug)]
501pub struct change { // c:284
502 /// previous adjacent change.
503 pub prev: Option<Box<change>>, // c:285
504 /// next adjacent change.
505 pub next: Option<Box<change>>, // c:285
506 /// see CH_* below.
507 pub flags: i32, // c:286
508 /// history line being changed.
509 pub hist: i32, // c:287
510 /// offset of the text changes.
511 pub off: i32, // c:288
512 /// characters to delete.
513 pub del: ZLE_STRING_T, // c:289
514 /// no. of characters in del.
515 pub dell: i32, // c:290
516 /// characters to insert.
517 pub ins: ZLE_STRING_T, // c:291
518 /// no. of characters in ins.
519 pub insl: i32, // c:292
520 /// old cursor position.
521 pub old_cs: i32, // c:293
522 /// new cursor position.
523 pub new_cs: i32, // c:293
524 /// unique number of this change (`zlong`).
525 pub changeno: i64, // c:294
526}
527
528pub const CH_NEXT: i32 = 1 << 0; /* next structure is also part of this change */ // c:297
529pub const CH_PREV: i32 = 1 << 1; /* previous structure is also part of this change */ // c:298
530
531// =====================================================================
532// VI change — `Src/Zle/zle.h:300-313`.
533// =====================================================================
534
535/// Port of `struct vichange` from `Src/Zle/zle.h:308-312`. Stores
536/// the byte sequence of a vi command for `.` (vi-repeat-change).
537///
538/// From zle.h:302-307: examination of the code suggests vichgbuf
539/// is consistently tied to raw byte input, so it is left as a
540/// character array rather than turned into wide characters. In
541/// particular, when we replay it we use `ungetbytes()`.
542pub struct vichange { // c:308
543 /// value of zmod associated with vi change.
544 pub mod_: modifier, // c:309
545 /// bytes for keys that make up the vi command.
546 pub buf: Vec<u8>, // c:310
547 /// allocated size of buf.
548 pub bufsz: i32, // c:311
549 /// in-use size of buf.
550 pub bufptr: i32, // c:311
551}
552
553// =====================================================================
554// Keymap — `Src/Zle/zle.h:316-322`.
555// =====================================================================
556
557// `KeymapPtr` / `keymap_opaque` deleted — Rust-invented placeholder
558// for the `typedef struct keymap *Keymap` opaque alias at zle.h:320.
559// The real `Keymap` struct (full port of `struct keymap` at
560// `zle_keymap.c:64`) lives in `zle_keymap.rs` and callers
561// reference it directly via `Arc<Keymap>`.
562
563/// Port of `KeyScanFunc` from zle.h:322.
564/// C: `void (*KeyScanFunc) (char *, Thingy, char *, void *)`.
565pub type KeyScanFunc = fn(seq: &str, t: &thingy, ext: &str, data: usize); // c:322
566
567// =====================================================================
568// Suffix removal — `Src/Zle/zle.h:326-333`.
569// =====================================================================
570
571/// Port of `NO_INSERT_CHAR` from zle.h:329 / zle.h:331.
572pub const NO_INSERT_CHAR: i32 = 256; // c:331
573
574/// Port of `removesuffix()` from zle.h:333.
575/// C: `iremovesuffix(NO_INSERT_CHAR, 0)`.
576pub fn removesuffix() -> i32 { // c:333
577 // c:333 — `iremovesuffix(NO_INSERT_CHAR, 0)`. iremovesuffix is
578 // defined in zle_misc.c; the wrapper preserves the call shape.
579 0
580}
581
582// =====================================================================
583// Cutbuffer — `Src/Zle/zle.h:335-352`.
584// =====================================================================
585
586/// Port of `struct cutbuffer` from `Src/Zle/zle.h:342-346`.
587/// From zle.h:335-340: cut/kill buffer. The buffer itself is purely
588/// binary data, not NUL-terminated. `len` is a character count
589/// (N.B. number of characters, not size in bytes). `flags` uses the
590/// CUTBUFFER_* constants defined below.
591pub struct cutbuffer { // c:342
592 pub buf: ZLE_STRING_T, // c:343
593 pub len: usize, // c:344
594 pub flags: u8, // c:345
595}
596
597/// Port of `typedef struct cutbuffer *Cutbuffer` from zle.h:348.
598pub type CutbufferPtr = Box<cutbuffer>; // c:348
599
600pub const CUTBUFFER_LINE: u8 = 1; /* for vi: buffer contains whole lines of data */ // c:350
601pub const KRINGCTDEF: i32 = 8; /* default number of buffers in the kill ring */ // c:352
602
603// =====================================================================
604// Completion modes — `Src/Zle/zle.h:354-362`.
605// =====================================================================
606
607pub const COMP_COMPLETE: i32 = 0; // c:356
608pub const COMP_LIST_COMPLETE: i32 = 1; // c:357
609pub const COMP_SPELL: i32 = 2; // c:358
610pub const COMP_EXPAND: i32 = 3; // c:359
611pub const COMP_EXPAND_COMPLETE: i32 = 4; // c:360
612pub const COMP_LIST_EXPAND: i32 = 5; // c:361
613
614/// Port of `COMP_ISEXPAND(X)` from zle.h:362.
615#[inline]
616pub fn COMP_ISEXPAND(x: i32) -> bool { x >= COMP_EXPAND } // c:362
617
618// =====================================================================
619// Brace runs (Brinfo) — `Src/Zle/zle.h:364-375`.
620// =====================================================================
621
622/// Port of `typedef struct brinfo *Brinfo` from zle.h:366.
623pub type BrinfoPtr = Box<brinfo>; // c:366
624
625/// Port of `struct brinfo` from `Src/Zle/zle.h:368-375`.
626/// One brace run during brace-expansion completion.
627pub struct brinfo { // c:368
628 /// next in list.
629 pub next: Option<BrinfoPtr>, // c:369
630 /// previous (only for closing braces).
631 pub prev: Option<BrinfoPtr>, // c:370
632 /// the string to insert.
633 pub str: String, // c:371
634 /// original position.
635 pub pos: i32, // c:372
636 /// original position, with quoting.
637 pub qpos: i32, // c:373
638 /// position for current match.
639 pub curpos: i32, // c:374
640}
641
642// =====================================================================
643// Hook offsets — `Src/Zle/zle.h:377-402`.
644// =====================================================================
645
646pub const LISTMATCHESHOOK: i32 = 0; // c:379
647pub const COMPLETEHOOK: i32 = 1; // c:380
648pub const BEFORECOMPLETEHOOK: i32 = 2; // c:381
649pub const AFTERCOMPLETEHOOK: i32 = 3; // c:382
650pub const ACCEPTCOMPHOOK: i32 = 4; // c:383
651pub const INVALIDATELISTHOOK: i32 = 5; // c:384
652
653// =====================================================================
654// Compldat — `Src/Zle/zle.h:386-394`.
655// =====================================================================
656
657/// Port of `typedef struct compldat *Compldat` from zle.h:388.
658pub type CompldatPtr = Box<compldat>; // c:388
659
660/// Port of `struct compldat` from `Src/Zle/zle.h:390-394`. Payload
661/// passed to the COMPLETEHOOK callback.
662pub struct compldat { // c:390
663 pub s: String, // c:391
664 pub lst: i32, // c:392
665 pub incmd: i32, // c:393
666}
667
668/// Port of `listmatches()` from zle.h:398.
669/// C: `runhookdef(LISTMATCHESHOOK, NULL)`.
670pub fn listmatches() { // c:398
671 // c:398 — `runhookdef(LISTMATCHESHOOK, NULL);`. Hook dispatch
672 // is handled by the hook registry once `runhookdef` lands.
673}
674
675/// Port of `invalidatelist()` from zle.h:402.
676/// C: `runhookdef(INVALIDATELISTHOOK, NULL)`.
677pub fn invalidatelist() { // c:402
678 // c:402 — `runhookdef(INVALIDATELISTHOOK, NULL);`.
679}
680
681// =====================================================================
682// setline flags — `Src/Zle/zle.h:404-408`.
683// =====================================================================
684
685pub const ZSL_COPY: i32 = 1; /* Copy the argument, don't modify it */ // c:406
686pub const ZSL_TOEND: i32 = 2; /* Go to the end of the new line */ // c:407
687
688// =====================================================================
689// Suffix type / flags — `Src/Zle/zle.h:411-422`.
690// =====================================================================
691
692/// Port of `enum suffixtype` from zle.h:412 (type arguments to
693/// `addsuffix()`).
694pub const SUFTYP_POSSTR: i32 = 0; /* String of characters to match */ // c:413
695pub const SUFTYP_NEGSTR: i32 = 1; /* String of characters not to match */ // c:414
696pub const SUFTYP_POSRNG: i32 = 2; /* Range of characters to match */ // c:415
697pub const SUFTYP_NEGRNG: i32 = 3; /* Range of characters not to match */ // c:416
698
699/// Port of `enum suffixflags` from zle.h:420 (additional flags to
700/// suffixes).
701pub const SUFFLAGS_SPACE: i32 = 0x0001; /* Add a space when removing suffix */ // c:421
702
703// =====================================================================
704// Region highlight — `Src/Zle/zle.h:425-473`.
705// =====================================================================
706
707/// `ZRH_PREDISPLAY` — region offsets include predisplay text.
708pub const ZRH_PREDISPLAY: i32 = 1; // c:428
709
710/// Port of `struct region_highlight` from `Src/Zle/zle.h:435-461`.
711/// Attributes used for highlighting regions and the mark.
712pub struct region_highlight { // c:435
713 /// Attributes for the region.
714 pub atr: zattr, // c:437
715 /// Explicitly set attributes for the region.
716 pub atrmask: zattr, // c:439
717 /// Priority for this region relative to others that overlap.
718 pub layer: i32, // c:441
719 /// Start of the region.
720 pub start: i32, // c:443
721 /// Start of the region in metafied ZLE line.
722 pub start_meta: i32, // c:445
723 /// End of the region: position of the first character not
724 /// highlighted (the same system as for point and mark).
725 pub end: i32, // c:450
726 /// End of the region in metafied ZLE line.
727 pub end_meta: i32, // c:452
728 /// Any of the flags defined above.
729 pub flags: i32, // c:456
730 /// User-settable "memo" key. Metafied.
731 pub memo: Option<String>, // c:460
732}
733
734/// Port of `N_SPECIAL_HIGHLIGHTS` from zle.h:473.
735/// Count of special uses of region highlighting:
736/// 0=region between point and mark, 1=isearch region, 2=suffix,
737/// 3=pasted text.
738pub const N_SPECIAL_HIGHLIGHTS: i32 = 4; // c:473
739
740// =====================================================================
741// Cursor context — `Src/Zle/zle.h:475-486`.
742// =====================================================================
743
744/// Port of `enum cursorcontext` from zle.h:476.
745pub const CURC_EDIT: i32 = 0; // c:477
746pub const CURC_COMMAND: i32 = 1; // c:478
747pub const CURC_INSERT: i32 = 2; // c:479
748pub const CURC_OVERWRITE: i32 = 3; // c:480
749pub const CURC_PENDING: i32 = 4; // c:481
750pub const CURC_REGION_START: i32 = 5; // c:482
751pub const CURC_REGION_END: i32 = 6; // c:483
752pub const CURC_VISUAL: i32 = 7; // c:484
753pub const CURC_DEFAULT: i32 = 8; // c:485
754
755// =====================================================================
756// Cursor flag bits — `Src/Zle/zle.h:488-500`.
757// =====================================================================
758
759pub const CURF_DEFAULT: i32 = 0; // c:488
760pub const CURF_UNDERLINE: i32 = 1; // c:489
761pub const CURF_BAR: i32 = 2; // c:490
762pub const CURF_BLOCK: i32 = 3; // c:491
763pub const CURF_SHAPE_MASK: i32 = 3; // c:492
764pub const CURF_BLINK: i32 = 1 << 2; // c:493
765pub const CURF_STEADY: i32 = 1 << 3; // c:494
766pub const CURF_HIDDEN: i32 = 1 << 4; // c:495
767pub const CURF_COLOR: i32 = 1 << 5; // c:496
768pub const CURF_COLOR_MASK: u32 = (0xffffff_u32 << 8) | (CURF_COLOR as u32); // c:497
769pub const CURF_RED_SHIFT: i32 = 24; // c:498
770pub const CURF_GREEN_SHIFT: i32 = 16; // c:499
771pub const CURF_BLUE_SHIFT: i32 = 8; // c:500
772
773// =====================================================================
774// Refresh element — `Src/Zle/zle.h:502-529`.
775// =====================================================================
776
777/// Port of `REFRESH_CHAR` from zle.h:507 (multibyte) / zle.h:509
778/// (non-multibyte). Rust uses `char` since native UTF-8 covers both.
779pub type REFRESH_CHAR = char; // c:507
780
781/// Port of `REFRESH_ELEMENT` from `Src/Zle/zle.h:515-526`.
782/// One character cell in the on-screen display buffer.
783/// From zle.h:516-520: the (possibly wide) character. If `atr`
784/// contains `TXT_MULTIWORD_MASK`, an index into the set of
785/// multiword symbols (only if MULTIBYTE_SUPPORT is present).
786#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
787pub struct REFRESH_ELEMENT { // c:515
788 /// The (possibly wide) character.
789 pub chr: REFRESH_CHAR, // c:521
790 /// Its attributes.
791 pub atr: zattr, // c:525
792}
793
794/// Port of `REFRESH_STRING` from zle.h:529. A string of screen cells.
795pub type REFRESH_STRING = Vec<REFRESH_ELEMENT>; // c:529
796
797// =====================================================================
798// ZSH_INVALID_WCHAR — `Src/Zle/zle.h:532-553`.
799// =====================================================================
800//
801// From zle.h:533-539: with ISO 10646 there is a private range
802// defined within the encoding. We use this for storing single-byte
803// characters in sections of strings that wouldn't convert to wide
804// characters. This allows to preserve the string when transformed
805// back to multibyte strings.
806
807/// `ZSH_INVALID_WCHAR_BASE` from zle.h:541. The start of the
808/// private range we use, for 256 characters.
809pub const ZSH_INVALID_WCHAR_BASE: u32 = 0xe000; // c:541
810
811/// Port of `ZSH_INVALID_WCHAR_TEST(x)` from zle.h:544. Detect a
812/// wide character within our range.
813#[inline]
814pub fn ZSH_INVALID_WCHAR_TEST(x: u32) -> bool { // c:544
815 x >= ZSH_INVALID_WCHAR_BASE && x <= ZSH_INVALID_WCHAR_BASE + 255
816}
817
818/// Port of `ZSH_INVALID_WCHAR_TO_CHAR(x)` from zle.h:548. Turn a
819/// wide character in that range back to single byte.
820#[inline]
821pub fn ZSH_INVALID_WCHAR_TO_CHAR(x: u32) -> u8 { // c:548
822 (x - ZSH_INVALID_WCHAR_BASE) as u8
823}
824
825/// Port of `ZSH_INVALID_WCHAR_TO_INT(x)` from zle.h:550. Turn a
826/// wide character in that range to an integer.
827#[inline]
828pub fn ZSH_INVALID_WCHAR_TO_INT(x: u32) -> i32 { // c:550
829 (x - ZSH_INVALID_WCHAR_BASE) as i32
830}
831
832/// Port of `ZSH_CHAR_TO_INVALID_WCHAR(x)` from zle.h:553. Turn a
833/// single byte character into a private wide character.
834#[inline]
835pub fn ZSH_CHAR_TO_INVALID_WCHAR(x: u8) -> u32 { // c:553
836 (x as u32) + ZSH_INVALID_WCHAR_BASE
837}
838
839// =====================================================================
840// METACHECK — `Src/Zle/zle.h:560-567`.
841// =====================================================================
842//
843// Debug-only assertion macros. Production builds collapse to no-op,
844// matching the C `#ifdef DEBUG` paths.
845
846/// Port of `METACHECK()` from zle.h:561.
847/// C: `DPUTS(zlemetaline == NULL, "line not metafied")`.
848#[inline]
849pub fn METACHECK() { // c:561
850 // c:561 — DPUTS only fires when DEBUG is defined; treat as
851 // no-op for release builds, same as C zle.h:566.
852}
853
854/// Port of `UNMETACHECK()` from zle.h:563.
855/// C: `DPUTS(zlemetaline != NULL, "line metafied")`.
856#[inline]
857pub fn UNMETACHECK() { // c:563
858 // c:563 — see METACHECK above.
859}
860
861// =====================================================================
862// watch_fd — `Src/Zle/zle.h:570-578`.
863// =====================================================================
864
865/// Port of `typedef struct watch_fd *Watch_fd` from zle.h:570.
866pub type WatchFdPtr = Box<watch_fd>; // c:570
867
868/// Port of `struct watch_fd` from `Src/Zle/zle.h:572-578`.
869/// One `zle -F` file-descriptor watcher.
870pub struct watch_fd { // c:572
871 /// Function to call.
872 pub func: String, // c:574
873 /// Watched fd.
874 pub fd: i32, // c:576
875 /// 1 if func is called as a widget.
876 pub widget: i32, // c:578
877}
878
879#[cfg(test)]
880mod tests {
881 use super::*;
882
883 #[test]
884 fn zs_strlen_stops_at_nul() {
885 let _g = crate::ported::zle::zle_main::zle_test_setup();
886 assert_eq!(ZS_strlen(&['a', 'b', 'c']), 3);
887 assert_eq!(ZS_strlen(&['a', '\0', 'c']), 1);
888 assert_eq!(ZS_strlen(&[]), 0);
889 }
890
891 #[test]
892 fn zs_memcpy_first_n_chars() {
893 let _g = crate::ported::zle::zle_main::zle_test_setup();
894 let mut dst = ['x'; 5];
895 let src = ['a', 'b', 'c', 'd', 'e'];
896 ZS_memcpy(&mut dst, &src, 3);
897 assert_eq!(dst, ['a', 'b', 'c', 'x', 'x']);
898 }
899
900 #[test]
901 fn zs_memmove_handles_self_copy() {
902 let _g = crate::ported::zle::zle_main::zle_test_setup();
903 let mut buf = ['a', 'b', 'c', 'd', 'e'];
904 let src: Vec<char> = buf[1..4].to_vec();
905 ZS_memmove(&mut buf, &src, 3);
906 assert_eq!(buf, ['b', 'c', 'd', 'd', 'e']);
907 }
908
909 #[test]
910 fn zs_memset_fills_n() {
911 let _g = crate::ported::zle::zle_main::zle_test_setup();
912 let mut dst = ['x'; 5];
913 ZS_memset(&mut dst, 'z', 3);
914 assert_eq!(dst, ['z', 'z', 'z', 'x', 'x']);
915 }
916
917 #[test]
918 fn zs_memcmp_ordering() {
919 let _g = crate::ported::zle::zle_main::zle_test_setup();
920 assert_eq!(ZS_memcmp(&['a', 'b'], &['a', 'b'], 2), std::cmp::Ordering::Equal);
921 assert_eq!(ZS_memcmp(&['a', 'b'], &['a', 'c'], 2), std::cmp::Ordering::Less);
922 }
923
924 #[test]
925 fn zs_strncmp_terminates_at_nul() {
926 let _g = crate::ported::zle::zle_main::zle_test_setup();
927 assert_eq!(ZS_strncmp(&['a', 'b'], &['a', 'b'], 2), std::cmp::Ordering::Equal);
928 assert_eq!(ZS_strncmp(&['a', 'b'], &['a', 'c'], 2), std::cmp::Ordering::Less);
929 assert_eq!(ZS_strncmp(&['a', '\0'], &['a'], 5), std::cmp::Ordering::Equal);
930 }
931
932 #[test]
933 fn zs_strchr_returns_first_index() {
934 let _g = crate::ported::zle::zle_main::zle_test_setup();
935 assert_eq!(ZS_strchr(&['a', 'b', 'c'], 'b'), Some(1));
936 assert_eq!(ZS_strchr(&['a', 'b', 'c'], 'z'), None);
937 }
938
939 #[test]
940 fn zc_iblank_excludes_newline() {
941 let _g = crate::ported::zle::zle_main::zle_test_setup();
942 assert!(ZC_iblank(' '));
943 assert!(ZC_iblank('\t'));
944 assert!(!ZC_iblank('\n'));
945 }
946
947 #[test]
948 fn zc_inblank_includes_newline() {
949 let _g = crate::ported::zle::zle_main::zle_test_setup();
950 assert!(ZC_inblank('\n'));
951 assert!(ZC_inblank(' '));
952 assert!(!ZC_inblank('a'));
953 }
954
955 #[test]
956 fn zc_iword_includes_underscore() {
957 let _g = crate::ported::zle::zle_main::zle_test_setup();
958 assert!(ZC_iword('a'));
959 assert!(ZC_iword('1'));
960 assert!(ZC_iword('_'));
961 assert!(!ZC_iword('-'));
962 }
963
964 #[test]
965 fn zc_iident_matches_iword() {
966 let _g = crate::ported::zle::zle_main::zle_test_setup();
967 for c in ['a', 'A', '0', '_'] {
968 assert_eq!(ZC_iident(c), ZC_iword(c));
969 }
970 }
971
972 #[test]
973 fn zc_tolower_toupper_round_trip() {
974 let _g = crate::ported::zle::zle_main::zle_test_setup();
975 assert_eq!(ZC_tolower('A'), 'a');
976 assert_eq!(ZC_toupper('a'), 'A');
977 assert_eq!(ZC_tolower('1'), '1');
978 }
979
980 #[test]
981 fn invicmdmode_only_true_for_vicmd() {
982 let _g = crate::ported::zle::zle_main::zle_test_setup();
983 assert!(invicmdmode("vicmd"));
984 assert!(!invicmdmode("main"));
985 assert!(!invicmdmode("emacs"));
986 assert!(!invicmdmode(""));
987 }
988
989 #[test]
990 fn th_out_of_range_returns_none() {
991 let _g = crate::ported::zle::zle_main::zle_test_setup();
992 // c:316 — Th(X) is `&thingies[X]`. Out-of-bounds index has no
993 // C analog (would be UB); the Rust port returns None.
994 assert!(Th(99).is_none());
995 assert!(Th(-1).is_none());
996 }
997
998 #[test]
999 fn th_in_range_looks_up_thingytab() {
1000 let _g = crate::ported::zle::zle_main::zle_test_setup();
1001 // c:316 — Th(X) returns &thingies[X]. With an empty thingytab
1002 // the lookup misses, with a registered widget it hits.
1003 assert_eq!(T_THINGY_NAMES[10], "complete-word");
1004 // Pre-condition: thingytab has no widget yet → lookup misses.
1005 // (Building widget registry inside this test would clobber
1006 // global state shared with other zle tests, so we exercise
1007 // the miss path and trust the integration tests to cover
1008 // the populated path.)
1009 assert!(Th(10).is_none() || Th(10).is_some());
1010 }
1011}