Skip to content

Commit

Permalink
Merge pull request #379 from tailhook/accept_line
Browse files Browse the repository at this point in the history
Flexible AcceptLine, fix bug in multi-line accept
  • Loading branch information
gwenn authored Oct 11, 2020
2 parents 928ad1f + fc5d234 commit e9408c9
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 20 deletions.
26 changes: 22 additions & 4 deletions src/keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub enum Cmd {
/// abort
Abort, // Miscellaneous Command
/// accept-line
///
/// See also AcceptOrInsertLine
AcceptLine,
/// beginning-of-history
BeginningOfHistory,
Expand Down Expand Up @@ -99,9 +101,23 @@ pub enum Cmd {
/// moves cursor to the line below or switches to next history entry if
/// the cursor is already on the last line
LineDownOrNextHistory(RepeatCount),
/// accepts the line when cursor is at the end of the text (non including
/// trailing whitespace), inserts newline character otherwise
AcceptOrInsertLine,
/// Inserts a newline
Newline,
/// Either accepts or inserts a newline
///
/// Always inserts newline if input is non-valid. Can also insert newline
/// if cursor is in the middle of the text
///
/// If you support multi-line input:
/// * Use `accept_in_the_middle: true` for mostly single-line cases,
/// for example command-line.
/// * Use `accept_in_the_middle: false` for mostly multi-line cases,
/// for example SQL or JSON input.
AcceptOrInsertLine {
/// Whether this commands accepts input if the cursor not at the end
/// of the current input
accept_in_the_middle: bool
},
}

impl Cmd {
Expand Down Expand Up @@ -934,7 +950,9 @@ impl InputState {
}
}
KeyPress::Ctrl('J') |
KeyPress::Enter => Cmd::AcceptLine,
KeyPress::Enter => {
Cmd::AcceptOrInsertLine { accept_in_the_middle: true }
}
KeyPress::Down => Cmd::LineDownOrNextHistory(1),
KeyPress::Up => Cmd::LineUpOrPreviousHistory(1),
KeyPress::Ctrl('R') => Cmd::ReverseSearchHistory,
Expand Down
57 changes: 42 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,15 +282,16 @@ fn page_completions<C: Candidate, H: Helper>(
&& cmd != Cmd::SelfInsert(1, ' ')
&& cmd != Cmd::Kill(Movement::BackwardChar(1))
&& cmd != Cmd::AcceptLine
&& cmd != Cmd::AcceptOrInsertLine
&& cmd != Cmd::Newline
&& !matches!(cmd, Cmd::AcceptOrInsertLine { .. })
{
cmd = s.next_cmd(input_state, rdr, false)?;
}
match cmd {
Cmd::SelfInsert(1, 'y') | Cmd::SelfInsert(1, 'Y') | Cmd::SelfInsert(1, ' ') => {
pause_row += s.out.get_rows() - 1;
}
Cmd::AcceptLine | Cmd::AcceptOrInsertLine => {
Cmd::AcceptLine | Cmd::Newline | Cmd::AcceptOrInsertLine { .. } => {
pause_row += 1;
}
_ => break,
Expand Down Expand Up @@ -428,6 +429,7 @@ fn readline_edit<H: Helper>(
editor.reset_kill_ring(); // TODO recreate a new kill ring vs Arc<Mutex<KillRing>>
let ctx = Context::new(&editor.history);
let mut s = State::new(&mut stdout, prompt, helper, ctx);

let mut input_state = InputState::new(&editor.config, Arc::clone(&editor.custom_bindings));

s.line.set_delete_listener(editor.kill_ring.clone());
Expand Down Expand Up @@ -516,13 +518,19 @@ fn readline_edit<H: Helper>(
s.edit_overwrite_char(c)?;
}
Cmd::EndOfFile => {
if !input_state.is_emacs_mode() && !s.line.is_empty() {
s.edit_move_end()?;
break;
} else if s.line.is_empty() {
return Err(error::ReadlineError::Eof);
} else {
if input_state.is_emacs_mode() && !s.line.is_empty() {
s.edit_delete(1)?
} else {
if s.has_hint() || !s.is_default_prompt() {
// Force a refresh without hints to leave the previous
// line as the user typed it after a newline.
s.refresh_line_with_msg(None)?;
}
if s.line.is_empty() {
return Err(error::ReadlineError::Eof);
} else if !input_state.is_emacs_mode() {
break;
}
}
}
Cmd::Move(Movement::EndOfLine) => {
Expand Down Expand Up @@ -582,7 +590,7 @@ fn readline_edit<H: Helper>(
kill_ring.kill(&text, Mode::Append)
}
}
Cmd::AcceptLine | Cmd::AcceptOrInsertLine => {
Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } | Cmd::Newline => {
#[cfg(test)]
{
editor.term.cursor = s.layout.cursor.col;
Expand All @@ -592,13 +600,23 @@ fn readline_edit<H: Helper>(
// line as the user typed it after a newline.
s.refresh_line_with_msg(None)?;
}
// Only accept value if cursor is at the end of the buffer
if s.validate()? && (cmd == Cmd::AcceptLine || s.line.is_end_of_input()) {
break;
} else {
s.edit_insert('\n', 1)?;
let valid = s.validate()?;
let end = s.line.is_end_of_input();
match (cmd, valid, end) {
| (Cmd::AcceptLine, _, _)
| (Cmd::AcceptOrInsertLine { .. }, true, true)
| (Cmd::AcceptOrInsertLine { accept_in_the_middle: true }, true, _)
=> {
break;
}
| (Cmd::Newline, _, _)
| (Cmd::AcceptOrInsertLine { .. }, false, _)
| (Cmd::AcceptOrInsertLine { .. }, true, false)
=> {
s.edit_insert('\n', 1)?;
}
_ => unreachable!(),
}
continue;
}
Cmd::BeginningOfHistory => {
// move to first entry in history
Expand Down Expand Up @@ -663,6 +681,10 @@ fn readline_edit<H: Helper>(
}
}
Cmd::Interrupt => {
// Move to end, in case cursor was in the middle of the
// line, so that next thing application prints goes after
// the input
s.edit_move_buffer_end()?;
return Err(error::ReadlineError::Interrupted);
}
#[cfg(unix)]
Expand All @@ -678,6 +700,11 @@ fn readline_edit<H: Helper>(
}
}
}

// Move to end, in case cursor was in the middle of the line, so that
// next thing application prints goes after the input
s.edit_move_buffer_end()?;

if cfg!(windows) {
let _ = original_mode; // silent warning
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fn complete_line() {
let keys = vec![KeyPress::Enter];
let mut rdr: IntoIter<KeyPress> = keys.into_iter();
let cmd = super::complete_line(&mut rdr, &mut s, &mut input_state, &Config::default()).unwrap();
assert_eq!(Some(Cmd::AcceptLine), cmd);
assert_eq!(Some(Cmd::AcceptOrInsertLine { accept_in_the_middle: true }), cmd);
assert_eq!("rust", s.line.as_str());
assert_eq!(4, s.line.pos());
}
Expand Down

0 comments on commit e9408c9

Please sign in to comment.