rustyline/
config.rs

1//! Customize line editor
2use std::default::Default;
3
4/// User preferences
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub struct Config {
7    /// Maximum number of entries in History.
8    max_history_size: usize, // history_max_entries
9    history_duplicates: HistoryDuplicates,
10    history_ignore_space: bool,
11    completion_type: CompletionType,
12    /// When listing completion alternatives, only display
13    /// one screen of possibilities at a time.
14    completion_prompt_limit: usize,
15    /// Duration (milliseconds) Rustyline will wait for a character when
16    /// reading an ambiguous key sequence.
17    keyseq_timeout: i32,
18    /// Emacs or Vi mode
19    edit_mode: EditMode,
20    /// If true, each nonblank line returned by `readline` will be
21    /// automatically added to the history.
22    auto_add_history: bool,
23    /// Beep or Flash or nothing
24    bell_style: BellStyle,
25    /// if colors should be enabled.
26    color_mode: ColorMode,
27    /// Whether to use stdio or not
28    behavior: Behavior,
29    /// Horizontal space taken by a tab.
30    tab_stop: usize,
31    /// Indentation size for indent/dedent commands
32    indent_size: usize,
33    /// Check if cursor position is at leftmost before displaying prompt
34    check_cursor_position: bool,
35    /// Bracketed paste on unix platform
36    enable_bracketed_paste: bool,
37}
38
39impl Config {
40    /// Returns a `Config` builder.
41    #[must_use]
42    pub fn builder() -> Builder {
43        Builder::new()
44    }
45
46    /// Tell the maximum length (i.e. number of entries) for the history.
47    #[must_use]
48    pub fn max_history_size(&self) -> usize {
49        self.max_history_size
50    }
51
52    pub(crate) fn set_max_history_size(&mut self, max_size: usize) {
53        self.max_history_size = max_size;
54    }
55
56    /// Tell if lines which match the previous history entry are saved or not
57    /// in the history list.
58    ///
59    /// By default, they are ignored.
60    #[must_use]
61    pub fn history_duplicates(&self) -> HistoryDuplicates {
62        self.history_duplicates
63    }
64
65    pub(crate) fn set_history_ignore_dups(&mut self, yes: bool) {
66        self.history_duplicates = if yes {
67            HistoryDuplicates::IgnoreConsecutive
68        } else {
69            HistoryDuplicates::AlwaysAdd
70        };
71    }
72
73    /// Tell if lines which begin with a space character are saved or not in
74    /// the history list.
75    ///
76    /// By default, they are saved.
77    #[must_use]
78    pub fn history_ignore_space(&self) -> bool {
79        self.history_ignore_space
80    }
81
82    pub(crate) fn set_history_ignore_space(&mut self, yes: bool) {
83        self.history_ignore_space = yes;
84    }
85
86    /// Completion behaviour.
87    ///
88    /// By default, `CompletionType::Circular`.
89    #[must_use]
90    pub fn completion_type(&self) -> CompletionType {
91        self.completion_type
92    }
93
94    /// When listing completion alternatives, only display
95    /// one screen of possibilities at a time (used for `CompletionType::List`
96    /// mode).
97    #[must_use]
98    pub fn completion_prompt_limit(&self) -> usize {
99        self.completion_prompt_limit
100    }
101
102    /// Duration (milliseconds) Rustyline will wait for a character when
103    /// reading an ambiguous key sequence (used for `EditMode::Vi` mode on unix
104    /// platform).
105    ///
106    /// By default, no timeout (-1) or 500ms if `EditMode::Vi` is activated.
107    #[must_use]
108    pub fn keyseq_timeout(&self) -> i32 {
109        self.keyseq_timeout
110    }
111
112    /// Emacs or Vi mode
113    #[must_use]
114    pub fn edit_mode(&self) -> EditMode {
115        self.edit_mode
116    }
117
118    /// Tell if lines are automatically added to the history.
119    ///
120    /// By default, they are not.
121    #[must_use]
122    pub fn auto_add_history(&self) -> bool {
123        self.auto_add_history
124    }
125
126    /// Bell style: beep, flash or nothing.
127    #[must_use]
128    pub fn bell_style(&self) -> BellStyle {
129        self.bell_style
130    }
131
132    /// Tell if colors should be enabled.
133    ///
134    /// By default, they are except if stdout is not a TTY.
135    #[must_use]
136    pub fn color_mode(&self) -> ColorMode {
137        self.color_mode
138    }
139
140    pub(crate) fn set_color_mode(&mut self, color_mode: ColorMode) {
141        self.color_mode = color_mode;
142    }
143
144    /// Whether to use stdio or not
145    ///
146    /// By default, stdio is used.
147    #[must_use]
148    pub fn behavior(&self) -> Behavior {
149        self.behavior
150    }
151
152    pub(crate) fn set_behavior(&mut self, behavior: Behavior) {
153        self.behavior = behavior;
154    }
155
156    /// Horizontal space taken by a tab.
157    ///
158    /// By default, 8.
159    #[must_use]
160    pub fn tab_stop(&self) -> usize {
161        self.tab_stop
162    }
163
164    pub(crate) fn set_tab_stop(&mut self, tab_stop: usize) {
165        self.tab_stop = tab_stop;
166    }
167
168    /// Check if cursor position is at leftmost before displaying prompt.
169    ///
170    /// By default, we don't check.
171    #[must_use]
172    pub fn check_cursor_position(&self) -> bool {
173        self.check_cursor_position
174    }
175
176    /// Indentation size used by indentation commands
177    ///
178    /// By default, 2.
179    #[must_use]
180    pub fn indent_size(&self) -> usize {
181        self.indent_size
182    }
183
184    pub(crate) fn set_indent_size(&mut self, indent_size: usize) {
185        self.indent_size = indent_size;
186    }
187
188    /// Bracketed paste on unix platform
189    ///
190    /// By default, it's enabled.
191    #[must_use]
192    pub fn enable_bracketed_paste(&self) -> bool {
193        self.enable_bracketed_paste
194    }
195}
196
197impl Default for Config {
198    fn default() -> Self {
199        Self {
200            max_history_size: 100,
201            history_duplicates: HistoryDuplicates::IgnoreConsecutive,
202            history_ignore_space: false,
203            completion_type: CompletionType::Circular, // TODO Validate
204            completion_prompt_limit: 100,
205            keyseq_timeout: -1,
206            edit_mode: EditMode::Emacs,
207            auto_add_history: false,
208            bell_style: BellStyle::default(),
209            color_mode: ColorMode::Enabled,
210            behavior: Behavior::default(),
211            tab_stop: 8,
212            indent_size: 2,
213            check_cursor_position: false,
214            enable_bracketed_paste: true,
215        }
216    }
217}
218
219/// Beep or flash or nothing
220#[derive(Clone, Copy, Debug, PartialEq, Eq)]
221pub enum BellStyle {
222    /// Beep
223    Audible,
224    /// Silent
225    None,
226    /// Flash screen (not supported)
227    Visible,
228}
229
230/// `Audible` by default on unix (overridden by current Terminal settings).
231/// `None` on windows.
232impl Default for BellStyle {
233    #[cfg(any(windows, target_arch = "wasm32"))]
234    fn default() -> Self {
235        BellStyle::None
236    }
237
238    #[cfg(unix)]
239    fn default() -> Self {
240        BellStyle::Audible
241    }
242}
243
244/// History filter
245#[derive(Clone, Copy, Debug, PartialEq, Eq)]
246pub enum HistoryDuplicates {
247    /// No filter
248    AlwaysAdd,
249    /// a line will not be added to the history if it matches the previous entry
250    IgnoreConsecutive,
251}
252
253/// Tab completion style
254#[derive(Clone, Copy, Debug, PartialEq, Eq)]
255#[non_exhaustive]
256pub enum CompletionType {
257    /// Complete the next full match (like in Vim by default)
258    Circular,
259    /// Complete till longest match.
260    /// When more than one match, list all matches
261    /// (like in Bash/Readline).
262    List,
263
264    /// Complete the match using fuzzy search and selection
265    /// (like fzf and plugins)
266    /// Currently only available for unix platforms as dependency on
267    /// skim->tuikit Compile with `--features=fuzzy` to enable
268    #[cfg(all(unix, feature = "with-fuzzy"))]
269    Fuzzy,
270}
271
272/// Style of editing / Standard keymaps
273#[derive(Clone, Copy, Debug, PartialEq, Eq)]
274#[non_exhaustive]
275pub enum EditMode {
276    /// Emacs keymap
277    Emacs,
278    /// Vi keymap
279    Vi,
280}
281
282/// Colorization mode
283#[derive(Clone, Copy, Debug, PartialEq, Eq)]
284#[non_exhaustive]
285pub enum ColorMode {
286    /// Activate highlighting if platform/terminal is supported.
287    Enabled,
288    /// Activate highlighting even if platform is not supported (windows < 10).
289    Forced,
290    /// Deactivate highlighting even if platform/terminal is supported.
291    Disabled,
292}
293
294/// Should the editor use stdio
295#[derive(Clone, Copy, Debug, PartialEq, Eq)]
296#[non_exhaustive]
297pub enum Behavior {
298    /// Use stdin / stdout
299    Stdio,
300    /// Use terminal-style interaction whenever possible, even if 'stdin' and/or
301    /// 'stdout' are not terminals.
302    PreferTerm,
303    // TODO
304    // Use file-style interaction, reading input from the given file.
305    // useFile
306}
307
308impl Default for Behavior {
309    fn default() -> Self {
310        Behavior::Stdio
311    }
312}
313
314/// Configuration builder
315#[derive(Clone, Debug, Default)]
316pub struct Builder {
317    p: Config,
318}
319
320impl Builder {
321    /// Returns a `Config` builder.
322    #[must_use]
323    pub fn new() -> Self {
324        Self {
325            p: Config::default(),
326        }
327    }
328
329    /// Set the maximum length for the history.
330    #[must_use]
331    pub fn max_history_size(mut self, max_size: usize) -> Self {
332        self.set_max_history_size(max_size);
333        self
334    }
335
336    /// Tell if lines which match the previous history entry are saved or not
337    /// in the history list.
338    ///
339    /// By default, they are ignored.
340    #[must_use]
341    pub fn history_ignore_dups(mut self, yes: bool) -> Self {
342        self.set_history_ignore_dups(yes);
343        self
344    }
345
346    /// Tell if lines which begin with a space character are saved or not in
347    /// the history list.
348    ///
349    /// By default, they are saved.
350    #[must_use]
351    pub fn history_ignore_space(mut self, yes: bool) -> Self {
352        self.set_history_ignore_space(yes);
353        self
354    }
355
356    /// Set `completion_type`.
357    #[must_use]
358    pub fn completion_type(mut self, completion_type: CompletionType) -> Self {
359        self.set_completion_type(completion_type);
360        self
361    }
362
363    /// The number of possible completions that determines when the user is
364    /// asked whether the list of possibilities should be displayed.
365    #[must_use]
366    pub fn completion_prompt_limit(mut self, completion_prompt_limit: usize) -> Self {
367        self.set_completion_prompt_limit(completion_prompt_limit);
368        self
369    }
370
371    /// Timeout for ambiguous key sequences in milliseconds.
372    /// Currently, it is used only to distinguish a single ESC from an ESC
373    /// sequence.
374    /// After seeing an ESC key, wait at most `keyseq_timeout_ms` for another
375    /// byte.
376    #[must_use]
377    pub fn keyseq_timeout(mut self, keyseq_timeout_ms: i32) -> Self {
378        self.set_keyseq_timeout(keyseq_timeout_ms);
379        self
380    }
381
382    /// Choose between Emacs or Vi mode.
383    #[must_use]
384    pub fn edit_mode(mut self, edit_mode: EditMode) -> Self {
385        self.set_edit_mode(edit_mode);
386        self
387    }
388
389    /// Tell if lines are automatically added to the history.
390    ///
391    /// By default, they are not.
392    #[must_use]
393    pub fn auto_add_history(mut self, yes: bool) -> Self {
394        self.set_auto_add_history(yes);
395        self
396    }
397
398    /// Set bell style: beep, flash or nothing.
399    #[must_use]
400    pub fn bell_style(mut self, bell_style: BellStyle) -> Self {
401        self.set_bell_style(bell_style);
402        self
403    }
404
405    /// Forces colorization on or off.
406    ///
407    /// By default, colorization is on except if stdout is not a TTY.
408    #[must_use]
409    pub fn color_mode(mut self, color_mode: ColorMode) -> Self {
410        self.set_color_mode(color_mode);
411        self
412    }
413
414    /// Whether to use stdio or not
415    ///
416    /// By default, stdio is used.
417    #[must_use]
418    pub fn behavior(mut self, behavior: Behavior) -> Self {
419        self.set_behavior(behavior);
420        self
421    }
422
423    /// Horizontal space taken by a tab.
424    ///
425    /// By default, `8`
426    #[must_use]
427    pub fn tab_stop(mut self, tab_stop: usize) -> Self {
428        self.set_tab_stop(tab_stop);
429        self
430    }
431
432    /// Check if cursor position is at leftmost before displaying prompt.
433    ///
434    /// By default, we don't check.
435    #[must_use]
436    pub fn check_cursor_position(mut self, yes: bool) -> Self {
437        self.set_check_cursor_position(yes);
438        self
439    }
440
441    /// Indentation size
442    ///
443    /// By default, `2`
444    #[must_use]
445    pub fn indent_size(mut self, indent_size: usize) -> Self {
446        self.set_indent_size(indent_size);
447        self
448    }
449
450    /// Enable or disable bracketed paste on unix platform
451    ///
452    /// By default, it's enabled.
453    #[must_use]
454    pub fn bracketed_paste(mut self, enabled: bool) -> Self {
455        self.enable_bracketed_paste(enabled);
456        self
457    }
458
459    /// Builds a `Config` with the settings specified so far.
460    #[must_use]
461    pub fn build(self) -> Config {
462        self.p
463    }
464}
465
466impl Configurer for Builder {
467    fn config_mut(&mut self) -> &mut Config {
468        &mut self.p
469    }
470}
471
472/// Trait for component that holds a `Config`.
473pub trait Configurer {
474    /// `Config` accessor.
475    fn config_mut(&mut self) -> &mut Config;
476
477    /// Set the maximum length for the history.
478    fn set_max_history_size(&mut self, max_size: usize) {
479        self.config_mut().set_max_history_size(max_size);
480    }
481
482    /// Tell if lines which match the previous history entry are saved or not
483    /// in the history list.
484    ///
485    /// By default, they are ignored.
486    fn set_history_ignore_dups(&mut self, yes: bool) {
487        self.config_mut().set_history_ignore_dups(yes);
488    }
489
490    /// Tell if lines which begin with a space character are saved or not in
491    /// the history list.
492    ///
493    /// By default, they are saved.
494    fn set_history_ignore_space(&mut self, yes: bool) {
495        self.config_mut().set_history_ignore_space(yes);
496    }
497    /// Set `completion_type`.
498    fn set_completion_type(&mut self, completion_type: CompletionType) {
499        self.config_mut().completion_type = completion_type;
500    }
501
502    /// The number of possible completions that determines when the user is
503    /// asked whether the list of possibilities should be displayed.
504    fn set_completion_prompt_limit(&mut self, completion_prompt_limit: usize) {
505        self.config_mut().completion_prompt_limit = completion_prompt_limit;
506    }
507
508    /// Timeout for ambiguous key sequences in milliseconds.
509    fn set_keyseq_timeout(&mut self, keyseq_timeout_ms: i32) {
510        self.config_mut().keyseq_timeout = keyseq_timeout_ms;
511    }
512
513    /// Choose between Emacs or Vi mode.
514    fn set_edit_mode(&mut self, edit_mode: EditMode) {
515        self.config_mut().edit_mode = edit_mode;
516        match edit_mode {
517            EditMode::Emacs => self.set_keyseq_timeout(-1), // no timeout
518            EditMode::Vi => self.set_keyseq_timeout(500),
519        }
520    }
521
522    /// Tell if lines are automatically added to the history.
523    ///
524    /// By default, they are not.
525    fn set_auto_add_history(&mut self, yes: bool) {
526        self.config_mut().auto_add_history = yes;
527    }
528
529    /// Set bell style: beep, flash or nothing.
530    fn set_bell_style(&mut self, bell_style: BellStyle) {
531        self.config_mut().bell_style = bell_style;
532    }
533
534    /// Forces colorization on or off.
535    ///
536    /// By default, colorization is on except if stdout is not a TTY.
537    fn set_color_mode(&mut self, color_mode: ColorMode) {
538        self.config_mut().set_color_mode(color_mode);
539    }
540
541    /// Whether to use stdio or not
542    ///
543    /// By default, stdio is used.
544    fn set_behavior(&mut self, behavior: Behavior) {
545        self.config_mut().set_behavior(behavior);
546    }
547
548    /// Horizontal space taken by a tab.
549    ///
550    /// By default, `8`
551    fn set_tab_stop(&mut self, tab_stop: usize) {
552        self.config_mut().set_tab_stop(tab_stop);
553    }
554
555    /// Check if cursor position is at leftmost before displaying prompt.
556    ///
557    /// By default, we don't check.
558    fn set_check_cursor_position(&mut self, yes: bool) {
559        self.config_mut().check_cursor_position = yes;
560    }
561    /// Indentation size for indent/dedent commands
562    ///
563    /// By default, `2`
564    fn set_indent_size(&mut self, size: usize) {
565        self.config_mut().set_indent_size(size);
566    }
567
568    /// Enable or disable bracketed paste on unix platform
569    ///
570    /// By default, it's enabled.
571    fn enable_bracketed_paste(&mut self, enabled: bool) {
572        self.config_mut().enable_bracketed_paste = enabled;
573    }
574}