summaryrefslogtreecommitdiff
path: root/helix-term/src/commands
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src/commands')
-rw-r--r--helix-term/src/commands/lsp.rs8
-rw-r--r--helix-term/src/commands/typed.rs130
2 files changed, 100 insertions, 38 deletions
diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs
index 1113b44e..3fa5c96f 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-term/src/commands/lsp.rs
@@ -9,7 +9,7 @@ use tui::text::{Span, Spans};
use super::{align_view, push_jump, Align, Context, Editor, Open};
use helix_core::{path, Selection};
-use helix_view::{editor::Action, theme::Style};
+use helix_view::{apply_transaction, editor::Action, theme::Style};
use crate::{
compositor::{self, Compositor},
@@ -596,9 +596,7 @@ pub fn apply_workspace_edit(
}
};
- let doc = editor
- .document_mut(doc_id)
- .expect("Document for document_changes not found");
+ let doc = doc_mut!(editor, &doc_id);
// Need to determine a view for apply/append_changes_to_history
let selections = doc.selections();
@@ -619,7 +617,7 @@ pub fn apply_workspace_edit(
text_edits,
offset_encoding,
);
- doc.apply(&transaction, view_id);
+ apply_transaction(&transaction, doc, view_mut!(editor, view_id));
doc.append_changes_to_history(view_id);
};
diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs
index 6d0ced65..1bfc8153 100644
--- a/helix-term/src/commands/typed.rs
+++ b/helix-term/src/commands/typed.rs
@@ -2,7 +2,10 @@ use std::ops::Deref;
use super::*;
-use helix_view::editor::{Action, ConfigEvent};
+use helix_view::{
+ apply_transaction,
+ editor::{Action, CloseError, ConfigEvent},
+};
use ui::completers::{self, Completer};
#[derive(Clone)]
@@ -71,8 +74,29 @@ fn buffer_close_by_ids_impl(
doc_ids: &[DocumentId],
force: bool,
) -> anyhow::Result<()> {
- for &doc_id in doc_ids {
- editor.close_document(doc_id, force)?;
+ let (modified_ids, modified_names): (Vec<_>, Vec<_>) = doc_ids
+ .iter()
+ .filter_map(|&doc_id| {
+ if let Err(CloseError::BufferModified(name)) = editor.close_document(doc_id, force) {
+ Some((doc_id, name))
+ } else {
+ None
+ }
+ })
+ .unzip();
+
+ if let Some(first) = modified_ids.first() {
+ let current = doc!(editor);
+ // If the current document is unmodified, and there are modified
+ // documents, switch focus to the first modified doc.
+ if !modified_ids.contains(&current.id()) {
+ editor.switch(*first, Action::Replace);
+ }
+ bail!(
+ "{} unsaved buffer(s) remaining: {:?}",
+ modified_names.len(),
+ modified_names
+ );
}
Ok(())
@@ -441,7 +465,7 @@ fn set_line_ending(
}
}),
);
- doc.apply(&transaction, view.id);
+ apply_transaction(&transaction, doc, view);
doc.append_changes_to_history(view.id);
Ok(())
@@ -459,7 +483,7 @@ fn earlier(
let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
let (view, doc) = current!(cx.editor);
- let success = doc.earlier(view.id, uk);
+ let success = doc.earlier(view, uk);
if !success {
cx.editor.set_status("Already at oldest change");
}
@@ -478,7 +502,7 @@ fn later(
let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
let (view, doc) = current!(cx.editor);
- let success = doc.later(view.id, uk);
+ let success = doc.later(view, uk);
if !success {
cx.editor.set_status("Already at newest change");
}
@@ -513,23 +537,26 @@ fn force_write_quit(
force_quit(cx, &[], event)
}
-/// Results an error if there are modified buffers remaining and sets editor error,
-/// otherwise returns `Ok(())`
+/// Results in an error if there are modified buffers remaining and sets editor
+/// error, otherwise returns `Ok(())`. If the current document is unmodified,
+/// and there are modified documents, switches focus to one of them.
pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> {
- let modified: Vec<_> = editor
+ let (modified_ids, modified_names): (Vec<_>, Vec<_>) = editor
.documents()
.filter(|doc| doc.is_modified())
- .map(|doc| {
- doc.relative_path()
- .map(|path| path.to_string_lossy().to_string())
- .unwrap_or_else(|| SCRATCH_BUFFER_NAME.into())
- })
- .collect();
- if !modified.is_empty() {
+ .map(|doc| (doc.id(), doc.display_name()))
+ .unzip();
+ if let Some(first) = modified_ids.first() {
+ let current = doc!(editor);
+ // If the current document is unmodified, and there are modified
+ // documents, switch focus to the first modified doc.
+ if !modified_ids.contains(&current.id()) {
+ editor.switch(*first, Action::Replace);
+ }
bail!(
"{} unsaved buffer(s) remaining: {:?}",
- modified.len(),
- modified
+ modified_names.len(),
+ modified_names
);
}
Ok(())
@@ -859,7 +886,7 @@ fn replace_selections_with_clipboard_impl(
(range.from(), range.to(), Some(contents.as_str().into()))
});
- doc.apply(&transaction, view.id);
+ apply_transaction(&transaction, doc, view);
doc.append_changes_to_history(view.id);
Ok(())
}
@@ -980,7 +1007,7 @@ fn reload(
let scrolloff = cx.editor.config().scrolloff;
let (view, doc) = current!(cx.editor);
- doc.reload(view.id).map(|_| {
+ doc.reload(view).map(|_| {
view.ensure_cursor_in_view(doc, scrolloff);
})
}
@@ -1000,7 +1027,7 @@ fn lsp_restart(
.context("LSP not defined for the current document")?;
let scope = config.scope.clone();
- cx.editor.language_servers.restart(config)?;
+ cx.editor.language_servers.restart(config, doc.path())?;
// This collect is needed because refresh_language_server would need to re-borrow editor.
let document_ids_to_refresh: Vec<DocumentId> = cx
@@ -1033,7 +1060,21 @@ fn tree_sitter_scopes(
let pos = doc.selection(view.id).primary().cursor(text);
let scopes = indent::get_scopes(doc.syntax(), text, pos);
- cx.editor.set_status(format!("scopes: {:?}", &scopes));
+
+ let contents = format!("```json\n{:?}\n````", scopes);
+
+ let callback = async move {
+ let call: job::Callback =
+ Box::new(move |editor: &mut Editor, compositor: &mut Compositor| {
+ let contents = ui::Markdown::new(contents, editor.syn_loader.clone());
+ let popup = Popup::new("hover", contents).auto_close(true);
+ compositor.replace_or_push("hover", popup);
+ });
+ Ok(call)
+ };
+
+ cx.jobs.callback(callback);
+
Ok(())
}
@@ -1196,18 +1237,41 @@ pub(super) fn goto_line_number(
args: &[Cow<str>],
event: PromptEvent,
) -> anyhow::Result<()> {
- if event != PromptEvent::Validate {
- return Ok(());
+ match event {
+ PromptEvent::Abort => {
+ if let Some(line_number) = cx.editor.last_line_number {
+ goto_line_impl(cx.editor, NonZeroUsize::new(line_number));
+ let (view, doc) = current!(cx.editor);
+ view.ensure_cursor_in_view(doc, line_number);
+ cx.editor.last_line_number = None;
+ }
+ return Ok(());
+ }
+ PromptEvent::Validate => {
+ ensure!(!args.is_empty(), "Line number required");
+ cx.editor.last_line_number = None;
+ }
+ PromptEvent::Update => {
+ if args.is_empty() {
+ if let Some(line_number) = cx.editor.last_line_number {
+ // When a user hits backspace and there are no numbers left,
+ // we can bring them back to their original line
+ goto_line_impl(cx.editor, NonZeroUsize::new(line_number));
+ let (view, doc) = current!(cx.editor);
+ view.ensure_cursor_in_view(doc, line_number);
+ cx.editor.last_line_number = None;
+ }
+ return Ok(());
+ }
+ let (view, doc) = current!(cx.editor);
+ let text = doc.text().slice(..);
+ let line = doc.selection(view.id).primary().cursor_line(text);
+ cx.editor.last_line_number.get_or_insert(line + 1);
+ }
}
-
- ensure!(!args.is_empty(), "Line number required");
-
let line = args[0].parse::<usize>()?;
-
goto_line_impl(cx.editor, NonZeroUsize::new(line));
-
let (view, doc) = current!(cx.editor);
-
view.ensure_cursor_in_view(doc, line);
Ok(())
}
@@ -1351,7 +1415,7 @@ fn sort_impl(
.map(|(s, fragment)| (s.from(), s.to(), Some(fragment))),
);
- doc.apply(&transaction, view.id);
+ apply_transaction(&transaction, doc, view);
doc.append_changes_to_history(view.id);
Ok(())
@@ -1395,7 +1459,7 @@ fn reflow(
(range.from(), range.to(), Some(reflowed_text))
});
- doc.apply(&transaction, view.id);
+ apply_transaction(&transaction, doc, view);
doc.append_changes_to_history(view.id);
view.ensure_cursor_in_view(doc, scrolloff);
@@ -2021,7 +2085,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand {
name: "insert-output",
aliases: &[],
- doc: "Run shell command, inserting output after each selection.",
+ doc: "Run shell command, inserting output before each selection.",
fun: insert_output,
completer: None,
},