Skip to content

Commit

Permalink
Set editor cursor position in C-x in vim and emacs
Browse files Browse the repository at this point in the history
Fixes #243
  • Loading branch information
osa1 committed Aug 29, 2020
1 parent 91c43cc commit da61106
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 14 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
RPL_WELCOME) before JOIN messages (after RPL_ENDOFMOTD), sometimes
identification takes so long JOIN command fails with a 477. We now try joining
again with 10 seconds breaks, up to 3 times. (#236, #240)
- When $EDITOR is (n)vim or emacs, C-x now places the cursor at its location in
the input field in the vim/emacs buffer. (#243)

# 2020/06/28: 0.6.0

Expand Down
30 changes: 24 additions & 6 deletions libtiny_tui/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
use termbox_simple::Termbox;
use tokio::sync::oneshot;

use std::io::{Read, Seek, SeekFrom, Write};
use std::process::Command;

#[derive(Debug)]
pub(crate) enum Error {
Io(::std::io::Error),
Expand All @@ -42,17 +45,14 @@ pub(crate) type Result<A> = ::std::result::Result<A, Error>;

pub(crate) type ResultReceiver = oneshot::Receiver<Result<Vec<String>>>;

/// `cursor` is the cursor location in `text_field_contents`.
pub(crate) fn run(
tb: &mut Termbox,
text_field_contents: &str,
cursor: i32, // location of cursor in `text_field_contents`
pasted_text: &str,
rcv_editor_ret: &mut Option<ResultReceiver>,
) -> Result<()> {
use std::{
io::{Read, Seek, SeekFrom, Write},
process::Command,
};

let editor = ::std::env::var("EDITOR")?;
let mut tmp_file = ::tempfile::NamedTempFile::new()?;

Expand All @@ -76,7 +76,25 @@ pub(crate) fn run(
// won't be reading term_input until it reads from rcv_editor_ret, so the editor has control
// over the tty, stdout, and stdin.
tokio::task::spawn_blocking(move || {
let ret = Command::new(editor).arg(tmp_file.path()).status();
let mut cmd = Command::new(&editor);

// If the editor is (n)vim or emacs, pass parameters to move the cursor to its location in
// `text_field_contents`
match editor.as_ref() {
"vim" | "nvim" => {
if cursor == 0 {
cmd.arg("-c").arg("normal! 3j");
} else {
cmd.arg("-c").arg(format!("normal! 3j{}l", cursor));
}
}
"emacs" => {
cmd.arg(format!("+4:{}", cursor + 1));
}
_ => {}
}

let ret = cmd.arg(tmp_file.path()).status();
let ret = match ret {
Err(io_err) => {
snd_editor_ret.send(Err(io_err.into())).unwrap();
Expand Down
8 changes: 4 additions & 4 deletions libtiny_tui/src/input_area/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,10 @@ impl InputArea {
}
}

/// Get contents of the text field and clear it.
pub(crate) fn flush(&mut self) -> String {
self.cursor = 0;
self.buffer.drain(..).collect()
/// Get contents of the text field and cursor location and clear it.
pub(crate) fn flush(&mut self) -> (String, i32) {
let cursor = ::std::mem::replace(&mut self.cursor, 0);
(self.buffer.drain(..).collect(), cursor)
}

/// Add a line to the text field history.
Expand Down
4 changes: 2 additions & 2 deletions libtiny_tui/src/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ impl MessagingUI {
}
}

/// Get contents of the input field and clear it.
pub(crate) fn flush_input_field(&mut self) -> String {
/// Get contents of the input field and cursor location and clear it.
pub(crate) fn flush_input_field(&mut self) -> (String, i32) {
self.input_field.flush()
}

Expand Down
4 changes: 2 additions & 2 deletions libtiny_tui/src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,8 @@ impl TUI {
/// Edit current input + `str` before sending.
fn run_editor(&mut self, str: &str, rcv_editor_ret: &mut Option<editor::ResultReceiver>) {
let tab = &mut self.tabs[self.active_idx].widget;
let tf = tab.flush_input_field();
match editor::run(&mut self.tb, &tf, &str, rcv_editor_ret) {
let (msg, cursor) = tab.flush_input_field();
match editor::run(&mut self.tb, &msg, cursor, str, rcv_editor_ret) {
Ok(()) => {}
Err(err) => self.handle_editor_err(err),
}
Expand Down

0 comments on commit da61106

Please sign in to comment.