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