1use crate::complete_hint_line;
2use crate::config::Config;
3use crate::edit::State;
4use crate::error;
5use crate::history::SearchDirection;
6use crate::keymap::{Anchor, At, Cmd, Movement, Word};
7use crate::keymap::{InputState, Refresher};
8use crate::kill_ring::{KillRing, Mode};
9use crate::line_buffer::WordAction;
10use crate::{Helper, Result};
11
12pub enum Status {
13 Proceed,
14 Submit,
15}
16
17pub fn execute<H: Helper>(
18 cmd: Cmd,
19 s: &mut State<'_, '_, H>,
20 input_state: &InputState,
21 kill_ring: &mut KillRing,
22 config: &Config,
23) -> Result<Status> {
24 use Status::{Proceed, Submit};
25
26 match cmd {
27 Cmd::EndOfFile | Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } | Cmd::Newline => {
28 if s.has_hint() || !s.is_default_prompt() || s.highlight_char {
29 s.forced_refresh = true;
32 s.refresh_line_with_msg(None)?;
33 s.forced_refresh = false;
34 }
35 }
36 _ => {}
37 };
38 match cmd {
39 Cmd::CompleteHint => {
40 complete_hint_line(s)?;
41 }
42 Cmd::SelfInsert(n, c) => {
43 s.edit_insert(c, n)?;
44 }
45 Cmd::Insert(n, text) => {
46 s.edit_yank(input_state, &text, Anchor::Before, n)?;
47 }
48 Cmd::Move(Movement::BeginningOfLine) => {
49 s.edit_move_home()?;
51 }
52 Cmd::Move(Movement::ViFirstPrint) => {
53 s.edit_move_home()?;
54 if s.line.starts_with(char::is_whitespace) {
55 s.edit_move_to_next_word(At::Start, Word::Big, 1)?;
56 }
57 }
58 Cmd::Move(Movement::BackwardChar(n)) => {
59 s.edit_move_backward(n)?;
61 }
62 Cmd::ReplaceChar(n, c) => s.edit_replace_char(c, n)?,
63 Cmd::Replace(mvt, text) => {
64 s.edit_kill(&mvt, kill_ring)?;
65 if let Some(text) = text {
66 s.edit_insert_text(&text)?;
67 }
68 }
69 Cmd::Overwrite(c) => {
70 s.edit_overwrite_char(c)?;
71 }
72 Cmd::EndOfFile => {
73 if s.line.is_empty() {
74 return Err(error::ReadlineError::Eof);
75 } else if !input_state.is_emacs_mode() {
76 return Ok(Submit);
77 }
78 }
79 Cmd::Move(Movement::EndOfLine) => {
80 s.edit_move_end()?;
82 }
83 Cmd::Move(Movement::ForwardChar(n)) => {
84 s.edit_move_forward(n)?;
86 }
87 Cmd::ClearScreen => {
88 s.clear_screen()?;
90 s.refresh_line()?;
91 }
92 Cmd::NextHistory => {
93 s.edit_history_next(false)?;
95 }
96 Cmd::PreviousHistory => {
97 s.edit_history_next(true)?;
99 }
100 Cmd::LineUpOrPreviousHistory(n) => {
101 if !s.edit_move_line_up(n)? {
102 s.edit_history_next(true)?;
103 }
104 }
105 Cmd::LineDownOrNextHistory(n) => {
106 if !s.edit_move_line_down(n)? {
107 s.edit_history_next(false)?;
108 }
109 }
110 Cmd::HistorySearchBackward => s.edit_history_search(SearchDirection::Reverse)?,
111 Cmd::HistorySearchForward => s.edit_history_search(SearchDirection::Forward)?,
112 Cmd::TransposeChars => {
113 s.edit_transpose_chars()?;
115 }
116 Cmd::Yank(n, anchor) => {
117 if let Some(text) = kill_ring.yank() {
119 s.edit_yank(input_state, text, anchor, n)?;
120 }
121 }
122 Cmd::ViYankTo(ref mvt) => {
123 if let Some(text) = s.line.copy(mvt) {
124 kill_ring.kill(&text, Mode::Append);
125 }
126 }
127 Cmd::Newline => {
128 s.edit_insert('\n', 1)?;
129 }
130 Cmd::Repaint => {
131 s.refresh_line()?;
132 }
133 Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } => {
134 let validation_result = s.validate()?;
135 let valid = validation_result.is_valid();
136 let end = s.line.is_end_of_input();
137 match (cmd, valid, end) {
138 (Cmd::AcceptLine, ..)
139 | (Cmd::AcceptOrInsertLine { .. }, true, true)
140 | (
141 Cmd::AcceptOrInsertLine {
142 accept_in_the_middle: true,
143 },
144 true,
145 _,
146 ) => {
147 return Ok(Submit);
148 }
149 (Cmd::AcceptOrInsertLine { .. }, false, _)
150 | (Cmd::AcceptOrInsertLine { .. }, true, false) => {
151 if valid || !validation_result.has_message() {
152 s.edit_insert('\n', 1)?;
153 }
154 }
155 _ => unreachable!(),
156 }
157 }
158 Cmd::BeginningOfHistory => {
159 s.edit_history(true)?;
161 }
162 Cmd::EndOfHistory => {
163 s.edit_history(false)?;
165 }
166 Cmd::Move(Movement::BackwardWord(n, word_def)) => {
167 s.edit_move_to_prev_word(word_def, n)?;
169 }
170 Cmd::CapitalizeWord => {
171 s.edit_word(WordAction::Capitalize)?;
173 }
174 Cmd::Kill(ref mvt) => {
175 s.edit_kill(mvt, kill_ring)?;
176 }
177 Cmd::Move(Movement::ForwardWord(n, at, word_def)) => {
178 s.edit_move_to_next_word(at, word_def, n)?;
180 }
181 Cmd::Move(Movement::LineUp(n)) => {
182 s.edit_move_line_up(n)?;
183 }
184 Cmd::Move(Movement::LineDown(n)) => {
185 s.edit_move_line_down(n)?;
186 }
187 Cmd::Move(Movement::BeginningOfBuffer) => {
188 s.edit_move_buffer_start()?;
190 }
191 Cmd::Move(Movement::EndOfBuffer) => {
192 s.edit_move_buffer_end()?;
194 }
195 Cmd::DowncaseWord => {
196 s.edit_word(WordAction::Lowercase)?;
198 }
199 Cmd::TransposeWords(n) => {
200 s.edit_transpose_words(n)?;
202 }
203 Cmd::UpcaseWord => {
204 s.edit_word(WordAction::Uppercase)?;
206 }
207 Cmd::YankPop => {
208 if let Some((yank_size, text)) = kill_ring.yank_pop() {
210 s.edit_yank_pop(yank_size, text)?;
211 }
212 }
213 Cmd::Move(Movement::ViCharSearch(n, cs)) => s.edit_move_to(cs, n)?,
214 Cmd::Undo(n) => {
215 if s.changes.undo(&mut s.line, n) {
216 s.refresh_line()?;
217 }
218 }
219 Cmd::Dedent(mvt) => {
220 s.edit_indent(&mvt, config.indent_size(), true)?;
221 }
222 Cmd::Indent(mvt) => {
223 s.edit_indent(&mvt, config.indent_size(), false)?;
224 }
225 Cmd::Interrupt => {
226 s.move_cursor_to_end()?;
230 return Err(error::ReadlineError::Interrupted);
231 }
232 _ => {
233 }
235 }
236 Ok(Proceed)
237}