Skip to content

Commit

Permalink
Autosave all when the terminal loses focus
Browse files Browse the repository at this point in the history
  • Loading branch information
groves committed Sep 2, 2022
1 parent e8730ca commit 96d6f6f
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 36 deletions.
1 change: 1 addition & 0 deletions book/src/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ You may also specify a file to use for configuration with the `-c` or
| `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers` and `spacer`, note that `diagnostics` also includes other features like breakpoints, 1-width padding will be inserted if gutters is non-empty | `["diagnostics", "line-numbers"]` |
| `auto-completion` | Enable automatic pop up of auto-completion. | `true` |
| `auto-format` | Enable automatic formatting on save. | `true` |
| `auto-save` | Enable automatic saving on focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal. | `false` |
| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` |
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
| `auto-info` | Whether to display infoboxes | `true` |
Expand Down
12 changes: 9 additions & 3 deletions helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use anyhow::{Context, Error};

use crossterm::{
event::{
DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture,
Event as CrosstermEvent,
DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste,
EnableFocusChange, EnableMouseCapture, Event as CrosstermEvent,
},
execute, terminal,
tty::IsTty,
Expand Down Expand Up @@ -95,6 +95,7 @@ fn restore_term() -> Result<(), Error> {
execute!(
stdout,
DisableBracketedPaste,
DisableFocusChange,
terminal::LeaveAlternateScreen
)?;
terminal::disable_raw_mode()?;
Expand Down Expand Up @@ -811,7 +812,12 @@ impl Application {
async fn claim_term(&mut self) -> Result<(), Error> {
terminal::enable_raw_mode()?;
let mut stdout = stdout();
execute!(stdout, terminal::EnterAlternateScreen, EnableBracketedPaste)?;
execute!(
stdout,
terminal::EnterAlternateScreen,
EnableBracketedPaste,
EnableFocusChange
)?;
execute!(stdout, terminal::Clear(terminal::ClearType::All))?;
if self.config.load().editor.mouse {
execute!(stdout, EnableMouseCapture)?;
Expand Down
51 changes: 19 additions & 32 deletions helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,28 +535,24 @@ pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()>
Ok(())
}

fn write_all_impl(
pub fn write_all_impl(
cx: &mut compositor::Context,
_args: &[Cow<str>],
event: PromptEvent,
quit: bool,
force: bool,
write_scratch: bool,
) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}

let mut errors = String::new();
let auto_format = cx.editor.config().auto_format;
let jobs = &mut cx.jobs;
// save all documents
for doc in &mut cx.editor.documents.values_mut() {
if doc.path().is_none() {
errors.push_str("cannot write a buffer without a filename\n");
if !doc.is_modified() {
continue;
}

if !doc.is_modified() {
if doc.path().is_none() {
if write_scratch {
errors.push_str("cannot write a buffer without a filename\n");
}
continue;
}

Expand All @@ -579,55 +575,46 @@ fn write_all_impl(
jobs.add(Job::new(future).wait_before_exiting());
}

if quit {
if !force {
buffers_remaining_impl(cx.editor)?;
}

// close all views
let views: Vec<_> = cx.editor.tree.views().map(|(view, _)| view.id).collect();
for view_id in views {
cx.editor.close(view_id);
}
match errors.len() {
0 => Ok(()),
_ => bail!(errors),
}

bail!(errors)
}

fn write_all(
cx: &mut compositor::Context,
args: &[Cow<str>],
_args: &[Cow<str>],
event: PromptEvent,
) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}

write_all_impl(cx, args, event, false, false)
write_all_impl(cx, false, true)
}

fn write_all_quit(
cx: &mut compositor::Context,
args: &[Cow<str>],
_args: &[Cow<str>],
event: PromptEvent,
) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}

write_all_impl(cx, args, event, true, false)
write_all_impl(cx, false, true)?;
quit_all_impl(cx.editor, false)
}

fn force_write_all_quit(
cx: &mut compositor::Context,
args: &[Cow<str>],
_args: &[Cow<str>],
event: PromptEvent,
) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}

write_all_impl(cx, args, event, true, true)
let _ = write_all_impl(cx, true, true);
quit_all_impl(cx.editor, true)
}

fn quit_all_impl(editor: &mut Editor, force: bool) -> anyhow::Result<()> {
Expand Down Expand Up @@ -2008,7 +1995,7 @@ pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableComma
.collect()
});

pub fn command_mode(cx: &mut Context) {
pub(super) fn command_mode(cx: &mut Context) {
let mut prompt = Prompt::new(
":".into(),
Some(':'),
Expand Down
10 changes: 9 additions & 1 deletion helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,15 @@ impl Component for EditorView {
}

Event::Mouse(event) => self.handle_mouse_event(event, &mut cx),
Event::FocusGained | Event::FocusLost => EventResult::Ignored(None),
Event::FocusGained => EventResult::Ignored(None),
Event::FocusLost => {
if context.editor.config().auto_save {
if let Err(e) = commands::typed::write_all_impl(context, false, false) {
context.editor.set_error(format!("{}", e));
}
}
EventResult::Consumed(None)
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ pub struct Config {
pub auto_completion: bool,
/// Automatic formatting on save. Defaults to true.
pub auto_format: bool,
/// Automatic save on focus lost. Defaults to true.
pub auto_save: bool,
/// Time in milliseconds since last keypress before idle timers trigger.
/// Used for autocompletion, set to 0 for instant. Defaults to 400ms.
#[serde(
Expand Down Expand Up @@ -562,6 +564,7 @@ impl Default for Config {
auto_pairs: AutoPairConfig::default(),
auto_completion: true,
auto_format: true,
auto_save: false,
idle_timeout: Duration::from_millis(400),
completion_trigger_len: 2,
auto_info: true,
Expand Down

0 comments on commit 96d6f6f

Please sign in to comment.