aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Tham2021-07-17 14:47:08 +0000
committerBlaž Hrastnik2021-08-03 00:32:21 +0000
commit821565e4efe84f97e08327138cbe8f09aba934e0 (patch)
treeeaf80ea3d12906db4805dfe27e30a51250014243
parentadb5d842ba3ff7e539a77de54a0a8db3018a3844 (diff)
Add ctrl-z to suspend
-rw-r--r--Cargo.lock14
-rw-r--r--helix-lsp/Cargo.toml2
-rw-r--r--helix-term/Cargo.toml6
-rw-r--r--helix-term/src/application.rs84
-rw-r--r--helix-term/src/commands.rs8
-rw-r--r--helix-term/src/compositor.rs17
-rw-r--r--helix-term/src/keymap.rs1
-rw-r--r--helix-tui/src/terminal.rs17
-rw-r--r--helix-view/Cargo.toml2
-rw-r--r--helix-view/src/graphics.rs2
10 files changed, 131 insertions, 22 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5688fd15..5a5fcf4b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -378,6 +378,8 @@ dependencies = [
"pulldown-cmark",
"serde",
"serde_json",
+ "signal-hook",
+ "signal-hook-tokio",
"tokio",
"toml",
]
@@ -866,6 +868,18 @@ dependencies = [
]
[[package]]
+name = "signal-hook-tokio"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6c5d32165ff8b94e68e7b3bdecb1b082e958c22434b363482cfb89dcd6f3ff8"
+dependencies = [
+ "futures-core",
+ "libc",
+ "signal-hook",
+ "tokio",
+]
+
+[[package]]
name = "similar"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml
index cf1f30a7..ef9feb94 100644
--- a/helix-lsp/Cargo.toml
+++ b/helix-lsp/Cargo.toml
@@ -23,5 +23,5 @@ lsp-types = { version = "0.89", features = ["proposed"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
-tokio = { version = "1.9", features = ["full"] }
+tokio = { version = "1.9", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
tokio-stream = "0.1.7"
diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml
index 1fc14ad2..0e2baae3 100644
--- a/helix-term/Cargo.toml
+++ b/helix-term/Cargo.toml
@@ -28,10 +28,11 @@ helix-lsp = { version = "0.3", path = "../helix-lsp" }
anyhow = "1"
once_cell = "1.8"
-tokio = { version = "1", features = ["full"] }
+tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
num_cpus = "1"
tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] }
crossterm = { version = "0.20", features = ["event-stream"] }
+signal-hook = "0.3"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
@@ -53,3 +54,6 @@ toml = "0.5"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
+
+[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
+signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index 5f350671..9e659fb0 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -18,6 +18,10 @@ use crossterm::{
event::{DisableMouseCapture, EnableMouseCapture, Event, EventStream},
execute, terminal,
};
+#[cfg(not(windows))]
+use signal_hook::{consts::signal, low_level};
+#[cfg(not(windows))]
+use signal_hook_tokio::Signals;
pub struct Application {
compositor: Compositor,
@@ -36,6 +40,8 @@ pub struct Application {
#[allow(dead_code)]
syn_loader: Arc<syntax::Loader>,
+ #[cfg(not(windows))]
+ signals: Signals,
jobs: Jobs,
lsp_progress: LspProgressMap,
}
@@ -102,6 +108,9 @@ impl Application {
editor.set_theme(theme);
+ #[cfg(not(windows))]
+ let signals = Signals::new(&[signal::SIGTSTP, signal::SIGCONT])?;
+
let app = Self {
compositor,
editor,
@@ -111,6 +120,8 @@ impl Application {
theme_loader,
syn_loader,
+ #[cfg(not(windows))]
+ signals,
jobs: Jobs::new(),
lsp_progress: LspProgressMap::new(),
};
@@ -147,6 +158,51 @@ impl Application {
use futures_util::StreamExt;
+ #[cfg(not(windows))]
+ tokio::select! {
+ biased;
+
+ event = reader.next() => {
+ self.handle_terminal_events(event)
+ }
+ Some(signal) = self.signals.next() => {
+ use helix_view::graphics::Rect;
+ match signal {
+ signal::SIGTSTP => {
+ self.compositor.save_cursor();
+ self.restore_term().unwrap();
+ low_level::emulate_default_handler(signal::SIGTSTP).unwrap();
+ }
+ signal::SIGCONT => {
+ self.claim_term().await.unwrap();
+ // redraw the terminal
+ let Rect { width, height, .. } = self.compositor.size();
+ self.compositor.resize(width, height);
+ self.compositor.load_cursor();
+ self.render();
+ }
+ _ => unreachable!(),
+ }
+ }
+ Some((id, call)) = self.editor.language_servers.incoming.next() => {
+ self.handle_language_server_message(call, id).await;
+ // limit render calls for fast language server messages
+ let last = self.editor.language_servers.incoming.is_empty();
+ if last || last_render.elapsed() > deadline {
+ self.render();
+ last_render = Instant::now();
+ }
+ }
+ Some(callback) = self.jobs.futures.next() => {
+ self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback);
+ self.render();
+ }
+ Some(callback) = self.jobs.wait_futures.next() => {
+ self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback);
+ self.render();
+ }
+ }
+ #[cfg(windows)]
tokio::select! {
biased;
@@ -443,15 +499,29 @@ impl Application {
}
}
- pub async fn run(&mut self) -> Result<(), Error> {
+ async fn claim_term(&mut self) -> Result<(), Error> {
terminal::enable_raw_mode()?;
-
let mut stdout = stdout();
-
execute!(stdout, terminal::EnterAlternateScreen)?;
+ self.editor.close_language_servers(None).await?;
if self.config.terminal.mouse {
execute!(stdout, EnableMouseCapture)?;
}
+ Ok(())
+ }
+
+ fn restore_term(&mut self) -> Result<(), Error> {
+ let mut stdout = stdout();
+ // reset cursor shape
+ write!(stdout, "\x1B[2 q")?;
+ execute!(stdout, DisableMouseCapture)?;
+ execute!(stdout, terminal::LeaveAlternateScreen)?;
+ terminal::disable_raw_mode()?;
+ Ok(())
+ }
+
+ pub async fn run(&mut self) -> Result<(), Error> {
+ self.claim_term().await?;
// Exit the alternate screen and disable raw mode before panicking
let hook = std::panic::take_hook();
@@ -469,13 +539,7 @@ impl Application {
self.editor.close_language_servers(None).await?;
- // reset cursor shape
- write!(stdout, "\x1B[2 q")?;
-
- execute!(stdout, DisableMouseCapture)?;
- execute!(stdout, terminal::LeaveAlternateScreen)?;
-
- terminal::disable_raw_mode()?;
+ self.restore_term()?;
Ok(())
}
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index cc2c2cca..5cbab34f 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -291,7 +291,8 @@ impl Command {
surround_replace, "Surround replace",
surround_delete, "Surround delete",
select_textobject_around, "Select around object",
- select_textobject_inner, "Select inside object"
+ select_textobject_inner, "Select inside object",
+ suspend, "Suspend"
);
}
@@ -3894,3 +3895,8 @@ fn surround_delete(cx: &mut Context) {
}
})
}
+
+fn suspend(_cx: &mut Context) {
+ #[cfg(not(windows))]
+ signal_hook::low_level::raise(signal_hook::consts::signal::SIGTSTP).unwrap();
+}
diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs
index c2cfa3a7..628c4e13 100644
--- a/helix-term/src/compositor.rs
+++ b/helix-term/src/compositor.rs
@@ -68,7 +68,7 @@ pub trait Component: Any + AnyComponent {
use anyhow::Error;
use std::io::stdout;
-use tui::backend::CrosstermBackend;
+use tui::backend::{Backend, CrosstermBackend};
type Terminal = tui::terminal::Terminal<CrosstermBackend<std::io::Stdout>>;
pub struct Compositor {
@@ -99,6 +99,21 @@ impl Compositor {
.expect("Unable to resize terminal")
}
+ pub fn save_cursor(&mut self) {
+ if self.terminal.cursor_kind() == CursorKind::Hidden {
+ self.terminal
+ .backend_mut()
+ .show_cursor(CursorKind::Block)
+ .ok();
+ }
+ }
+
+ pub fn load_cursor(&mut self) {
+ if self.terminal.cursor_kind() == CursorKind::Hidden {
+ self.terminal.backend_mut().hide_cursor().ok();
+ }
+ }
+
pub fn push(&mut self, mut layer: Box<dyn Component>) {
let size = self.size();
// trigger required_size on init
diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs
index 053b92e6..5fe730a1 100644
--- a/helix-term/src/keymap.rs
+++ b/helix-term/src/keymap.rs
@@ -502,6 +502,7 @@ impl Default for Keymaps {
},
"\"" => select_register,
+ "C-z" => suspend,
});
// TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether
// we keep this separate select mode. More keys can fit into normal mode then, but it's weird
diff --git a/helix-tui/src/terminal.rs b/helix-tui/src/terminal.rs
index 4637eb71..22e9232f 100644
--- a/helix-tui/src/terminal.rs
+++ b/helix-tui/src/terminal.rs
@@ -45,8 +45,8 @@ where
buffers: [Buffer; 2],
/// Index of the current buffer in the previous array
current: usize,
- /// Whether the cursor is currently hidden
- hidden_cursor: bool,
+ /// Kind of cursor (hidden or others)
+ cursor_kind: CursorKind,
/// Viewport
viewport: Viewport,
}
@@ -57,7 +57,7 @@ where
{
fn drop(&mut self) {
// Attempt to restore the cursor state
- if self.hidden_cursor {
+ if self.cursor_kind == CursorKind::Hidden {
if let Err(err) = self.show_cursor(CursorKind::Block) {
eprintln!("Failed to show the cursor: {}", err);
}
@@ -93,7 +93,7 @@ where
Buffer::empty(options.viewport.area),
],
current: 0,
- hidden_cursor: false,
+ cursor_kind: CursorKind::Block,
viewport: options.viewport,
})
}
@@ -185,15 +185,20 @@ where
Ok(())
}
+ #[inline]
+ pub fn cursor_kind(&self) -> CursorKind {
+ self.cursor_kind
+ }
+
pub fn hide_cursor(&mut self) -> io::Result<()> {
self.backend.hide_cursor()?;
- self.hidden_cursor = true;
+ self.cursor_kind = CursorKind::Hidden;
Ok(())
}
pub fn show_cursor(&mut self, kind: CursorKind) -> io::Result<()> {
self.backend.show_cursor(kind)?;
- self.hidden_cursor = false;
+ self.cursor_kind = kind;
Ok(())
}
diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml
index 89e183f0..3617506f 100644
--- a/helix-view/Cargo.toml
+++ b/helix-view/Cargo.toml
@@ -24,7 +24,7 @@ crossterm = { version = "0.20", optional = true }
once_cell = "1.8"
url = "2"
-tokio = { version = "1", features = ["full"] }
+tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
slotmap = "1"
diff --git a/helix-view/src/graphics.rs b/helix-view/src/graphics.rs
index e14ce2b9..5138e923 100644
--- a/helix-view/src/graphics.rs
+++ b/helix-view/src/graphics.rs
@@ -1,7 +1,7 @@
use bitflags::bitflags;
use std::cmp::{max, min};
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy, PartialEq)]
/// UNSTABLE
pub enum CursorKind {
/// █