Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-view/src/editor.rs')
| -rw-r--r-- | helix-view/src/editor.rs | 171 |
1 files changed, 37 insertions, 134 deletions
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 7f8cff9c..bc811b88 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -14,6 +14,7 @@ use crate::{ tree::{self, Tree}, Document, DocumentId, View, ViewId, }; +use dap::StackFrame; use helix_event::dispatch; use helix_vcs::DiffProviderRegistry; @@ -28,7 +29,7 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, fs, io::{self, stdin}, - num::{NonZeroU8, NonZeroUsize}, + num::NonZeroUsize, path::{Path, PathBuf}, pin::Pin, sync::Arc, @@ -51,7 +52,7 @@ use helix_core::{ }, Change, LineEnding, Position, Range, Selection, Uri, NATIVE_LINE_ENDING, }; -use helix_dap::{self as dap, registry::DebugAdapterId}; +use helix_dap as dap; use helix_lsp::lsp; use helix_stdx::path::canonicalize; @@ -221,49 +222,6 @@ impl Default for FilePickerConfig { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case", default, deny_unknown_fields)] -pub struct FileExplorerConfig { - /// IgnoreOptions - /// Enables ignoring hidden files. - /// Whether to hide hidden files in file explorer and global search results. Defaults to false. - pub hidden: bool, - /// Enables following symlinks. - /// Whether to follow symbolic links in file picker and file or directory completions. Defaults to false. - pub follow_symlinks: bool, - /// Enables reading ignore files from parent directories. Defaults to false. - pub parents: bool, - /// Enables reading `.ignore` files. - /// Whether to hide files listed in .ignore in file picker and global search results. Defaults to false. - pub ignore: bool, - /// Enables reading `.gitignore` files. - /// Whether to hide files listed in .gitignore in file picker and global search results. Defaults to false. - pub git_ignore: bool, - /// Enables reading global .gitignore, whose path is specified in git's config: `core.excludefile` option. - /// Whether to hide files listed in global .gitignore in file picker and global search results. Defaults to false. - pub git_global: bool, - /// Enables reading `.git/info/exclude` files. - /// Whether to hide files listed in .git/info/exclude in file picker and global search results. Defaults to false. - pub git_exclude: bool, - /// Whether to flatten single-child directories in file explorer. Defaults to true. - pub flatten_dirs: bool, -} - -impl Default for FileExplorerConfig { - fn default() -> Self { - Self { - hidden: false, - follow_symlinks: false, - parents: false, - ignore: false, - git_ignore: false, - git_global: false, - git_exclude: false, - flatten_dirs: true, - } - } -} - fn serialize_alphabet<S>(alphabet: &[char], serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, @@ -321,9 +279,6 @@ pub struct Config { /// either absolute or relative to the current opened document or current working directory (if the buffer is not yet saved). /// Defaults to true. pub path_completion: bool, - /// Configures completion of words from open buffers. - /// Defaults to enabled with a trigger length of 7. - pub word_completion: WordCompletion, /// Automatic formatting on save. Defaults to true. pub auto_format: bool, /// Default register used for yank/paste. Defaults to '"' @@ -361,7 +316,6 @@ pub struct Config { /// Whether to display infoboxes. Defaults to true. pub auto_info: bool, pub file_picker: FilePickerConfig, - pub file_explorer: FileExplorerConfig, /// Configuration of the statusline elements pub statusline: StatusLineConfig, /// Shape for cursor in each mode @@ -392,10 +346,6 @@ pub struct Config { pub default_line_ending: LineEndingConfig, /// Whether to automatically insert a trailing line-ending on write if missing. Defaults to `true`. pub insert_final_newline: bool, - /// Whether to use atomic operations to write documents to disk. - /// This prevents data loss if the editor is interrupted while writing the file, but may - /// confuse some file watching/hot reloading programs. Defaults to `true`. - pub atomic_save: bool, /// Whether to automatically remove all trailing line-endings after the final one on write. /// Defaults to `false`. pub trim_final_newlines: bool, @@ -423,19 +373,6 @@ pub struct Config { /// Whether to read settings from [EditorConfig](https://editorconfig.org) files. Defaults to /// `true`. pub editor_config: bool, - /// Whether to render rainbow colors for matching brackets. Defaults to `false`. - pub rainbow_brackets: bool, - /// Whether to enable Kitty Keyboard Protocol - pub kitty_keyboard_protocol: KittyKeyboardProtocolConfig, -} - -#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, Clone, Copy)] -#[serde(rename_all = "kebab-case")] -pub enum KittyKeyboardProtocolConfig { - #[default] - Auto, - Disabled, - Enabled, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] @@ -522,9 +459,6 @@ pub struct LspConfig { pub display_signature_help_docs: bool, /// Display inlay hints pub display_inlay_hints: bool, - /// Maximum displayed length of inlay hints (excluding the added trailing `…`). - /// If it's `None`, there's no limit - pub inlay_hints_length_limit: Option<NonZeroU8>, /// Display document color swatches pub display_color_swatches: bool, /// Whether to enable snippet support @@ -542,7 +476,6 @@ impl Default for LspConfig { auto_signature_help: true, display_signature_help_docs: true, display_inlay_hints: false, - inlay_hints_length_limit: None, snippets: true, goto_reference_include_declaration: true, display_color_swatches: true, @@ -685,9 +618,6 @@ pub enum StatusLineElement { /// Indicator for selected register Register, - - /// The base of current working directory - CurrentWorkingDirectory, } // Cursor shape is read and used on every rendered frame and so needs @@ -1037,22 +967,6 @@ pub enum PopupBorderConfig { Menu, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[serde(default, rename_all = "kebab-case", deny_unknown_fields)] -pub struct WordCompletion { - pub enable: bool, - pub trigger_length: NonZeroU8, -} - -impl Default for WordCompletion { - fn default() -> Self { - Self { - enable: true, - trigger_length: NonZeroU8::new(7).unwrap(), - } - } -} - impl Default for Config { fn default() -> Self { Self { @@ -1072,7 +986,6 @@ impl Default for Config { auto_pairs: AutoPairConfig::default(), auto_completion: true, path_completion: true, - word_completion: WordCompletion::default(), auto_format: true, default_yank_register: '"', auto_save: AutoSave::default(), @@ -1082,7 +995,6 @@ impl Default for Config { completion_trigger_len: 2, auto_info: true, file_picker: FilePickerConfig::default(), - file_explorer: FileExplorerConfig::default(), statusline: StatusLineConfig::default(), cursor_shape: CursorShapeConfig::default(), true_color: false, @@ -1105,7 +1017,6 @@ impl Default for Config { workspace_lsp_roots: Vec::new(), default_line_ending: LineEndingConfig::default(), insert_final_newline: true, - atomic_save: true, trim_final_newlines: false, trim_trailing_whitespace: false, smart_tab: Some(SmartTabConfig::default()), @@ -1113,11 +1024,9 @@ impl Default for Config { indent_heuristic: IndentationHeuristic::default(), jump_label_alphabet: ('a'..='z').collect(), inline_diagnostics: InlineDiagnosticsConfig::default(), - end_of_line_diagnostics: DiagnosticFilter::Enable(Severity::Hint), + end_of_line_diagnostics: DiagnosticFilter::Disable, clipboard_provider: ClipboardProvider::default(), editor_config: true, - rainbow_brackets: false, - kitty_keyboard_protocol: Default::default(), } } } @@ -1170,7 +1079,8 @@ pub struct Editor { pub diagnostics: Diagnostics, pub diff_providers: DiffProviderRegistry, - pub debug_adapters: dap::registry::Registry, + pub debugger: Option<dap::Client>, + pub debugger_events: SelectAll<UnboundedReceiverStream<dap::Payload>>, pub breakpoints: HashMap<PathBuf, Vec<Breakpoint>>, pub syn_loader: Arc<ArcSwap<syntax::Loader>>, @@ -1228,7 +1138,7 @@ pub enum EditorEvent { DocumentSaved(DocumentSavedEventResult), ConfigEvent(ConfigEvent), LanguageServerMessage((LanguageServerId, Call)), - DebuggerEvent((DebugAdapterId, dap::Payload)), + DebuggerEvent(dap::Payload), IdleTimer, Redraw, } @@ -1315,7 +1225,8 @@ impl Editor { language_servers, diagnostics: Diagnostics::new(), diff_providers: DiffProviderRegistry::default(), - debug_adapters: dap::registry::Registry::new(), + debugger: None, + debugger_events: SelectAll::new(), breakpoints: HashMap::new(), syn_loader, theme_loader, @@ -1377,16 +1288,11 @@ impl Editor { /// Call if the config has changed to let the editor update all /// relevant members. - pub fn refresh_config(&mut self, old_config: &Config) { + pub fn refresh_config(&mut self) { let config = self.config(); self.auto_pairs = (&config.auto_pairs).into(); self.reset_idle_timer(); self._refresh(); - helix_event::dispatch(crate::events::ConfigDidChange { - editor: self, - old: old_config, - new: &config, - }) } pub fn clear_idle_timer(&mut self) { @@ -1527,11 +1433,7 @@ impl Editor { log::error!("failed to apply workspace edit: {err:?}") } } - - if old_path.exists() { - fs::rename(old_path, &new_path)?; - } - + fs::rename(old_path, &new_path)?; if let Some(doc) = self.document_by_path(old_path) { self.set_doc_path(doc.id(), &new_path); } @@ -1644,7 +1546,7 @@ impl Editor { doc.language_servers.iter().filter(|(name, doc_ls)| { language_servers .get(*name) - .is_none_or(|ls| ls.id() != doc_ls.id()) + .map_or(true, |ls| ls.id() != doc_ls.id()) }); for (_, language_server) in doc_language_servers_not_in_registry { @@ -1654,7 +1556,7 @@ impl Editor { let language_servers_not_in_doc = language_servers.iter().filter(|(name, ls)| { doc.language_servers .get(*name) - .is_none_or(|doc_ls| ls.id() != doc_ls.id()) + .map_or(true, |doc_ls| ls.id() != doc_ls.id()) }); for (_, language_server) in language_servers_not_in_doc { @@ -2044,29 +1946,28 @@ impl Editor { } pub fn focus(&mut self, view_id: ViewId) { - if self.tree.focus == view_id { - return; - } + let prev_id = std::mem::replace(&mut self.tree.focus, view_id); - // Reset mode to normal and ensure any pending changes are committed in the old document. - self.enter_normal_mode(); - let (view, doc) = current!(self); - doc.append_changes_to_history(view); - self.ensure_cursor_in_view(view_id); - // Update jumplist selections with new document changes. - for (view, _focused) in self.tree.views_mut() { + // if leaving the view: mode should reset and the cursor should be + // within view + if prev_id != view_id { + self.enter_normal_mode(); + self.ensure_cursor_in_view(view_id); + + // Update jumplist selections with new document changes. + for (view, _focused) in self.tree.views_mut() { + let doc = doc_mut!(self, &view.doc); + view.sync_changes(doc); + } + let view = view!(self, view_id); let doc = doc_mut!(self, &view.doc); - view.sync_changes(doc); + doc.mark_as_focused(); + let focus_lost = self.tree.get(prev_id).doc; + dispatch(DocumentFocusLost { + editor: self, + doc: focus_lost, + }); } - - let prev_id = std::mem::replace(&mut self.tree.focus, view_id); - doc_mut!(self).mark_as_focused(); - - let focus_lost = self.tree.get(prev_id).doc; - dispatch(DocumentFocusLost { - editor: self, - doc: focus_lost, - }); } pub fn focus_next(&mut self) { @@ -2245,7 +2146,7 @@ impl Editor { Some(message) = self.language_servers.incoming.next() => { return EditorEvent::LanguageServerMessage(message) } - Some(event) = self.debug_adapters.incoming.next() => { + Some(event) = self.debugger_events.next() => { return EditorEvent::DebuggerEvent(event) } @@ -2321,8 +2222,10 @@ impl Editor { } } - pub fn current_stack_frame(&self) -> Option<&dap::StackFrame> { - self.debug_adapters.current_stack_frame() + pub fn current_stack_frame(&self) -> Option<&StackFrame> { + self.debugger + .as_ref() + .and_then(|debugger| debugger.current_stack_frame()) } /// Returns the id of a view that this doc contains a selection for, |