Support more control over input buffer

This PR adds a new message: `UpdateInputBuffer: InputOperation`

This makes it possible to perform cursor based input operations without
needing input from the keyboard.
This commit is contained in:
Arijit Basu 2021-11-05 14:52:52 +05:30 committed by Arijit Basu
parent b45a553a0c
commit 05c2f7aa68
3 changed files with 104 additions and 23 deletions

View File

@ -210,9 +210,25 @@ Go to the next path visited.
Follow the symlink under focus to its actual location.
### { UpdateInputBuffer = [Input Opertaion][71] }
**YAML:** `BufferInput: Input Operation`
Update the input buffer using cursor based operations.
**YAML Example:** `UpdateInputBuffer: GoToPreviousWord`
**Lua Example:** `{ UpdateInputBuffer = "GoToPreviousWord" }`
### "UpdateInputBufferFromKey"
**YAML:** `UpdateInputBufferFromKey`
Update the input buffer from the key read from keyboard input.
### { BufferInput = "string" }
**YAML:** `BufferInput(String)`
**YAML:** `BufferInput: string`
Append/buffer the given string into the input buffer.
@ -790,6 +806,24 @@ Write the application state to a file, without quitting. Also helpful for debugg
Terminate the application with a non-zero return code.
## InputOperation
Cursor based input operation can be one of the following:
- { SetCursor = int }
- { InsertCharacter = str }
- "GoToPreviousCharacter"
- "GoToNextCharacter"
- "GoToPreviousWord"
- "GoToNextWord"
- "GoToStart"
- "GoToEnd"
- "DeletePreviousCharacter"
- "DeleteNextCharacter"
- "DeletePreviousWord"
- "DeleteNextWord"
- "DeleteLine"
## Lua Function Calls
xplr allows users to define lua functions using the `xplr.fn.custom` Lua API.
@ -1286,3 +1320,4 @@ xplr.config.modes.builtin.default.key_bindings.on_key.space = {
[68]: #loc
[69]: #paths
[70]: #history-1
[71]: #inputoperation

View File

@ -1,7 +1,7 @@
use crate::config::Config;
use crate::config::Mode;
use crate::explorer;
use crate::input::Key;
use crate::input::{InputOperation, Key};
use crate::lua;
use crate::permissions::Permissions;
use crate::ui::Layout;
@ -777,6 +777,11 @@ pub enum ExternalMsg {
/// Follow the symlink under focus to its actual location.
FollowSymlink,
/// Update the input buffer using cursor based operations.
///
/// **Example:** `UpdateInputBuffer: GoToPreviousWord`
UpdateInputBuffer(InputOperation),
/// Update the input buffer from given key
UpdateInputBufferFromKey,
@ -1481,6 +1486,9 @@ impl App {
ExternalMsg::LastVisitedPath => self.last_visited_path(),
ExternalMsg::NextVisitedPath => self.next_visited_path(),
ExternalMsg::FollowSymlink => self.follow_symlink(),
ExternalMsg::UpdateInputBuffer(op) => {
self.update_input_buffer(op)
}
ExternalMsg::UpdateInputBufferFromKey => {
self.update_input_buffer_from_key(key)
}
@ -1886,18 +1894,21 @@ impl App {
}
}
fn update_input_buffer_from_key(
mut self,
key: Option<Key>,
) -> Result<Self> {
if let Some(req) = key.and_then(|k| k.to_input_request()) {
if let Some(buf) = self.input.as_mut() {
buf.handle(req);
}
fn update_input_buffer(mut self, op: InputOperation) -> Result<Self> {
if let Some(buf) = self.input.as_mut() {
buf.handle(op.into());
}
Ok(self)
}
fn update_input_buffer_from_key(self, key: Option<Key>) -> Result<Self> {
if let Some(op) = key.and_then(|k| k.to_input_operation()) {
self.update_input_buffer(op)
} else {
Ok(self)
}
}
fn buffer_input(mut self, input: &str) -> Result<Self> {
if let Some(buf) = self.input.as_mut() {
buf.handle(InputRequest::GoToEnd);

View File

@ -208,27 +208,25 @@ impl std::fmt::Display for Key {
}
impl Key {
pub fn to_input_request(&self) -> Option<InputRequest> {
use InputRequest::*;
pub fn to_input_operation(&self) -> Option<InputOperation> {
use InputOperation::*;
use Key::*;
match self {
Backspace => Some(DeletePrevChar),
Delete => Some(DeleteNextChar),
Tab => Some(InsertChar('\t')),
Space => Some(InsertChar(' ')),
Left => Some(GoToPrevChar),
CtrlLeft => Some(GoToPrevWord),
Right => Some(GoToNextChar),
Backspace => Some(DeletePreviousCharacter),
Delete => Some(DeleteNextCharacter),
Tab => Some(InsertCharacter('\t')),
Space => Some(InsertCharacter(' ')),
Left => Some(GoToPreviousCharacter),
CtrlLeft => Some(GoToPreviousWord),
Right => Some(GoToNextCharacter),
CtrlRight => Some(GoToNextWord),
CtrlU => Some(DeleteLine),
CtrlW => Some(DeletePrevWord),
CtrlW => Some(DeletePreviousWord),
CtrlDelete => Some(DeleteNextWord),
CtrlA => Some(GoToStart),
CtrlE => Some(GoToEnd),
Enter => Some(Submit),
Esc => Some(Escape),
key => key.to_char().map(InsertChar),
key => key.to_char().map(InsertCharacter),
}
}
@ -726,3 +724,40 @@ impl PartialOrd for Key {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum InputOperation {
SetCursor(usize),
InsertCharacter(char),
GoToPreviousCharacter,
GoToNextCharacter,
GoToPreviousWord,
GoToNextWord,
GoToStart,
GoToEnd,
DeletePreviousCharacter,
DeleteNextCharacter,
DeletePreviousWord,
DeleteNextWord,
DeleteLine,
}
impl Into<InputRequest> for InputOperation {
fn into(self) -> InputRequest {
match self {
Self::SetCursor(i) => InputRequest::SetCursor(i),
Self::InsertCharacter(c) => InputRequest::InsertChar(c),
Self::GoToPreviousCharacter => InputRequest::GoToPrevChar,
Self::GoToNextCharacter => InputRequest::GoToNextChar,
Self::GoToPreviousWord => InputRequest::GoToPrevWord,
Self::GoToNextWord => InputRequest::GoToNextWord,
Self::GoToStart => InputRequest::GoToStart,
Self::GoToEnd => InputRequest::GoToEnd,
Self::DeletePreviousCharacter => InputRequest::DeletePrevChar,
Self::DeleteNextCharacter => InputRequest::DeleteNextChar,
Self::DeletePreviousWord => InputRequest::DeletePrevWord,
Self::DeleteNextWord => InputRequest::DeleteNextWord,
Self::DeleteLine => InputRequest::DeleteLine,
}
}
}