1use crate::{layout::GraphemeClusterMode, Result};
3use std::default::Default;
4
5#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct Config {
8 max_history_size: usize, history_duplicates: HistoryDuplicates,
11 history_ignore_space: bool,
12 completion_type: CompletionType,
13 completion_show_all_if_ambiguous: bool,
16 completion_prompt_limit: usize,
19 keyseq_timeout: Option<u16>,
22 edit_mode: EditMode,
24 auto_add_history: bool,
27 bell_style: BellStyle,
29 color_mode: ColorMode,
31 grapheme_cluster_mode: GraphemeClusterMode,
33 behavior: Behavior,
35 tab_stop: u8,
37 indent_size: u8,
39 check_cursor_position: bool,
41 enable_bracketed_paste: bool,
43 enable_synchronized_output: bool,
45 enable_signals: bool,
47}
48
49impl Config {
50 #[must_use]
52 pub fn builder() -> Builder {
53 Builder::new()
54 }
55
56 #[must_use]
58 pub fn max_history_size(&self) -> usize {
59 self.max_history_size
60 }
61
62 pub(crate) fn set_max_history_size(&mut self, max_size: usize) {
63 self.max_history_size = max_size;
64 }
65
66 #[must_use]
71 pub fn history_duplicates(&self) -> HistoryDuplicates {
72 self.history_duplicates
73 }
74
75 pub(crate) fn set_history_ignore_dups(&mut self, yes: bool) {
76 self.history_duplicates = if yes {
77 HistoryDuplicates::IgnoreConsecutive
78 } else {
79 HistoryDuplicates::AlwaysAdd
80 };
81 }
82
83 #[must_use]
88 pub fn history_ignore_space(&self) -> bool {
89 self.history_ignore_space
90 }
91
92 pub(crate) fn set_history_ignore_space(&mut self, yes: bool) {
93 self.history_ignore_space = yes;
94 }
95
96 #[must_use]
100 pub fn completion_type(&self) -> CompletionType {
101 self.completion_type
102 }
103
104 #[must_use]
108 pub fn completion_prompt_limit(&self) -> usize {
109 self.completion_prompt_limit
110 }
111
112 #[must_use]
116 pub fn completion_show_all_if_ambiguous(&self) -> bool {
117 self.completion_show_all_if_ambiguous
118 }
119
120 #[must_use]
126 pub fn keyseq_timeout(&self) -> Option<u16> {
127 self.keyseq_timeout
128 }
129
130 #[must_use]
132 pub fn edit_mode(&self) -> EditMode {
133 self.edit_mode
134 }
135
136 #[must_use]
140 pub fn auto_add_history(&self) -> bool {
141 self.auto_add_history
142 }
143
144 #[must_use]
146 pub fn bell_style(&self) -> BellStyle {
147 self.bell_style
148 }
149
150 #[must_use]
155 pub fn color_mode(&self) -> ColorMode {
156 if self.color_mode == ColorMode::Enabled
157 && std::env::var_os("NO_COLOR").is_some_and(|os| !os.is_empty())
158 {
159 return ColorMode::Disabled;
160 }
161 self.color_mode
162 }
163
164 #[must_use]
166 pub fn grapheme_cluster_mode(&self) -> GraphemeClusterMode {
167 self.grapheme_cluster_mode
168 }
169
170 pub(crate) fn set_color_mode(&mut self, color_mode: ColorMode) {
171 self.color_mode = color_mode;
172 }
173
174 #[must_use]
178 pub fn behavior(&self) -> Behavior {
179 self.behavior
180 }
181
182 pub(crate) fn set_behavior(&mut self, behavior: Behavior) {
183 self.behavior = behavior;
184 }
185
186 #[must_use]
190 pub fn tab_stop(&self) -> u8 {
191 self.tab_stop
192 }
193
194 pub(crate) fn set_tab_stop(&mut self, tab_stop: u8) {
195 self.tab_stop = tab_stop;
196 }
197
198 #[must_use]
202 pub fn check_cursor_position(&self) -> bool {
203 self.check_cursor_position
204 }
205
206 #[must_use]
210 pub fn indent_size(&self) -> u8 {
211 self.indent_size
212 }
213
214 pub(crate) fn set_indent_size(&mut self, indent_size: u8) {
215 self.indent_size = indent_size;
216 }
217
218 #[must_use]
222 pub fn enable_bracketed_paste(&self) -> bool {
223 self.enable_bracketed_paste
224 }
225
226 #[must_use]
230 pub fn enable_synchronized_output(&self) -> bool {
231 self.enable_synchronized_output
232 }
233
234 #[must_use]
238 pub fn enable_signals(&self) -> bool {
239 self.enable_signals
240 }
241
242 pub(crate) fn set_enable_signals(&mut self, enable_signals: bool) {
243 self.enable_signals = enable_signals;
244 }
245}
246
247impl Default for Config {
248 fn default() -> Self {
249 Self {
250 max_history_size: 100,
251 history_duplicates: HistoryDuplicates::IgnoreConsecutive,
252 history_ignore_space: false,
253 completion_type: CompletionType::Circular, completion_prompt_limit: 100,
255 completion_show_all_if_ambiguous: false,
256 keyseq_timeout: None,
257 edit_mode: EditMode::Emacs,
258 auto_add_history: false,
259 bell_style: BellStyle::default(),
260 color_mode: ColorMode::Enabled,
261 grapheme_cluster_mode: GraphemeClusterMode::from_env(),
262 behavior: Behavior::default(),
263 tab_stop: 8,
264 indent_size: 2,
265 check_cursor_position: false,
266 enable_bracketed_paste: true,
267 enable_synchronized_output: true,
268 enable_signals: false,
269 }
270 }
271}
272
273#[derive(Clone, Copy, Debug, PartialEq, Eq)]
275pub enum BellStyle {
276 Audible,
278 None,
280 Visible,
282}
283
284impl Default for BellStyle {
287 #[cfg(any(windows, target_arch = "wasm32"))]
288 fn default() -> Self {
289 Self::None
290 }
291
292 #[cfg(unix)]
293 fn default() -> Self {
294 Self::Audible
295 }
296}
297
298#[derive(Clone, Copy, Debug, PartialEq, Eq)]
300pub enum HistoryDuplicates {
301 AlwaysAdd,
303 IgnoreConsecutive,
305}
306
307#[derive(Clone, Copy, Debug, PartialEq, Eq)]
309#[non_exhaustive]
310pub enum CompletionType {
311 Circular,
313 List,
317
318 #[cfg(all(unix, feature = "with-fuzzy"))]
323 Fuzzy,
324}
325
326#[derive(Clone, Copy, Debug, PartialEq, Eq)]
328#[non_exhaustive]
329pub enum EditMode {
330 Emacs,
332 Vi,
334}
335
336#[derive(Clone, Copy, Debug, PartialEq, Eq)]
338#[non_exhaustive]
339pub enum ColorMode {
340 Enabled,
342 Forced,
344 Disabled,
346}
347
348#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
350#[non_exhaustive]
351pub enum Behavior {
352 #[default]
354 Stdio,
355 PreferTerm,
358 }
362
363#[derive(Clone, Debug, Default)]
365pub struct Builder {
366 p: Config,
367}
368
369impl Builder {
370 #[must_use]
372 pub fn new() -> Self {
373 Self {
374 p: Config::default(),
375 }
376 }
377
378 pub fn max_history_size(mut self, max_size: usize) -> Result<Self> {
380 self.set_max_history_size(max_size)?;
381 Ok(self)
382 }
383
384 pub fn history_ignore_dups(mut self, yes: bool) -> Result<Self> {
389 self.set_history_ignore_dups(yes)?;
390 Ok(self)
391 }
392
393 #[must_use]
398 pub fn history_ignore_space(mut self, yes: bool) -> Self {
399 self.set_history_ignore_space(yes);
400 self
401 }
402
403 #[must_use]
405 pub fn completion_type(mut self, completion_type: CompletionType) -> Self {
406 self.set_completion_type(completion_type);
407 self
408 }
409
410 #[must_use]
413 pub fn completion_prompt_limit(mut self, completion_prompt_limit: usize) -> Self {
414 self.set_completion_prompt_limit(completion_prompt_limit);
415 self
416 }
417
418 #[must_use]
423 pub fn completion_show_all_if_ambiguous(
424 mut self,
425 completion_show_all_if_ambiguous: bool,
426 ) -> Self {
427 self.set_completion_show_all_if_ambiguous(completion_show_all_if_ambiguous);
428 self
429 }
430
431 #[must_use]
437 pub fn keyseq_timeout(mut self, keyseq_timeout_ms: Option<u16>) -> Self {
438 self.set_keyseq_timeout(keyseq_timeout_ms);
439 self
440 }
441
442 #[must_use]
444 pub fn edit_mode(mut self, edit_mode: EditMode) -> Self {
445 self.set_edit_mode(edit_mode);
446 self
447 }
448
449 #[must_use]
453 pub fn auto_add_history(mut self, yes: bool) -> Self {
454 self.set_auto_add_history(yes);
455 self
456 }
457
458 #[must_use]
460 pub fn bell_style(mut self, bell_style: BellStyle) -> Self {
461 self.set_bell_style(bell_style);
462 self
463 }
464
465 #[must_use]
469 pub fn color_mode(mut self, color_mode: ColorMode) -> Self {
470 self.set_color_mode(color_mode);
471 self
472 }
473
474 #[must_use]
476 pub fn grapheme_cluster_mode(mut self, grapheme_cluster_mode: GraphemeClusterMode) -> Self {
477 self.set_grapheme_cluster_mode(grapheme_cluster_mode);
478 self
479 }
480
481 #[must_use]
485 pub fn behavior(mut self, behavior: Behavior) -> Self {
486 self.p.set_behavior(behavior); self
488 }
489
490 #[must_use]
494 pub fn tab_stop(mut self, tab_stop: u8) -> Self {
495 self.set_tab_stop(tab_stop);
496 self
497 }
498
499 #[must_use]
503 pub fn check_cursor_position(mut self, yes: bool) -> Self {
504 self.set_check_cursor_position(yes);
505 self
506 }
507
508 #[must_use]
512 pub fn indent_size(mut self, indent_size: u8) -> Self {
513 self.set_indent_size(indent_size);
514 self
515 }
516
517 #[must_use]
521 pub fn bracketed_paste(mut self, enabled: bool) -> Self {
522 self.enable_bracketed_paste(enabled);
523 self
524 }
525
526 #[must_use]
530 pub fn enable_signals(mut self, enable_signals: bool) -> Self {
531 self.set_enable_signals(enable_signals);
532 self
533 }
534
535 #[must_use]
537 pub fn build(self) -> Config {
538 self.p
539 }
540}
541
542impl Configurer for Builder {
543 fn config_mut(&mut self) -> &mut Config {
544 &mut self.p
545 }
546}
547
548pub trait Configurer {
550 fn config_mut(&mut self) -> &mut Config;
552
553 fn set_max_history_size(&mut self, max_size: usize) -> Result<()> {
555 self.config_mut().set_max_history_size(max_size);
556 Ok(())
557 }
558
559 fn set_history_ignore_dups(&mut self, yes: bool) -> Result<()> {
564 self.config_mut().set_history_ignore_dups(yes);
565 Ok(())
566 }
567
568 fn set_history_ignore_space(&mut self, yes: bool) {
573 self.config_mut().set_history_ignore_space(yes);
574 }
575 fn set_completion_type(&mut self, completion_type: CompletionType) {
577 self.config_mut().completion_type = completion_type;
578 }
579
580 fn set_completion_show_all_if_ambiguous(&mut self, completion_show_all_if_ambiguous: bool) {
585 self.config_mut().completion_show_all_if_ambiguous = completion_show_all_if_ambiguous;
586 }
587
588 fn set_completion_prompt_limit(&mut self, completion_prompt_limit: usize) {
591 self.config_mut().completion_prompt_limit = completion_prompt_limit;
592 }
593
594 fn set_keyseq_timeout(&mut self, keyseq_timeout_ms: Option<u16>) {
596 self.config_mut().keyseq_timeout = keyseq_timeout_ms;
597 }
598
599 fn set_edit_mode(&mut self, edit_mode: EditMode) {
601 self.config_mut().edit_mode = edit_mode;
602 match edit_mode {
603 EditMode::Emacs => self.set_keyseq_timeout(None), EditMode::Vi => self.set_keyseq_timeout(Some(500)),
605 }
606 }
607
608 fn set_auto_add_history(&mut self, yes: bool) {
612 self.config_mut().auto_add_history = yes;
613 }
614
615 fn set_bell_style(&mut self, bell_style: BellStyle) {
617 self.config_mut().bell_style = bell_style;
618 }
619
620 fn set_color_mode(&mut self, color_mode: ColorMode) {
624 self.config_mut().set_color_mode(color_mode);
625 }
626
627 fn set_grapheme_cluster_mode(&mut self, grapheme_cluster_mode: GraphemeClusterMode) {
629 self.config_mut().grapheme_cluster_mode = grapheme_cluster_mode;
630 }
631
632 fn set_tab_stop(&mut self, tab_stop: u8) {
636 self.config_mut().set_tab_stop(tab_stop);
637 }
638
639 fn set_check_cursor_position(&mut self, yes: bool) {
643 self.config_mut().check_cursor_position = yes;
644 }
645 fn set_indent_size(&mut self, size: u8) {
649 self.config_mut().set_indent_size(size);
650 }
651
652 fn enable_bracketed_paste(&mut self, enabled: bool) {
656 self.config_mut().enable_bracketed_paste = enabled;
657 }
658
659 fn enable_synchronized_output(&mut self, enabled: bool) {
663 self.config_mut().enable_synchronized_output = enabled;
664 }
665
666 fn set_enable_signals(&mut self, enable_signals: bool) {
670 self.config_mut().set_enable_signals(enable_signals);
671 }
672}