Skip to main content

lineread/
reader.rs

1//! Provides access to terminal read operations
2
3use std::borrow::Cow;
4use std::collections::{HashMap, VecDeque};
5use std::io;
6use std::mem::replace;
7use std::ops::{Deref, DerefMut};
8use std::path::{Path, PathBuf};
9use std::slice;
10use std::sync::{Arc, MutexGuard};
11use std::time::{Duration, Instant};
12
13use mortal::SequenceMap;
14
15use crate::command::{Category, Command};
16use crate::complete::{Completer, Completion, DummyCompleter};
17use crate::function::Function;
18use crate::inputrc::{parse_file, Directive};
19use crate::interface::Interface;
20use crate::prompter::Prompter;
21use crate::sys::path::{env_init_file, system_init_file, user_init_file};
22use crate::terminal::{RawRead, Signal, SignalSet, Size, Terminal, TerminalReader};
23use crate::util::{first_char, match_name};
24use crate::variables::{Variable, VariableIter, Variables};
25
26/// Default set of string characters
27pub const STRING_CHARS: &str = "\"'";
28
29/// Default set of word break characters
30pub const WORD_BREAK_CHARS: &str = " \t\n\"\\'`@$><=;|&{(";
31
32/// Indicates the start of a series of invisible characters in the prompt
33pub const START_INVISIBLE: char = '\x01';
34
35/// Indicates the end of a series of invisible characters in the prompt
36pub const END_INVISIBLE: char = '\x02';
37
38/// Maximum size of kill ring
39const MAX_KILLS: usize = 10;
40
41/// Provides access to data related to reading and processing user input.
42///
43/// Holds a lock on terminal read operations.
44/// See [`Interface`] for more information about concurrent operations.
45///
46/// An instance of this type can be constructed using the
47/// [`Interface::lock_reader`] method.
48///
49/// [`Interface`]: ../interface/struct.Interface.html
50/// [`Interface::lock_reader`]: ../interface/struct.Interface.html#method.lock_reader
51pub struct Reader<'a, Term: 'a + Terminal> {
52    iface: &'a Interface<Term>,
53    lock: ReadLock<'a, Term>,
54}
55
56pub(crate) struct Read<Term: Terminal> {
57    /// Application name
58    pub application: Cow<'static, str>,
59
60    /// Pending input
61    pub input_buffer: Vec<u8>,
62    /// Pending macro sequence
63    pub macro_buffer: String,
64
65    pub bindings: SequenceMap<Cow<'static, str>, Command>,
66    pub functions: HashMap<Cow<'static, str>, Arc<dyn Function<Term>>>,
67
68    /// Current input sequence
69    pub sequence: String,
70    /// Whether newline has been received
71    pub input_accepted: bool,
72
73    /// Whether overwrite mode is currently active
74    pub overwrite_mode: bool,
75    /// Characters appended while in overwrite mode
76    pub overwritten_append: usize,
77    /// Characters overwritten in overwrite mode
78    pub overwritten_chars: String,
79
80    /// Configured completer
81    pub completer: Arc<dyn Completer<Term>>,
82    /// Character appended to completions
83    pub completion_append_character: Option<char>,
84    /// Current set of possible completions
85    pub completions: Option<Vec<Completion>>,
86    /// Current "menu-complete" entry being viewed:
87    pub completion_index: usize,
88    /// Start of the completed word
89    pub completion_start: usize,
90    /// Start of the inserted prefix of a completed word
91    pub completion_prefix: usize,
92    /// Byte length of the common prefix of completion display strings (for highlighting)
93    pub completion_display_prefix: usize,
94    /// Whether to highlight the distinguishing suffix of completion candidates
95    pub highlight_completions: bool,
96
97    pub string_chars: Cow<'static, str>,
98    pub word_break: Cow<'static, str>,
99
100    pub last_cmd: Category,
101    pub last_yank: Option<(usize, usize)>,
102    pub kill_ring: VecDeque<String>,
103
104    pub catch_signals: bool,
105    pub ignore_signals: SignalSet,
106    pub report_signals: SignalSet,
107    pub last_resize: Option<Size>,
108    pub last_signal: Option<Signal>,
109
110    variables: Variables,
111
112    pub state: InputState,
113    pub max_wait_duration: Option<Duration>,
114}
115
116pub(crate) struct ReadLock<'a, Term: 'a + Terminal> {
117    term: Box<dyn TerminalReader<Term> + 'a>,
118    data: MutexGuard<'a, Read<Term>>,
119}
120
121/// Returned from [`read_line`] to indicate user input
122///
123/// [`read_line`]: ../interface/struct.Interface.html#method.read_line
124#[derive(Debug)]
125pub enum ReadResult {
126    /// User issued end-of-file
127    Eof,
128    /// User input received
129    Input(String),
130    /// Reported signal was received
131    Signal(Signal),
132}
133
134#[derive(Copy, Clone, Debug)]
135pub(crate) enum InputState {
136    Inactive,
137    NewSequence,
138    ContinueSequence { expiry: Option<Instant> },
139    Number,
140    CharSearch { n: usize, backward: bool },
141    TextSearch,
142    CompleteIntro,
143    CompleteMore(usize),
144    QuotedInsert(usize),
145}
146
147impl<'a, Term: 'a + Terminal> Reader<'a, Term> {
148    pub(crate) fn new(iface: &'a Interface<Term>, lock: ReadLock<'a, Term>) -> Reader<'a, Term> {
149        Reader { iface, lock }
150    }
151
152    /// Interactively reads a line from the terminal device.
153    ///
154    /// User input is collected until one of the following conditions is met:
155    ///
156    /// * If the user issues an end-of-file, `ReadResult::Eof` is returned.
157    /// * When the user inputs a newline (`'\n'`), the resulting input
158    ///   (not containing a trailing newline character) is returned as
159    ///   `ReadResult::Input(_)`.
160    /// * When a reported signal (see [`set_report_signal`]) is received,
161    ///   it is returned as `ReadResult::Signal(_)`. The `read_line` operation may
162    ///   then be either resumed with another call to `read_line` or ended by
163    ///   calling [`cancel_read_line`].
164    ///
165    /// [`cancel_read_line`]: #method.cancel_read_line
166    /// [`set_report_signal`]: #method.set_report_signal
167    pub fn read_line(&mut self) -> io::Result<ReadResult> {
168        loop {
169            if let Some(res) = self.read_line_step(None)? {
170                return Ok(res);
171            }
172        }
173    }
174
175    /// Performs one step of the interactive `read_line` loop.
176    ///
177    /// This method can be used to drive the `read_line` process asynchronously.
178    /// It will wait for input only up to the specified duration, then process
179    /// any available input from the terminal.
180    ///
181    /// If the user completes the input process, `Ok(Some(result))` is returned.
182    /// Otherwise, `Ok(None)` is returned to indicate that the interactive loop
183    /// may continue.
184    ///
185    /// The interactive prompt may be cancelled prematurely using the
186    /// [`cancel_read_line`] method.
187    ///
188    /// See [`read_line`] for details on the return value.
189    ///
190    /// [`cancel_read_line`]: #method.cancel_read_line
191    /// [`read_line`]: #method.read_line
192    pub fn read_line_step(&mut self, timeout: Option<Duration>) -> io::Result<Option<ReadResult>> {
193        self.initialize_read_line()?;
194
195        let state = self.prepare_term()?;
196        let res = self.read_line_step_impl(timeout);
197        self.lock.term.restore(state)?;
198
199        res
200    }
201
202    /// Cancels an in-progress `read_line` operation.
203    ///
204    /// This method will reset internal data structures to their original state
205    /// and move the terminal cursor to a new, empty line.
206    ///
207    /// This method is called to prematurely end the interactive loop when
208    /// using the [`read_line_step`] method.
209    ///
210    /// It is not necessary to call this method if using the [`read_line`] method.
211    ///
212    /// [`read_line`]: #method.read_line
213    /// [`read_line_step`]: #method.read_line_step
214    pub fn cancel_read_line(&mut self) -> io::Result<()> {
215        self.end_read_line()
216    }
217
218    fn initialize_read_line(&mut self) -> io::Result<()> {
219        if !self.lock.is_active() {
220            self.prompter().start_read_line()?;
221        }
222        Ok(())
223    }
224
225    fn read_line_step_impl(&mut self, timeout: Option<Duration>) -> io::Result<Option<ReadResult>> {
226        let do_read = if self.lock.is_input_available() {
227            // This branch will be taken only if a macro has buffered some input.
228            // We check for input with a zero duration to see if the user has
229            // entered Ctrl-C, e.g. to interrupt an infinitely recursive macro.
230            self.lock
231                .term
232                .wait_for_input(Some(Duration::from_secs(0)))?
233        } else {
234            let timeout = limit_duration(timeout, self.lock.max_wait_duration);
235            self.lock.term.wait_for_input(timeout)?
236        };
237
238        if do_read {
239            self.lock.read_input()?;
240        }
241
242        if let Some(size) = self.lock.take_resize() {
243            self.handle_resize(size)?;
244        }
245
246        if let Some(sig) = self.lock.take_signal() {
247            if self.lock.report_signals.contains(sig) {
248                return Ok(Some(ReadResult::Signal(sig)));
249            }
250            if !self.lock.ignore_signals.contains(sig) {
251                self.handle_signal(sig)?;
252            }
253        }
254
255        // Acquire the write lock and process all available input
256        {
257            let mut prompter = self.prompter();
258
259            prompter.check_expire_timeout()?;
260
261            // If the macro buffer grows in size while input is being processed,
262            // we end this step and let the caller try again. This is to allow
263            // reading Ctrl-C to interrupt (perhaps infinite) macro execution.
264            let mut macro_len = prompter.read.data.macro_buffer.len();
265
266            while prompter.read.is_input_available() {
267                if let Some(ch) = prompter.read.read_char()? {
268                    if let Some(r) = prompter.handle_input(ch)? {
269                        prompter.end_read_line()?;
270                        return Ok(Some(r));
271                    }
272                }
273
274                let new_macro_len = prompter.read.data.macro_buffer.len();
275
276                if new_macro_len != 0 && new_macro_len >= macro_len {
277                    break;
278                }
279
280                macro_len = new_macro_len;
281            }
282        }
283
284        Ok(None)
285    }
286
287    fn end_read_line(&mut self) -> io::Result<()> {
288        if self.lock.is_active() {
289            self.prompter().end_read_line()?;
290        }
291        Ok(())
292    }
293
294    fn prepare_term(&mut self) -> io::Result<Term::PrepareState> {
295        if self.read_next_raw() {
296            self.lock.term.prepare(true, SignalSet::new())
297        } else {
298            let mut signals = self.lock.report_signals.union(self.lock.ignore_signals);
299
300            if self.lock.catch_signals {
301                // Ctrl-C is always intercepted (unless we're catching no signals).
302                // By default, lineread handles it by clearing the current input state.
303                signals.insert(Signal::Interrupt);
304            }
305
306            let block_signals = !self.lock.catch_signals;
307
308            self.lock.term.prepare(block_signals, signals)
309        }
310    }
311
312    fn read_next_raw(&self) -> bool {
313        match self.lock.state {
314            InputState::QuotedInsert(_) => true,
315            _ => false,
316        }
317    }
318
319    /// Sets the input buffer to the given string.
320    ///
321    /// This method internally acquires the `Interface` write lock.
322    ///
323    /// # Notes
324    ///
325    /// To prevent invalidating the cursor, this method sets the cursor
326    /// position to the end of the new buffer.
327    pub fn set_buffer(&mut self, buf: &str) -> io::Result<()> {
328        if self.lock.is_active() {
329            self.prompter().set_buffer(buf)
330        } else {
331            self.iface.lock_write_data().set_buffer(buf);
332            Ok(())
333        }
334    }
335
336    /// Sets the cursor position in the input buffer.
337    ///
338    /// This method internally acquires the `Interface` write lock.
339    ///
340    /// # Panics
341    ///
342    /// If the given position is out of bounds or not on a `char` boundary.
343    pub fn set_cursor(&mut self, pos: usize) -> io::Result<()> {
344        if self.lock.is_active() {
345            self.prompter().set_cursor(pos)
346        } else {
347            self.iface.lock_write_data().set_cursor(pos);
348            Ok(())
349        }
350    }
351
352    /// Sets the prompt that will be displayed when `read_line` is called.
353    ///
354    /// This method internally acquires the `Interface` write lock.
355    ///
356    /// # Notes
357    ///
358    /// If `prompt` contains any terminal escape sequences (e.g. color codes),
359    /// such escape sequences should be immediately preceded by the character
360    /// `'\x01'` and immediately followed by the character `'\x02'`.
361    pub fn set_prompt(&mut self, prompt: &str) -> io::Result<()> {
362        self.prompter().set_prompt(prompt)
363    }
364
365    /// Adds a line to history.
366    ///
367    /// This method internally acquires the `Interface` write lock.
368    ///
369    /// If a `read_line` call is in progress, this method has no effect.
370    pub fn add_history(&self, line: String) {
371        if !self.lock.is_active() {
372            self.iface.lock_write().add_history(line);
373        }
374    }
375
376    /// Adds a line to history, unless it is identical to the most recent entry.
377    ///
378    /// This method internally acquires the `Interface` write lock.
379    ///
380    /// If a `read_line` call is in progress, this method has no effect.
381    pub fn add_history_unique(&self, line: String) {
382        if !self.lock.is_active() {
383            self.iface.lock_write().add_history_unique(line);
384        }
385    }
386
387    /// Removes all history entries.
388    ///
389    /// This method internally acquires the `Interface` write lock.
390    ///
391    /// If a `read_line` call is in progress, this method has no effect.
392    pub fn clear_history(&self) {
393        if !self.lock.is_active() {
394            self.iface.lock_write().clear_history();
395        }
396    }
397
398    /// Removes the history entry at the given index.
399    ///
400    /// This method internally acquires the `Interface` write lock.
401    ///
402    /// If the index is out of bounds, this method has no effect.
403    ///
404    /// If a `read_line` call is in progress, this method has no effect.
405    pub fn remove_history(&self, idx: usize) {
406        if !self.lock.is_active() {
407            self.iface.lock_write().remove_history(idx);
408        }
409    }
410
411    /// Sets the maximum number of history entries.
412    ///
413    /// This method internally acquires the `Interface` write lock.
414    ///
415    /// If `n` is less than the current number of history entries,
416    /// the oldest entries are truncated to meet the given requirement.
417    ///
418    /// If a `read_line` call is in progress, this method has no effect.
419    pub fn set_history_size(&self, n: usize) {
420        if !self.lock.is_active() {
421            self.iface.lock_write().set_history_size(n);
422        }
423    }
424
425    /// Truncates history to the only the most recent `n` entries.
426    ///
427    /// This method internally acquires the `Interface` write lock.
428    ///
429    /// If a `read_line` call is in progress, this method has no effect.
430    pub fn truncate_history(&self, n: usize) {
431        if !self.lock.is_active() {
432            self.iface.lock_write().truncate_history(n);
433        }
434    }
435
436    /// Returns the application name
437    pub fn application(&self) -> &str {
438        &self.lock.application
439    }
440
441    /// Sets the application name
442    pub fn set_application<T>(&mut self, application: T)
443    where
444        T: Into<Cow<'static, str>>,
445    {
446        self.lock.application = application.into();
447    }
448
449    /// Returns a reference to the current completer instance.
450    pub fn completer(&self) -> &Arc<dyn Completer<Term>> {
451        &self.lock.completer
452    }
453
454    /// Replaces the current completer, returning the previous instance.
455    pub fn set_completer(
456        &mut self,
457        completer: Arc<dyn Completer<Term>>,
458    ) -> Arc<dyn Completer<Term>> {
459        replace(&mut self.lock.completer, completer)
460    }
461
462    /// Enables or disables highlighting of completion candidate suffixes.
463    pub fn set_highlight_completions(&mut self, enable: bool) {
464        self.lock.highlight_completions = enable;
465    }
466
467    /// Returns the value of the named variable or `None`
468    /// if no such variable exists.
469    pub fn get_variable(&self, name: &str) -> Option<Variable> {
470        self.lock.get_variable(name)
471    }
472
473    /// Sets the value of the named variable and returns the previous
474    /// value.
475    ///
476    /// If `name` does not refer to a variable or the `value` is not
477    /// a valid value for the variable, `None` is returned.
478    pub fn set_variable(&mut self, name: &str, value: &str) -> Option<Variable> {
479        self.lock.set_variable(name, value)
480    }
481
482    /// Returns an iterator over stored variables.
483    pub fn variables(&self) -> VariableIter<'_> {
484        self.lock.variables.iter()
485    }
486
487    /// Returns whether to "blink" matching opening parenthesis character
488    /// when a closing parenthesis character is entered.
489    ///
490    /// The default value is `false`.
491    pub fn blink_matching_paren(&self) -> bool {
492        self.lock.blink_matching_paren
493    }
494
495    /// Sets the `blink-matching-paren` variable.
496    pub fn set_blink_matching_paren(&mut self, set: bool) {
497        self.lock.blink_matching_paren = set;
498    }
499
500    /// Returns whether `lineread` will catch certain signals.
501    pub fn catch_signals(&self) -> bool {
502        self.lock.catch_signals
503    }
504
505    /// Sets whether `lineread` will catch certain signals.
506    ///
507    /// This setting is `true` by default. It can be disabled to allow the
508    /// host program to handle signals itself.
509    pub fn set_catch_signals(&mut self, enabled: bool) {
510        self.lock.catch_signals = enabled;
511    }
512
513    /// Returns whether the given `Signal` is ignored.
514    pub fn ignore_signal(&self, signal: Signal) -> bool {
515        self.lock.ignore_signals.contains(signal)
516    }
517
518    /// Sets whether the given `Signal` will be ignored.
519    pub fn set_ignore_signal(&mut self, signal: Signal, set: bool) {
520        if set {
521            self.lock.ignore_signals.insert(signal);
522            self.lock.report_signals.remove(signal);
523        } else {
524            self.lock.ignore_signals.remove(signal);
525        }
526    }
527
528    /// Returns whether the given `Signal` is to be reported.
529    pub fn report_signal(&self, signal: Signal) -> bool {
530        self.lock.report_signals.contains(signal)
531    }
532
533    /// Sets whether to report the given `Signal`.
534    ///
535    /// When a reported signal is received via the terminal, it will be returned
536    /// from `Interface::read_line` as `Ok(Signal(signal))`.
537    pub fn set_report_signal(&mut self, signal: Signal, set: bool) {
538        if set {
539            self.lock.report_signals.insert(signal);
540            self.lock.ignore_signals.remove(signal);
541        } else {
542            self.lock.report_signals.remove(signal);
543        }
544    }
545
546    /// Returns whether Tab completion is disabled.
547    ///
548    /// The default value is `false`.
549    pub fn disable_completion(&self) -> bool {
550        self.lock.disable_completion
551    }
552
553    /// Sets the `disable-completion` variable.
554    pub fn set_disable_completion(&mut self, disable: bool) {
555        self.lock.disable_completion = disable;
556    }
557
558    /// When certain control characters are pressed, a character sequence
559    /// equivalent to this character will be echoed.
560    ///
561    /// The default value is `true`.
562    pub fn echo_control_characters(&self) -> bool {
563        self.lock.echo_control_characters
564    }
565
566    /// Sets the `echo-control-characters` variable.
567    pub fn set_echo_control_characters(&mut self, echo: bool) {
568        self.lock.echo_control_characters = echo;
569    }
570
571    /// Returns the character, if any, that is appended to a successful completion.
572    pub fn completion_append_character(&self) -> Option<char> {
573        self.lock.completion_append_character
574    }
575
576    /// Sets the character, if any, that is appended to a successful completion.
577    pub fn set_completion_append_character(&mut self, ch: Option<char>) {
578        self.lock.completion_append_character = ch;
579    }
580
581    /// Returns the width of completion listing display.
582    ///
583    /// If this value is greater than the terminal width, terminal width is used
584    /// instead.
585    ///
586    /// The default value is equal to `usize::max_value()`.
587    pub fn completion_display_width(&self) -> usize {
588        self.lock.completion_display_width
589    }
590
591    /// Sets the `completion-display-width` variable.
592    pub fn set_completion_display_width(&mut self, n: usize) {
593        self.lock.completion_display_width = n;
594    }
595
596    /// Returns the minimum number of completion items that require user
597    /// confirmation before listing.
598    ///
599    /// The default value is `100`.
600    pub fn completion_query_items(&self) -> usize {
601        self.lock.completion_query_items
602    }
603
604    /// Sets the `completion-query-items` variable.
605    pub fn set_completion_query_items(&mut self, n: usize) {
606        self.lock.completion_query_items = n;
607    }
608
609    /// Returns the timeout to wait for further user input when an ambiguous
610    /// sequence has been entered. If the value is `None`, wait is indefinite.
611    ///
612    /// The default value 500 milliseconds.
613    pub fn keyseq_timeout(&self) -> Option<Duration> {
614        self.lock.keyseq_timeout
615    }
616
617    /// Sets the `keyseq-timeout` variable.
618    pub fn set_keyseq_timeout(&mut self, timeout: Option<Duration>) {
619        self.lock.keyseq_timeout = timeout;
620    }
621
622    /// Returns whether to list possible completions one page at a time.
623    ///
624    /// The default value is `true`.
625    pub fn page_completions(&self) -> bool {
626        self.lock.page_completions
627    }
628
629    /// Sets the `page-completions` variable.
630    pub fn set_page_completions(&mut self, set: bool) {
631        self.lock.page_completions = set;
632    }
633
634    /// Returns whether to list completions horizontally, rather than down
635    /// the screen.
636    ///
637    /// The default value is `false`.
638    pub fn print_completions_horizontally(&self) -> bool {
639        self.lock.print_completions_horizontally
640    }
641
642    /// Sets the `print-completions-horizontally` variable.
643    pub fn set_print_completions_horizontally(&mut self, set: bool) {
644        self.lock.print_completions_horizontally = set;
645    }
646
647    /// Returns the set of characters that delimit strings.
648    pub fn string_chars(&self) -> &str {
649        &self.lock.string_chars
650    }
651
652    /// Sets the set of characters that delimit strings.
653    pub fn set_string_chars<T>(&mut self, chars: T)
654    where
655        T: Into<Cow<'static, str>>,
656    {
657        self.lock.string_chars = chars.into();
658    }
659
660    /// Returns the set of characters that indicate a word break.
661    pub fn word_break_chars(&self) -> &str {
662        &self.lock.word_break
663    }
664
665    /// Sets the set of characters that indicate a word break.
666    pub fn set_word_break_chars<T>(&mut self, chars: T)
667    where
668        T: Into<Cow<'static, str>>,
669    {
670        self.lock.word_break = chars.into();
671    }
672
673    /// Returns an iterator over bound sequences
674    pub fn bindings(&self) -> BindingIter<'_> {
675        self.lock.bindings()
676    }
677
678    /// Binds a sequence to a command.
679    ///
680    /// Returns the previously bound command.
681    pub fn bind_sequence<T>(&mut self, seq: T, cmd: Command) -> Option<Command>
682    where
683        T: Into<Cow<'static, str>>,
684    {
685        self.lock.bind_sequence(seq, cmd)
686    }
687
688    /// Binds a sequence to a command, if and only if the given sequence
689    /// is not already bound to a command.
690    ///
691    /// Returns `true` if a new binding was created.
692    pub fn bind_sequence_if_unbound<T>(&mut self, seq: T, cmd: Command) -> bool
693    where
694        T: Into<Cow<'static, str>>,
695    {
696        self.lock.bind_sequence_if_unbound(seq, cmd)
697    }
698
699    /// Removes a binding for the given sequence.
700    ///
701    /// Returns the previously bound command.
702    pub fn unbind_sequence(&mut self, seq: &str) -> Option<Command> {
703        self.lock.unbind_sequence(seq)
704    }
705
706    /// Defines a named function to which sequences may be bound.
707    ///
708    /// The name should consist of lowercase ASCII letters and numbers,
709    /// containing no spaces, with words separated by hyphens. However,
710    /// this is not a requirement.
711    ///
712    /// Returns the function previously defined with the same name.
713    pub fn define_function<T>(
714        &mut self,
715        name: T,
716        cmd: Arc<dyn Function<Term>>,
717    ) -> Option<Arc<dyn Function<Term>>>
718    where
719        T: Into<Cow<'static, str>>,
720    {
721        self.lock.define_function(name, cmd)
722    }
723
724    /// Removes a function defined with the given name.
725    ///
726    /// Returns the defined function.
727    pub fn remove_function(&mut self, name: &str) -> Option<Arc<dyn Function<Term>>> {
728        self.lock.remove_function(name)
729    }
730
731    pub(crate) fn evaluate_directives(&mut self, term: &Term, dirs: Vec<Directive>) {
732        self.lock.data.evaluate_directives(term, dirs)
733    }
734
735    pub(crate) fn evaluate_directive(&mut self, term: &Term, dir: Directive) {
736        self.lock.data.evaluate_directive(term, dir)
737    }
738
739    fn prompter<'b>(&'b mut self) -> Prompter<'b, 'a, Term> {
740        Prompter::new(&mut self.lock, self.iface.lock_write())
741    }
742
743    fn handle_resize(&mut self, size: Size) -> io::Result<()> {
744        self.prompter().handle_resize(size)
745    }
746
747    fn handle_signal(&mut self, sig: Signal) -> io::Result<()> {
748        self.prompter().handle_signal(sig)
749    }
750}
751
752impl<'a, Term: 'a + Terminal> ReadLock<'a, Term> {
753    pub fn new(
754        term: Box<dyn TerminalReader<Term> + 'a>,
755        data: MutexGuard<'a, Read<Term>>,
756    ) -> ReadLock<'a, Term> {
757        ReadLock { term, data }
758    }
759
760    /// Reads the next character of input.
761    ///
762    /// Performs a non-blocking read from the terminal, if necessary.
763    ///
764    /// If non-input data was received (e.g. a signal) or insufficient input
765    /// is available, `Ok(None)` is returned.
766    pub fn read_char(&mut self) -> io::Result<Option<char>> {
767        if let Some(ch) = self.macro_pop() {
768            Ok(Some(ch))
769        } else if let Some(ch) = self.decode_input()? {
770            Ok(Some(ch))
771        } else {
772            Ok(None)
773        }
774    }
775
776    fn read_input(&mut self) -> io::Result<()> {
777        match self.term.read(&mut self.data.input_buffer)? {
778            RawRead::Bytes(_) => (),
779            RawRead::Resize(new_size) => {
780                self.last_resize = Some(new_size);
781            }
782            RawRead::Signal(sig) => {
783                self.last_signal = Some(sig);
784            }
785        }
786
787        Ok(())
788    }
789
790    fn is_input_available(&self) -> bool {
791        !self.data.macro_buffer.is_empty()
792            || match self.peek_input() {
793                Ok(Some(_)) | Err(_) => true,
794                Ok(None) => false,
795            }
796    }
797
798    fn macro_pop(&mut self) -> Option<char> {
799        if self.data.macro_buffer.is_empty() {
800            None
801        } else {
802            Some(self.data.macro_buffer.remove(0))
803        }
804    }
805
806    fn decode_input(&mut self) -> io::Result<Option<char>> {
807        let res = self.peek_input();
808
809        if let Ok(Some(ch)) = res {
810            self.data.input_buffer.drain(..ch.len_utf8());
811        }
812
813        res
814    }
815
816    fn peek_input(&self) -> io::Result<Option<char>> {
817        if self.data.input_buffer.is_empty() {
818            Ok(None)
819        } else {
820            first_char(&self.data.input_buffer)
821        }
822    }
823
824    pub fn reset_data(&mut self) {
825        self.data.reset_data();
826    }
827}
828
829impl<'a, Term: 'a + Terminal> Deref for ReadLock<'a, Term> {
830    type Target = Read<Term>;
831
832    fn deref(&self) -> &Read<Term> {
833        &self.data
834    }
835}
836
837impl<'a, Term: 'a + Terminal> DerefMut for ReadLock<'a, Term> {
838    fn deref_mut(&mut self) -> &mut Read<Term> {
839        &mut self.data
840    }
841}
842
843impl<Term: Terminal> Deref for Read<Term> {
844    type Target = Variables;
845
846    fn deref(&self) -> &Variables {
847        &self.variables
848    }
849}
850
851impl<Term: Terminal> DerefMut for Read<Term> {
852    fn deref_mut(&mut self) -> &mut Variables {
853        &mut self.variables
854    }
855}
856
857impl<Term: Terminal> Read<Term> {
858    pub fn new(term: &Term, application: Cow<'static, str>) -> Read<Term> {
859        let mut r = Read {
860            application,
861
862            bindings: default_bindings(),
863            functions: HashMap::new(),
864
865            input_buffer: Vec::new(),
866            macro_buffer: String::new(),
867
868            sequence: String::new(),
869            input_accepted: false,
870
871            overwrite_mode: false,
872            overwritten_append: 0,
873            overwritten_chars: String::new(),
874
875            completer: Arc::new(DummyCompleter),
876            completion_append_character: Some(' '),
877            completions: None,
878            completion_index: 0,
879            completion_start: 0,
880            completion_prefix: 0,
881            completion_display_prefix: 0,
882            highlight_completions: false,
883
884            string_chars: STRING_CHARS.into(),
885            word_break: WORD_BREAK_CHARS.into(),
886
887            last_cmd: Category::Other,
888            last_yank: None,
889            kill_ring: VecDeque::with_capacity(MAX_KILLS),
890
891            catch_signals: true,
892            ignore_signals: SignalSet::new(),
893            report_signals: SignalSet::new(),
894            last_resize: None,
895            last_signal: None,
896
897            variables: Variables::default(),
898
899            state: InputState::Inactive,
900            max_wait_duration: None,
901        };
902
903        r.read_init(term);
904        r
905    }
906
907    pub fn bindings(&self) -> BindingIter<'_> {
908        BindingIter(self.bindings.sequences().iter())
909    }
910
911    pub fn variables(&self) -> VariableIter<'_> {
912        self.variables.iter()
913    }
914
915    fn take_resize(&mut self) -> Option<Size> {
916        self.last_resize.take()
917    }
918
919    fn take_signal(&mut self) -> Option<Signal> {
920        self.last_signal.take()
921    }
922
923    pub fn queue_input(&mut self, seq: &str) {
924        self.macro_buffer.insert_str(0, seq);
925    }
926
927    pub fn is_active(&self) -> bool {
928        match self.state {
929            InputState::Inactive => false,
930            _ => true,
931        }
932    }
933
934    pub fn reset_data(&mut self) {
935        self.state = InputState::NewSequence;
936        self.input_accepted = false;
937        self.overwrite_mode = false;
938        self.overwritten_append = 0;
939        self.overwritten_chars.clear();
940        self.sequence.clear();
941
942        self.completions = None;
943
944        self.last_cmd = Category::Other;
945        self.last_yank = None;
946
947        self.last_resize = None;
948        self.last_signal = None;
949    }
950
951    pub fn bind_sequence<T>(&mut self, seq: T, cmd: Command) -> Option<Command>
952    where
953        T: Into<Cow<'static, str>>,
954    {
955        self.bindings.insert(seq.into(), cmd)
956    }
957
958    pub fn bind_sequence_if_unbound<T>(&mut self, seq: T, cmd: Command) -> bool
959    where
960        T: Into<Cow<'static, str>>,
961    {
962        use mortal::sequence::Entry;
963
964        match self.bindings.entry(seq.into()) {
965            Entry::Occupied(_) => false,
966            Entry::Vacant(ent) => {
967                ent.insert(cmd);
968                true
969            }
970        }
971    }
972
973    pub fn unbind_sequence(&mut self, seq: &str) -> Option<Command> {
974        self.bindings.remove(seq).map(|(_, cmd)| cmd)
975    }
976
977    pub fn define_function<T>(
978        &mut self,
979        name: T,
980        cmd: Arc<dyn Function<Term>>,
981    ) -> Option<Arc<dyn Function<Term>>>
982    where
983        T: Into<Cow<'static, str>>,
984    {
985        self.functions.insert(name.into(), cmd)
986    }
987
988    pub fn remove_function(&mut self, name: &str) -> Option<Arc<dyn Function<Term>>> {
989        self.functions.remove(name)
990    }
991
992    fn read_init(&mut self, term: &Term) {
993        if let Some(path) = env_init_file() {
994            // If `INPUTRC` is present, even if invalid, parse nothing else.
995            // Thus, an empty `INPUTRC` will inhibit loading configuration.
996            self.read_init_file_if_exists(term, Some(path));
997        } else {
998            if !self.read_init_file_if_exists(term, user_init_file()) {
999                self.read_init_file_if_exists(term, system_init_file());
1000            }
1001        }
1002    }
1003
1004    fn read_init_file_if_exists(&mut self, term: &Term, path: Option<PathBuf>) -> bool {
1005        match path {
1006            Some(ref path) if path.exists() => {
1007                self.read_init_file(term, path);
1008                true
1009            }
1010            _ => false,
1011        }
1012    }
1013
1014    fn read_init_file(&mut self, term: &Term, path: &Path) {
1015        if let Some(dirs) = parse_file(path) {
1016            self.evaluate_directives(term, dirs);
1017        }
1018    }
1019
1020    /// Evaluates a series of configuration directives.
1021    pub(crate) fn evaluate_directives(&mut self, term: &Term, dirs: Vec<Directive>) {
1022        for dir in dirs {
1023            self.evaluate_directive(term, dir);
1024        }
1025    }
1026
1027    /// Evaluates a single configuration directive.
1028    pub(crate) fn evaluate_directive(&mut self, term: &Term, dir: Directive) {
1029        match dir {
1030            Directive::Bind(seq, cmd) => {
1031                self.bind_sequence(seq, cmd);
1032            }
1033            Directive::Conditional {
1034                name,
1035                value,
1036                then_group,
1037                else_group,
1038            } => {
1039                let name = name.as_ref().map(|s| &s[..]);
1040
1041                if self.eval_condition(term, name, &value) {
1042                    self.evaluate_directives(term, then_group);
1043                } else {
1044                    self.evaluate_directives(term, else_group);
1045                }
1046            }
1047            Directive::SetVariable(name, value) => {
1048                self.set_variable(&name, &value);
1049            }
1050        }
1051    }
1052
1053    fn eval_condition(&self, term: &Term, name: Option<&str>, value: &str) -> bool {
1054        match name {
1055            None => self.application == value,
1056            Some("lib") => value == "lineread",
1057            Some("mode") => value == "emacs",
1058            Some("term") => self.term_matches(term, value),
1059            _ => false,
1060        }
1061    }
1062
1063    fn term_matches(&self, term: &Term, value: &str) -> bool {
1064        match_name(term.name(), value)
1065    }
1066}
1067
1068/// Iterator over `Reader` bindings
1069pub struct BindingIter<'a>(slice::Iter<'a, (Cow<'static, str>, Command)>);
1070
1071impl<'a> ExactSizeIterator for BindingIter<'a> {}
1072
1073impl<'a> Iterator for BindingIter<'a> {
1074    type Item = (&'a str, &'a Command);
1075
1076    #[inline]
1077    fn next(&mut self) -> Option<Self::Item> {
1078        self.0.next().map(|&(ref s, ref cmd)| (&s[..], cmd))
1079    }
1080
1081    #[inline]
1082    fn nth(&mut self, n: usize) -> Option<Self::Item> {
1083        self.0.nth(n).map(|&(ref s, ref cmd)| (&s[..], cmd))
1084    }
1085
1086    #[inline]
1087    fn size_hint(&self) -> (usize, Option<usize>) {
1088        self.0.size_hint()
1089    }
1090}
1091
1092impl<'a> DoubleEndedIterator for BindingIter<'a> {
1093    #[inline]
1094    fn next_back(&mut self) -> Option<Self::Item> {
1095        self.0.next_back().map(|&(ref s, ref cmd)| (&s[..], cmd))
1096    }
1097}
1098
1099fn default_bindings() -> SequenceMap<Cow<'static, str>, Command> {
1100    use crate::command::Command::*;
1101
1102    SequenceMap::from(vec![
1103        // Carriage return and line feed
1104        ("\r".into(), AcceptLine),
1105        ("\n".into(), AcceptLine),
1106        // Possible sequences for arrow keys, Home, End
1107        ("\x1b[A".into(), PreviousHistory),
1108        ("\x1b[B".into(), NextHistory),
1109        ("\x1b[C".into(), ForwardChar),
1110        ("\x1b[D".into(), BackwardChar),
1111        ("\x1b[H".into(), BeginningOfLine),
1112        ("\x1b[F".into(), EndOfLine),
1113        // More possible sequences for arrow keys, Home, End
1114        ("\x1bOA".into(), PreviousHistory),
1115        ("\x1bOB".into(), NextHistory),
1116        ("\x1bOC".into(), ForwardChar),
1117        ("\x1bOD".into(), BackwardChar),
1118        ("\x1bOH".into(), BeginningOfLine),
1119        ("\x1bOF".into(), EndOfLine),
1120        // Possible sequences for Insert, Delete
1121        ("\x1b[2~".into(), OverwriteMode),
1122        ("\x1b[3~".into(), DeleteChar),
1123        // Basic commands
1124        ("\x01".into(), BeginningOfLine),             // Ctrl-A
1125        ("\x02".into(), BackwardChar),                // Ctrl-B
1126        ("\x04".into(), DeleteChar),                  // Ctrl-D
1127        ("\x05".into(), EndOfLine),                   // Ctrl-E
1128        ("\x06".into(), ForwardChar),                 // Ctrl-F
1129        ("\x07".into(), Abort),                       // Ctrl-G
1130        ("\x08".into(), BackwardDeleteChar),          // Ctrl-H
1131        ("\x0b".into(), KillLine),                    // Ctrl-K
1132        ("\x0c".into(), ClearScreen),                 // Ctrl-L
1133        ("\x0e".into(), NextHistory),                 // Ctrl-N
1134        ("\x10".into(), PreviousHistory),             // Ctrl-P
1135        ("\x12".into(), ReverseSearchHistory),        // Ctrl-R
1136        ("\x14".into(), TransposeChars),              // Ctrl-T
1137        ("\x15".into(), BackwardKillLine),            // Ctrl-U
1138        ("\x16".into(), QuotedInsert),                // Ctrl-V
1139        ("\x17".into(), UnixWordRubout),              // Ctrl-W
1140        ("\x19".into(), Yank),                        // Ctrl-Y
1141        ("\x1d".into(), CharacterSearch),             // Ctrl-]
1142        ("\x7f".into(), BackwardDeleteChar),          // Rubout
1143        ("\x1b\x08".into(), BackwardKillWord),        // Escape, Ctrl-H
1144        ("\x1b\x1d".into(), CharacterSearchBackward), // Escape, Ctrl-]
1145        ("\x1b\x7f".into(), BackwardKillWord),        // Escape, Rubout
1146        ("\x1bb".into(), BackwardWord),               // Escape, b
1147        ("\x1bd".into(), KillWord),                   // Escape, d
1148        ("\x1bf".into(), ForwardWord),                // Escape, f
1149        ("\x1bt".into(), TransposeWords),             // Escape, t
1150        ("\x1by".into(), YankPop),                    // Escape, y
1151        ("\x1b#".into(), InsertComment),              // Escape, #
1152        ("\x1b<".into(), BeginningOfHistory),         // Escape, <
1153        ("\x1b>".into(), EndOfHistory),               // Escape, >
1154        // Completion commands
1155        ("\t".into(), Complete),               // Tab
1156        ("\x1b?".into(), PossibleCompletions), // Escape, ?
1157        ("\x1b*".into(), InsertCompletions),   // Escape, *
1158        // Digit commands
1159        ("\x1b-".into(), DigitArgument), // Escape, -
1160        ("\x1b0".into(), DigitArgument), // Escape, 0
1161        ("\x1b1".into(), DigitArgument), // Escape, 1
1162        ("\x1b2".into(), DigitArgument), // Escape, 2
1163        ("\x1b3".into(), DigitArgument), // Escape, 3
1164        ("\x1b4".into(), DigitArgument), // Escape, 4
1165        ("\x1b5".into(), DigitArgument), // Escape, 5
1166        ("\x1b6".into(), DigitArgument), // Escape, 6
1167        ("\x1b7".into(), DigitArgument), // Escape, 7
1168        ("\x1b8".into(), DigitArgument), // Escape, 8
1169        ("\x1b9".into(), DigitArgument), // Escape, 9
1170    ])
1171}
1172
1173fn limit_duration(dur: Option<Duration>, max: Option<Duration>) -> Option<Duration> {
1174    match (dur, max) {
1175        (dur, None) | (None, dur) => dur,
1176        (Some(dur), Some(max)) => Some(dur.min(max)),
1177    }
1178}