Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--Cargo.lock15
-rw-r--r--helix-term/Cargo.toml15
-rw-r--r--helix-term/src/application.rs18
-rw-r--r--helix-term/src/args.rs37
-rw-r--r--helix-term/src/config.rs114
-rw-r--r--helix-term/src/keymap/macros.rs127
-rw-r--r--helix-term/src/lib.rs15
-rw-r--r--helix-view/Cargo.toml18
-rw-r--r--helix-view/src/args.rs36
-rw-r--r--helix-view/src/commands/dap.rs (renamed from helix-term/src/commands/dap.rs)15
-rw-r--r--helix-view/src/commands/lsp.rs (renamed from helix-term/src/commands/lsp.rs)6
-rw-r--r--helix-view/src/commands/mod.rs (renamed from helix-term/src/commands.rs)41
-rw-r--r--helix-view/src/commands/typed.rs (renamed from helix-term/src/commands/typed.rs)2
-rw-r--r--helix-view/src/keymap.rs (renamed from helix-term/src/keymap.rs)110
-rw-r--r--helix-view/src/keymap/default.rs (renamed from helix-term/src/keymap/default.rs)0
-rw-r--r--helix-view/src/keymap/macros.rs60
-rw-r--r--helix-view/src/lib.rs16
-rw-r--r--helix-view/src/macros.rs66
-rw-r--r--helix-view/src/ui/completion.rs (renamed from helix-term/src/ui/completion.rs)6
-rw-r--r--helix-view/src/ui/editor.rs (renamed from helix-term/src/ui/editor.rs)12
-rw-r--r--helix-view/src/ui/markdown.rs (renamed from helix-term/src/ui/markdown.rs)4
-rw-r--r--helix-view/src/ui/menu.rs (renamed from helix-term/src/ui/menu.rs)4
-rw-r--r--helix-view/src/ui/mod.rs (renamed from helix-term/src/ui/mod.rs)14
-rw-r--r--helix-view/src/ui/overlay.rs (renamed from helix-term/src/ui/overlay.rs)4
-rw-r--r--helix-view/src/ui/picker.rs (renamed from helix-term/src/ui/picker.rs)4
-rw-r--r--helix-view/src/ui/popup.rs (renamed from helix-term/src/ui/popup.rs)4
-rw-r--r--helix-view/src/ui/prompt.rs (renamed from helix-term/src/ui/prompt.rs)14
-rw-r--r--helix-view/src/ui/spinner.rs (renamed from helix-term/src/ui/spinner.rs)0
-rw-r--r--helix-view/src/ui/text.rs (renamed from helix-term/src/ui/text.rs)5
29 files changed, 398 insertions, 384 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c2fc9982..0e9ba36a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -878,24 +878,17 @@ dependencies = [
"anyhow",
"arc-swap",
"chrono",
- "content_inspector",
"crossterm",
"fern",
"futures-util",
- "fuzzy-matcher",
- "grep-regex",
- "grep-searcher",
"helix-core",
"helix-dap",
"helix-loader",
"helix-lsp",
"helix-tui",
"helix-view",
- "ignore",
"log",
"once_cell",
- "pulldown-cmark",
- "retain_mut",
"ropey",
"serde",
"serde_json",
@@ -942,15 +935,23 @@ dependencies = [
"bitflags",
"chardetng",
"clipboard-win",
+ "content_inspector",
"crossterm",
"futures-util",
+ "fuzzy-matcher",
+ "grep-regex",
+ "grep-searcher",
"helix-core",
"helix-dap",
"helix-graphics",
+ "helix-loader",
"helix-lsp",
"helix-tui",
+ "ignore",
"log",
"once_cell",
+ "pulldown-cmark",
+ "retain_mut",
"serde",
"serde_json",
"slotmap",
diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml
index cd4973ad..7b38d42d 100644
--- a/helix-term/Cargo.toml
+++ b/helix-term/Cargo.toml
@@ -51,27 +51,12 @@ fern = "0.6"
chrono = { version = "0.4", default-features = false, features = ["clock"] }
log = "0.4"
-# File picker
-fuzzy-matcher = "0.3"
-ignore = "0.4"
-# markdown doc rendering
-pulldown-cmark = { version = "0.9", default-features = false }
-# file type detection
-content_inspector = "0.2.4"
-
# config
toml = "0.5"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
-# ripgrep for global search
-grep-regex = "0.1.9"
-grep-searcher = "0.1.8"
-
-# Remove once retain_mut lands in stable rust
-retain_mut = "0.1.7"
-
[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 cc5ff0c4..8f7a4ae6 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -5,17 +5,19 @@ use helix_core::{
};
#[cfg(feature = "lsp")]
-use crate::commands::apply_workspace_edit;
-#[cfg(feature = "lsp")]
use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
#[cfg(feature = "lsp")]
+use helix_view::commands::apply_workspace_edit;
+#[cfg(feature = "lsp")]
use serde_json::json;
-use helix_view::{align_view, editor::ConfigEvent, graphics::Rect, theme, Align, Editor};
+use helix_view::{
+ align_view, editor::ConfigEvent, graphics::Rect, theme, true_color, Align, Editor,
+};
+
+use crate::{args::Args, config::Config};
-use crate::{
- args::Args,
- config::Config,
+use helix_view::{
keymap::Keymaps,
ui::{self, overlay::overlayed},
};
@@ -96,7 +98,7 @@ impl Application {
&helix_loader::runtime_dir(),
));
- let true_color = config.editor.true_color || crate::true_color();
+ let true_color = config.editor.true_color || true_color();
let theme = config
.theme
.as_ref()
@@ -358,7 +360,7 @@ impl Application {
}
fn true_color(&self) -> bool {
- self.config.load().editor.true_color || crate::true_color()
+ self.config.load().editor.true_color || true_color()
}
#[cfg(windows)]
diff --git a/helix-term/src/args.rs b/helix-term/src/args.rs
index b99c7d1a..e1f0d9a7 100644
--- a/helix-term/src/args.rs
+++ b/helix-term/src/args.rs
@@ -1,6 +1,7 @@
use anyhow::Result;
use helix_core::Position;
-use std::path::{Path, PathBuf};
+use helix_view::args::parse_file;
+use std::path::PathBuf;
#[derive(Default)]
pub struct Args {
@@ -65,37 +66,3 @@ impl Args {
Ok(args)
}
}
-
-/// Parse arg into [`PathBuf`] and position.
-pub(crate) fn parse_file(s: &str) -> (PathBuf, Position) {
- let def = || (PathBuf::from(s), Position::default());
- if Path::new(s).exists() {
- return def();
- }
- split_path_row_col(s)
- .or_else(|| split_path_row(s))
- .unwrap_or_else(def)
-}
-
-/// Split file.rs:10:2 into [`PathBuf`], row and col.
-///
-/// Does not validate if file.rs is a file or directory.
-fn split_path_row_col(s: &str) -> Option<(PathBuf, Position)> {
- let mut s = s.rsplitn(3, ':');
- let col: usize = s.next()?.parse().ok()?;
- let row: usize = s.next()?.parse().ok()?;
- let path = s.next()?.into();
- let pos = Position::new(row.saturating_sub(1), col.saturating_sub(1));
- Some((path, pos))
-}
-
-/// Split file.rs:10 into [`PathBuf`] and row.
-///
-/// Does not validate if file.rs is a file or directory.
-fn split_path_row(s: &str) -> Option<(PathBuf, Position)> {
- let (path, row) = s.rsplit_once(':')?;
- let row: usize = row.parse().ok()?;
- let path = path.into();
- let pos = Position::new(row.saturating_sub(1), 0);
- Some((path, pos))
-}
diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs
index 4407a882..27dcb971 100644
--- a/helix-term/src/config.rs
+++ b/helix-term/src/config.rs
@@ -1,5 +1,5 @@
-use crate::keymap::{default::default, merge_keys, Keymap};
use helix_view::document::Mode;
+use helix_view::keymap::{default::default, Keymap};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt::Display;
@@ -27,6 +27,15 @@ impl Default for Config {
}
}
+/// Merge default config keys with user overwritten keys for custom user config.
+pub fn merge_keys(mut config: Config) -> Config {
+ let mut delta = std::mem::replace(&mut config.keys, default());
+ for (mode, keys) in &mut config.keys {
+ keys.merge(delta.remove(mode).unwrap_or_default())
+ }
+ config
+}
+
#[derive(Debug)]
pub enum ConfigLoadError {
BadConfig(TomlError),
@@ -63,10 +72,9 @@ mod tests {
#[test]
fn parsing_keymaps_config_file() {
- use crate::keymap;
- use crate::keymap::Keymap;
use helix_core::hashmap;
use helix_view::document::Mode;
+ use helix_view::keymap::{self, Keymap};
let sample_keymaps = r#"
[keys.insert]
@@ -104,4 +112,104 @@ mod tests {
let default_keys = Config::default().keys;
assert_eq!(default_keys, default());
}
+
+ use arc_swap::access::Constant;
+ use helix_core::hashmap;
+
+ #[test]
+ fn merge_partial_keys() {
+ let config = Config {
+ keys: hashmap! {
+ Mode::Normal => Keymap::new(
+ keymap!({ "Normal mode"
+ "i" => normal_mode,
+ "无" => insert_mode,
+ "z" => jump_backward,
+ "g" => { "Merge into goto mode"
+ "$" => goto_line_end,
+ "g" => delete_char_forward,
+ },
+ })
+ )
+ },
+ ..Default::default()
+ };
+ let mut merged_config = merge_keys(config.clone());
+ assert_ne!(config, merged_config);
+
+ let mut keymap = Keymaps::new(Box::new(Constant(merged_config.keys.clone())));
+ assert_eq!(
+ keymap.get(Mode::Normal, key!('i')),
+ KeymapResult::Matched(MappableCommand::normal_mode),
+ "Leaf should replace leaf"
+ );
+ assert_eq!(
+ keymap.get(Mode::Normal, key!('无')),
+ KeymapResult::Matched(MappableCommand::insert_mode),
+ "New leaf should be present in merged keymap"
+ );
+ // Assumes that z is a node in the default keymap
+ assert_eq!(
+ keymap.get(Mode::Normal, key!('z')),
+ KeymapResult::Matched(MappableCommand::jump_backward),
+ "Leaf should replace node"
+ );
+
+ let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap();
+ // Assumes that `g` is a node in default keymap
+ assert_eq!(
+ keymap.root().search(&[key!('g'), key!('$')]).unwrap(),
+ &KeyTrie::Leaf(MappableCommand::goto_line_end),
+ "Leaf should be present in merged subnode"
+ );
+ // Assumes that `gg` is in default keymap
+ assert_eq!(
+ keymap.root().search(&[key!('g'), key!('g')]).unwrap(),
+ &KeyTrie::Leaf(MappableCommand::delete_char_forward),
+ "Leaf should replace old leaf in merged subnode"
+ );
+ // Assumes that `ge` is in default keymap
+ assert_eq!(
+ keymap.root().search(&[key!('g'), key!('e')]).unwrap(),
+ &KeyTrie::Leaf(MappableCommand::goto_last_line),
+ "Old leaves in subnode should be present in merged node"
+ );
+
+ assert!(merged_config.keys.get(&Mode::Normal).unwrap().len() > 1);
+ assert!(merged_config.keys.get(&Mode::Insert).unwrap().len() > 0);
+ }
+
+ #[test]
+ fn order_should_be_set() {
+ let config = Config {
+ keys: hashmap! {
+ Mode::Normal => Keymap::new(
+ keymap!({ "Normal mode"
+ "space" => { ""
+ "s" => { ""
+ "v" => vsplit,
+ "c" => hsplit,
+ },
+ },
+ })
+ )
+ },
+ ..Default::default()
+ };
+ let mut merged_config = merge_keys(config.clone());
+ assert_ne!(config, merged_config);
+ let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap();
+ // Make sure mapping works
+ assert_eq!(
+ keymap
+ .root()
+ .search(&[key!(' '), key!('s'), key!('v')])
+ .unwrap(),
+ &KeyTrie::Leaf(MappableCommand::vsplit),
+ "Leaf should be present in merged subnode"
+ );
+ // Make sure an order was set during merge
+ let node = keymap.root().search(&[helix_view::key!(' ')]).unwrap();
+ assert!(!node.node().unwrap().order().is_empty())
+ }
}
diff --git a/helix-term/src/keymap/macros.rs b/helix-term/src/keymap/macros.rs
deleted file mode 100644
index c4a1bfbb..00000000
--- a/helix-term/src/keymap/macros.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-#[macro_export]
-macro_rules! key {
- ($key:ident) => {
- ::helix_view::input::KeyEvent {
- code: ::helix_view::keyboard::KeyCode::$key,
- modifiers: ::helix_view::keyboard::KeyModifiers::NONE,
- }
- };
- ($($ch:tt)*) => {
- ::helix_view::input::KeyEvent {
- code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
- modifiers: ::helix_view::keyboard::KeyModifiers::NONE,
- }
- };
-}
-
-#[macro_export]
-macro_rules! shift {
- ($key:ident) => {
- ::helix_view::input::KeyEvent {
- code: ::helix_view::keyboard::KeyCode::$key,
- modifiers: ::helix_view::keyboard::KeyModifiers::SHIFT,
- }
- };
- ($($ch:tt)*) => {
- ::helix_view::input::KeyEvent {
- code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
- modifiers: ::helix_view::keyboard::KeyModifiers::SHIFT,
- }
- };
-}
-
-#[macro_export]
-macro_rules! ctrl {
- ($key:ident) => {
- ::helix_view::input::KeyEvent {
- code: ::helix_view::keyboard::KeyCode::$key,
- modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL,
- }
- };
- ($($ch:tt)*) => {
- ::helix_view::input::KeyEvent {
- code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
- modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL,
- }
- };
-}
-
-#[macro_export]
-macro_rules! alt {
- ($key:ident) => {
- ::helix_view::input::KeyEvent {
- code: ::helix_view::keyboard::KeyCode::$key,
- modifiers: ::helix_view::keyboard::KeyModifiers::ALT,
- }
- };
- ($($ch:tt)*) => {
- ::helix_view::input::KeyEvent {
- code: ::helix_view::keyboard::KeyCode::Char($($ch)*),
- modifiers: ::helix_view::keyboard::KeyModifiers::ALT,
- }
- };
-}
-
-/// Macro for defining the root of a `Keymap` object. Example:
-///
-/// ```
-/// # use helix_core::hashmap;
-/// # use helix_term::keymap;
-/// # use helix_term::keymap::Keymap;
-/// let normal_mode = keymap!({ "Normal mode"
-/// "i" => insert_mode,
-/// "g" => { "Goto"
-/// "g" => goto_file_start,
-/// "e" => goto_file_end,
-/// },
-/// "j" | "down" => move_line_down,
-/// });
-/// let keymap = Keymap::new(normal_mode);
-/// ```
-#[macro_export]
-macro_rules! keymap {
- (@trie $cmd:ident) => {
- $crate::keymap::KeyTrie::Leaf($crate::commands::MappableCommand::$cmd)
- };
-
- (@trie
- { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
- ) => {
- keymap!({ $label $(sticky=$sticky)? $($($key)|+ => $value,)+ })
- };
-
- (@trie [$($cmd:ident),* $(,)?]) => {
- $crate::keymap::KeyTrie::Sequence(vec![$($crate::commands::Command::$cmd),*])
- };
-
- (
- { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
- ) => {
- // modified from the hashmap! macro
- {
- let _cap = hashmap!(@count $($($key),+),*);
- let mut _map = ::std::collections::HashMap::with_capacity(_cap);
- let mut _order = ::std::vec::Vec::with_capacity(_cap);
- $(
- $(
- let _key = $key.parse::<::helix_view::input::KeyEvent>().unwrap();
- let _duplicate = _map.insert(
- _key,
- keymap!(@trie $value)
- );
- assert!(_duplicate.is_none(), "Duplicate key found: {:?}", _duplicate.unwrap());
- _order.push(_key);
- )+
- )*
- let mut _node = $crate::keymap::KeyTrieNode::new($label, _map, _order);
- $( _node.is_sticky = $sticky; )?
- $crate::keymap::KeyTrie::Node(_node)
- }
- };
-}
-
-pub use alt;
-pub use ctrl;
-pub use key;
-pub use keymap;
-pub use shift;
diff --git a/helix-term/src/lib.rs b/helix-term/src/lib.rs
index d7f52785..891653f7 100644
--- a/helix-term/src/lib.rs
+++ b/helix-term/src/lib.rs
@@ -3,20 +3,5 @@ extern crate helix_view;
pub mod application;
pub mod args;
-pub mod commands;
pub mod config;
pub mod health;
-pub mod keymap;
-pub mod ui;
-pub use keymap::macros::*;
-
-#[cfg(not(windows))]
-fn true_color() -> bool {
- std::env::var("COLORTERM")
- .map(|v| matches!(v.as_str(), "truecolor" | "24bit"))
- .unwrap_or(false)
-}
-#[cfg(windows)]
-fn true_color() -> bool {
- true
-}
diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml
index 15478e81..69df49cc 100644
--- a/helix-view/Cargo.toml
+++ b/helix-view/Cargo.toml
@@ -23,6 +23,7 @@ helix-core = { version = "0.6", path = "../helix-core" }
helix-graphics = { version = "0.6", path = "../helix-graphics" }
helix-lsp = { version = "0.6", path = "../helix-lsp", optional = true }
helix-dap = { version = "0.6", path = "../helix-dap", optional = true }
+helix-loader = { version = "0.6", path = "../helix-loader" }
tokio-stream = { version = "0.1", optional = true }
tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"], optional = true }
@@ -46,6 +47,23 @@ serde_json = "1.0"
toml = "0.5"
log = "~0.4"
+# Command dependencies
+
+# File picker
+fuzzy-matcher = "0.3"
+ignore = "0.4"
+# markdown doc rendering
+pulldown-cmark = { version = "0.9", default-features = false }
+# file type detection
+content_inspector = "0.2.4"
+
+# ripgrep for global search
+grep-regex = "0.1.9"
+grep-searcher = "0.1.8"
+
+# Remove once retain_mut lands in stable rust
+retain_mut = "0.1.7"
+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
which = "4.2"
diff --git a/helix-view/src/args.rs b/helix-view/src/args.rs
new file mode 100644
index 00000000..4a69e12d
--- /dev/null
+++ b/helix-view/src/args.rs
@@ -0,0 +1,36 @@
+use helix_core::Position;
+use std::path::{Path, PathBuf};
+
+/// Parse arg into [`PathBuf`] and position.
+pub fn parse_file(s: &str) -> (PathBuf, Position) {
+ let def = || (PathBuf::from(s), Position::default());
+ if Path::new(s).exists() {
+ return def();
+ }
+ split_path_row_col(s)
+ .or_else(|| split_path_row(s))
+ .unwrap_or_else(def)
+}
+
+/// Split file.rs:10:2 into [`PathBuf`], row and col.
+///
+/// Does not validate if file.rs is a file or directory.
+fn split_path_row_col(s: &str) -> Option<(PathBuf, Position)> {
+ let mut s = s.rsplitn(3, ':');
+ let col: usize = s.next()?.parse().ok()?;
+ let row: usize = s.next()?.parse().ok()?;
+ let path = s.next()?.into();
+ let pos = Position::new(row.saturating_sub(1), col.saturating_sub(1));
+ Some((path, pos))
+}
+
+/// Split file.rs:10 into [`PathBuf`] and row.
+///
+/// Does not validate if file.rs is a file or directory.
+fn split_path_row(s: &str) -> Option<(PathBuf, Position)> {
+ let (path, row) = s.rsplit_once(':')?;
+ let row: usize = row.parse().ok()?;
+ let path = path.into();
+ let pos = Position::new(row.saturating_sub(1), 0);
+ Some((path, pos))
+}
diff --git a/helix-term/src/commands/dap.rs b/helix-view/src/commands/dap.rs
index 2ef8b5ff..65e4fa06 100644
--- a/helix-term/src/commands/dap.rs
+++ b/helix-view/src/commands/dap.rs
@@ -1,13 +1,13 @@
use super::{Context, Editor};
+use crate::editor::Breakpoint;
use crate::ui::{self, overlay::overlayed, FilePicker, Picker, Popup, Prompt, PromptEvent, Text};
-use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion};
-use helix_dap::{self as dap, Client};
-use helix_lsp::block_on;
-use helix_view::editor::Breakpoint;
-use helix_view::{
+use crate::{
compositor::{self, Compositor},
job::{Callback, Jobs},
};
+use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion};
+use helix_dap::{self as dap, Client};
+use helix_lsp::block_on;
use serde_json::{to_value, Value};
use tokio_stream::wrappers::UnboundedReceiverStream;
@@ -18,7 +18,8 @@ use std::path::PathBuf;
use anyhow::{anyhow, bail};
-use helix_view::handlers::dap::{breakpoints_changed, jump_to_stack_frame, select_thread_id};
+use crate::debugger;
+use crate::handlers::dap::{breakpoints_changed, jump_to_stack_frame, select_thread_id};
fn thread_picker(
cx: &mut Context,
@@ -474,7 +475,7 @@ pub fn dap_variables(cx: &mut Context) {
let text_style = theme.get("ui.text.focus");
for scope in scopes.iter() {
- // use helix_view::graphics::Style;
+ // use crate::graphics::Style;
use tui::text::{Span, Spans};
let response = block_on(debugger.variables(scope.variables_reference));
diff --git a/helix-term/src/commands/lsp.rs b/helix-view/src/commands/lsp.rs
index 3fafb03e..816a653f 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-view/src/commands/lsp.rs
@@ -7,10 +7,10 @@ use helix_lsp::{
use super::{align_view, push_jump, Align, Context, Editor};
use helix_core::Selection;
-use helix_view::editor::Action;
+use crate::editor::Action;
use crate::ui::{self, overlay::overlayed, FileLocation, FilePicker, Popup, PromptEvent};
-use helix_view::compositor::{self, Compositor};
+use crate::compositor::{self, Compositor};
use std::borrow::Cow;
@@ -255,7 +255,7 @@ pub fn code_action(cx: &mut Context) {
});
picker.move_down(); // pre-select the first item
- let popup = Popup::new("code-action", picker).margin(helix_view::graphics::Margin {
+ let popup = Popup::new("code-action", picker).margin(crate::graphics::Margin {
vertical: 1,
horizontal: 1,
});
diff --git a/helix-term/src/commands.rs b/helix-view/src/commands/mod.rs
index ac226676..5aa29ba4 100644
--- a/helix-term/src/commands.rs
+++ b/helix-view/src/commands/mod.rs
@@ -10,6 +10,16 @@ pub use dap::*;
pub use lsp::*;
pub use typed::*;
+use crate::{
+ clipboard::ClipboardType,
+ document::{Mode, SCRATCH_BUFFER_NAME},
+ editor::{Action, Motion},
+ info::Info,
+ input::KeyEvent,
+ keyboard::KeyCode,
+ view::View,
+ Document, DocumentId, Editor, ViewId,
+};
use helix_core::{
comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes,
history::UndoKind,
@@ -29,18 +39,8 @@ use helix_core::{
LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril,
Transaction,
};
-use helix_view::{
- clipboard::ClipboardType,
- document::{Mode, SCRATCH_BUFFER_NAME},
- editor::{Action, Motion},
- info::Info,
- input::KeyEvent,
- keyboard::KeyCode,
- view::View,
- Document, DocumentId, Editor, ViewId,
-};
-use helix_view::{
+use crate::{
compositor::{self, Component, Compositor},
job::{self, Job, Jobs},
};
@@ -56,8 +56,13 @@ use crate::{
};
use futures_util::{FutureExt, StreamExt};
-use std::{collections::HashMap, fmt, future::Future};
-use std::{collections::HashSet, num::NonZeroUsize};
+
+use std::{
+ collections::{HashMap, HashSet},
+ fmt,
+ future::Future,
+ num::NonZeroUsize,
+};
use std::{
borrow::Cow,
@@ -77,7 +82,7 @@ pub struct Context<'a> {
pub count: Option<NonZeroUsize>,
pub editor: &'a mut Editor,
- pub callback: Option<helix_view::compositor::Callback>,
+ pub callback: Option<crate::compositor::Callback>,
pub on_next_key_callback: Option<Box<dyn FnOnce(&mut Context, KeyEvent)>>,
pub jobs: &'a mut Jobs,
}
@@ -126,7 +131,7 @@ impl<'a> Context<'a> {
}
}
-use helix_view::{align_view, Align};
+use crate::{align_view, Align};
/// A MappableCommand is either a static command like "jump_view_up" or a Typable command like
/// :format. It causes a side-effect on the state (usually by creating and applying a transaction).
@@ -4397,8 +4402,8 @@ fn shell_prompt(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBeha
}
fn suspend(_cx: &mut Context) {
- #[cfg(not(windows))]
- signal_hook::low_level::raise(signal_hook::consts::signal::SIGTSTP).unwrap();
+ // #[cfg(not(windows))]
+ // signal_hook::low_level::raise(signal_hook::consts::signal::SIGTSTP).unwrap();
}
fn add_newline_above(cx: &mut Context) {
@@ -4557,7 +4562,7 @@ fn record_macro(cx: &mut Context) {
fn replay_macro(cx: &mut Context) {
let reg = cx.register.unwrap_or('@');
let keys: Vec<KeyEvent> = if let Some([keys_str]) = cx.editor.registers.read(reg) {
- match helix_view::input::parse_macro(keys_str) {
+ match crate::input::parse_macro(keys_str) {
Ok(keys) => keys,
Err(err) => {
cx.editor.set_error(format!("Invalid macro: {}", err));
diff --git a/helix-term/src/commands/typed.rs b/helix-view/src/commands/typed.rs
index d3e185c7..aeed6a56 100644
--- a/helix-term/src/commands/typed.rs
+++ b/helix-view/src/commands/typed.rs
@@ -1,6 +1,6 @@
use super::*;
-use helix_view::editor::{Action, ConfigEvent};
+use crate::editor::{Action, ConfigEvent};
use ui::completers::{self, Completer};
#[derive(Clone)]
diff --git a/helix-term/src/keymap.rs b/helix-view/src/keymap.rs
index 37dbc5de..c9f26e17 100644
--- a/helix-term/src/keymap.rs
+++ b/helix-view/src/keymap.rs
@@ -2,12 +2,11 @@ pub mod default;
pub mod macros;
pub use crate::commands::MappableCommand;
-use crate::config::Config;
+use crate::{document::Mode, info::Info, input::KeyEvent};
use arc_swap::{
access::{DynAccess, DynGuard},
ArcSwap,
};
-use helix_view::{document::Mode, info::Info, input::KeyEvent};
use serde::Deserialize;
use std::{
borrow::Cow,
@@ -361,20 +360,10 @@ impl Default for Keymaps {
}
}
-/// Merge default config keys with user overwritten keys for custom user config.
-pub fn merge_keys(mut config: Config) -> Config {
- let mut delta = std::mem::replace(&mut config.keys, default());
- for (mode, keys) in &mut config.keys {
- keys.merge(delta.remove(mode).unwrap_or_default())
- }
- config
-}
-
#[cfg(test)]
mod tests {
use super::macros::keymap;
use super::*;
- use arc_swap::access::Constant;
use helix_core::hashmap;
#[test]
@@ -393,103 +382,6 @@ mod tests {
}
#[test]
- fn merge_partial_keys() {
- let config = Config {
- keys: hashmap! {
- Mode::Normal => Keymap::new(
- keymap!({ "Normal mode"
- "i" => normal_mode,
- "无" => insert_mode,
- "z" => jump_backward,
- "g" => { "Merge into goto mode"
- "$" => goto_line_end,
- "g" => delete_char_forward,
- },
- })
- )
- },
- ..Default::default()
- };
- let mut merged_config = merge_keys(config.clone());
- assert_ne!(config, merged_config);
-
- let mut keymap = Keymaps::new(Box::new(Constant(merged_config.keys.clone())));
- assert_eq!(
- keymap.get(Mode::Normal, key!('i')),
- KeymapResult::Matched(MappableCommand::normal_mode),
- "Leaf should replace leaf"
- );
- assert_eq!(
- keymap.get(Mode::Normal, key!('无')),
- KeymapResult::Matched(MappableCommand::insert_mode),
- "New leaf should be present in merged keymap"
- );
- // Assumes that z is a node in the default keymap
- assert_eq!(
- keymap.get(Mode::Normal, key!('z')),
- KeymapResult::Matched(MappableCommand::jump_backward),
- "Leaf should replace node"
- );
-
- let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap();
- // Assumes that `g` is a node in default keymap
- assert_eq!(
- keymap.root().search(&[key!('g'), key!('$')]).unwrap(),
- &KeyTrie::Leaf(MappableCommand::goto_line_end),
- "Leaf should be present in merged subnode"
- );
- // Assumes that `gg` is in default keymap
- assert_eq!(
- keymap.root().search(&[key!('g'), key!('g')]).unwrap(),
- &KeyTrie::Leaf(MappableCommand::delete_char_forward),
- "Leaf should replace old leaf in merged subnode"
- );
- // Assumes that `ge` is in default keymap
- assert_eq!(
- keymap.root().search(&[key!('g'), key!('e')]).unwrap(),
- &KeyTrie::Leaf(MappableCommand::goto_last_line),
- "Old leaves in subnode should be present in merged node"
- );
-
- assert!(merged_config.keys.get(&Mode::Normal).unwrap().len() > 1);
- assert!(merged_config.keys.get(&Mode::Insert).unwrap().len() > 0);
- }
-
- #[test]
- fn order_should_be_set() {
- let config = Config {
- keys: hashmap! {
- Mode::Normal => Keymap::new(
- keymap!({ "Normal mode"
- "space" => { ""
- "s" => { ""
- "v" => vsplit,
- "c" => hsplit,
- },
- },
- })
- )
- },
- ..Default::default()
- };
- let mut merged_config = merge_keys(config.clone());
- assert_ne!(config, merged_config);
- let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap();
- // Make sure mapping works
- assert_eq!(
- keymap
- .root()
- .search(&[key!(' '), key!('s'), key!('v')])
- .unwrap(),
- &KeyTrie::Leaf(MappableCommand::vsplit),
- "Leaf should be present in merged subnode"
- );
- // Make sure an order was set during merge
- let node = keymap.root().search(&[crate::key!(' ')]).unwrap();
- assert!(!node.node().unwrap().order().is_empty())
- }
-
- #[test]
fn aliased_modes_are_same_in_default_keymap() {
let keymaps = Keymaps::default().map();
let root = keymaps.get(&Mode::Normal).unwrap().root();
diff --git a/helix-term/src/keymap/default.rs b/helix-view/src/keymap/default.rs
index a1037beb..a1037beb 100644
--- a/helix-term/src/keymap/default.rs
+++ b/helix-view/src/keymap/default.rs
diff --git a/helix-view/src/keymap/macros.rs b/helix-view/src/keymap/macros.rs
new file mode 100644
index 00000000..1f6e2aa7
--- /dev/null
+++ b/helix-view/src/keymap/macros.rs
@@ -0,0 +1,60 @@
+/// Macro for defining the root of a `Keymap` object. Example:
+///
+/// ```
+/// # use helix_core::hashmap;
+/// # use helix_term::keymap;
+/// # use helix_term::keymap::Keymap;
+/// let normal_mode = keymap!({ "Normal mode"
+/// "i" => insert_mode,
+/// "g" => { "Goto"
+/// "g" => goto_file_start,
+/// "e" => goto_file_end,
+/// },
+/// "j" | "down" => move_line_down,
+/// });
+/// let keymap = Keymap::new(normal_mode);
+/// ```
+#[macro_export]
+macro_rules! keymap {
+ (@trie $cmd:ident) => {
+ $crate::keymap::KeyTrie::Leaf($crate::commands::MappableCommand::$cmd)
+ };
+
+ (@trie
+ { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
+ ) => {
+ keymap!({ $label $(sticky=$sticky)? $($($key)|+ => $value,)+ })
+ };
+
+ (@trie [$($cmd:ident),* $(,)?]) => {
+ $crate::keymap::KeyTrie::Sequence(vec![$($crate::commands::Command::$cmd),*])
+ };
+
+ (
+ { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ }
+ ) => {
+ // modified from the hashmap! macro
+ {
+ let _cap = hashmap!(@count $($($key),+),*);
+ let mut _map = ::std::collections::HashMap::with_capacity(_cap);
+ let mut _order = ::std::vec::Vec::with_capacity(_cap);
+ $(
+ $(
+ let _key = $key.parse::<$crate::input::KeyEvent>().unwrap();
+ let _duplicate = _map.insert(
+ _key,
+ keymap!(@trie $value)
+ );
+ assert!(_duplicate.is_none(), "Duplicate key found: {:?}", _duplicate.unwrap());
+ _order.push(_key);
+ )+
+ )*
+ let mut _node = $crate::keymap::KeyTrieNode::new($label, _map, _order);
+ $( _node.is_sticky = $sticky; )?
+ $crate::keymap::KeyTrie::Node(_node)
+ }
+ };
+}
+
+pub use crate::{alt, ctrl, key, shift};
+pub use keymap;
diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs
index b8519650..5ba31853 100644
--- a/helix-view/src/lib.rs
+++ b/helix-view/src/lib.rs
@@ -1,17 +1,22 @@
#[macro_use]
pub mod macros;
+pub mod args;
pub mod backend {
#[cfg(feature = "term")]
pub mod term;
}
pub mod clipboard;
+pub mod commands;
pub mod compositor;
pub mod document;
pub mod editor;
+pub mod ui;
pub use helix_graphics as graphics;
pub mod gutter;
pub mod job;
+pub mod keymap;
+pub use keymap::macros::*;
pub mod handlers {
#[cfg(feature = "dap")]
pub mod dap;
@@ -47,6 +52,17 @@ slotmap::new_key_type! {
pub struct ViewId;
}
+#[cfg(not(windows))]
+pub fn true_color() -> bool {
+ std::env::var("COLORTERM")
+ .map(|v| matches!(v.as_str(), "truecolor" | "24bit"))
+ .unwrap_or(false)
+}
+#[cfg(windows)]
+pub fn true_color() -> bool {
+ true
+}
+
pub enum Align {
Top,
Center,
diff --git a/helix-view/src/macros.rs b/helix-view/src/macros.rs
index 04f8df94..f939d129 100644
--- a/helix-view/src/macros.rs
+++ b/helix-view/src/macros.rs
@@ -61,3 +61,69 @@ macro_rules! doc {
$crate::current_ref!($editor).1
}};
}
+
+// Keymap macros
+
+#[macro_export]
+macro_rules! key {
+ ($key:ident) => {
+ $crate::input::KeyEvent {
+ code: $crate::keyboard::KeyCode::$key,
+ modifiers: $crate::keyboard::KeyModifiers::NONE,
+ }
+ };
+ ($($ch:tt)*) => {
+ $crate::input::KeyEvent {
+ code: $crate::keyboard::KeyCode::Char($($ch)*),
+ modifiers: $crate::keyboard::KeyModifiers::NONE,
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! shift {
+ ($key:ident) => {
+ $crate::input::KeyEvent {
+ code: $crate::keyboard::KeyCode::$key,
+ modifiers: $crate::keyboard::KeyModifiers::SHIFT,
+ }
+ };
+ ($($ch:tt)*) => {
+ $crate::input::KeyEvent {
+ code: $crate::keyboard::KeyCode::Char($($ch)*),
+ modifiers: $crate::keyboard::KeyModifiers::SHIFT,
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! ctrl {
+ ($key:ident) => {
+ $crate::input::KeyEvent {
+ code: $crate::keyboard::KeyCode::$key,
+ modifiers: $crate::keyboard::KeyModifiers::CONTROL,
+ }
+ };
+ ($($ch:tt)*) => {
+ $crate::input::KeyEvent {
+ code: $crate::keyboard::KeyCode::Char($($ch)*),
+ modifiers: $crate::keyboard::KeyModifiers::CONTROL,
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! alt {
+ ($key:ident) => {
+ $crate::input::KeyEvent {
+ code: $crate::keyboard::KeyCode::$key,
+ modifiers: $crate::keyboard::KeyModifiers::ALT,
+ }
+ };
+ ($($ch:tt)*) => {
+ $crate::input::KeyEvent {
+ code: $crate::keyboard::KeyCode::Char($($ch)*),
+ modifiers: $crate::keyboard::KeyModifiers::ALT,
+ }
+ };
+}
diff --git a/helix-term/src/ui/completion.rs b/helix-view/src/ui/completion.rs
index b144a78b..64ef686e 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-view/src/ui/completion.rs
@@ -1,10 +1,10 @@
-use helix_view::compositor::{Component, Context, Event, EventResult, RenderContext};
-use helix_view::editor::CompleteAction;
+use crate::compositor::{Component, Context, Event, EventResult, RenderContext};
+use crate::editor::CompleteAction;
use std::borrow::Cow;
use helix_core::{Change, Transaction};
-use helix_view::{
+use crate::{
graphics::Rect,
input::{KeyCode, KeyEvent},
Document, Editor,
diff --git a/helix-term/src/ui/editor.rs b/helix-view/src/ui/editor.rs
index e6f4c109..8d479337 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-view/src/ui/editor.rs
@@ -4,7 +4,7 @@ use crate::{
ui::{Completion, ProgressSpinners},
};
-use helix_view::compositor::{Component, Context, Event, EventResult, RenderContext};
+use crate::compositor::{Component, Context, Event, EventResult, RenderContext};
use helix_core::{
coords_at_pos, encoding,
@@ -17,7 +17,7 @@ use helix_core::{
unicode::width::UnicodeWidthStr,
LineEnding, Position, Range, Selection, Transaction,
};
-use helix_view::{
+use crate::{
document::{Mode, SCRATCH_BUFFER_NAME},
editor::{CompleteAction, CursorShapeConfig},
graphics::{CursorKind, Modifier, Rect, Style},
@@ -928,7 +928,7 @@ impl EditorView {
editor.clear_idle_timer(); // don't retrigger
}
- pub fn handle_idle_timeout(&mut self, cx: &mut helix_view::compositor::Context) -> EventResult {
+ pub fn handle_idle_timeout(&mut self, cx: &mut crate::compositor::Context) -> EventResult {
if self.completion.is_some()
|| !cx.editor.config().auto_completion
|| doc!(cx.editor).mode != Mode::Insert
@@ -1163,7 +1163,7 @@ impl Component for EditorView {
fn handle_event(
&mut self,
event: Event,
- context: &mut helix_view::compositor::Context,
+ context: &mut crate::compositor::Context,
) -> EventResult {
let mut cx = commands::Context {
editor: context.editor,
@@ -1314,7 +1314,7 @@ impl Component for EditorView {
// render status msg
if let Some((status_msg, severity)) = &cx.editor.status_msg {
status_msg_width = status_msg.width();
- use helix_view::editor::Severity;
+ use crate::editor::Severity;
let style = if *severity == Severity::Error {
cx.editor.theme.get("error")
} else {
@@ -1361,7 +1361,7 @@ impl Component for EditorView {
if let Some((reg, _)) = cx.editor.macro_recording {
let disp = format!("[{}]", reg);
let style = style
- .fg(helix_view::graphics::Color::Yellow)
+ .fg(crate::graphics::Color::Yellow)
.add_modifier(Modifier::BOLD);
cx.surface.set_string(
area.x + area.width.saturating_sub(3),
diff --git a/helix-term/src/ui/markdown.rs b/helix-view/src/ui/markdown.rs
index 6ed08dd9..def84477 100644
--- a/helix-term/src/ui/markdown.rs
+++ b/helix-view/src/ui/markdown.rs
@@ -1,4 +1,4 @@
-use helix_view::compositor::{Component, RenderContext};
+use crate::compositor::{Component, RenderContext};
use tui::text::{Span, Spans, Text};
use std::sync::Arc;
@@ -9,7 +9,7 @@ use helix_core::{
syntax::{self, HighlightEvent, Syntax},
Rope,
};
-use helix_view::{
+use crate::{
graphics::{Margin, Rect, Style},
Theme,
};
diff --git a/helix-term/src/ui/menu.rs b/helix-view/src/ui/menu.rs
index 8bc97d50..de370e0d 100644
--- a/helix-term/src/ui/menu.rs
+++ b/helix-view/src/ui/menu.rs
@@ -1,5 +1,5 @@
use crate::{ctrl, key, shift};
-use helix_view::compositor::{
+use crate::compositor::{
Callback, Component, Compositor, Context, Event, EventResult, RenderContext,
};
use tui::widgets::Table;
@@ -9,7 +9,7 @@ pub use tui::widgets::{Cell, Row};
use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
use fuzzy_matcher::FuzzyMatcher;
-use helix_view::{graphics::Rect, Editor};
+use crate::{graphics::Rect, Editor};
use tui::layout::Constraint;
pub trait Item {
diff --git a/helix-term/src/ui/mod.rs b/helix-view/src/ui/mod.rs
index 7f7df202..0105175e 100644
--- a/helix-term/src/ui/mod.rs
+++ b/helix-view/src/ui/mod.rs
@@ -19,9 +19,9 @@ pub use prompt::{Prompt, PromptEvent};
pub use spinner::{ProgressSpinners, Spinner};
pub use text::Text;
+use crate::{Document, Editor, View};
use helix_core::regex::Regex;
use helix_core::regex::RegexBuilder;
-use helix_view::{Document, Editor, View};
use std::path::PathBuf;
@@ -30,7 +30,7 @@ pub fn prompt(
prompt: std::borrow::Cow<'static, str>,
history_register: Option<char>,
completion_fn: impl FnMut(&Editor, &str) -> Vec<prompt::Completion> + 'static,
- callback_fn: impl FnMut(&mut helix_view::compositor::Context, &str, PromptEvent) + 'static,
+ callback_fn: impl FnMut(&mut crate::compositor::Context, &str, PromptEvent) + 'static,
) {
let mut prompt = Prompt::new(prompt, history_register, completion_fn, callback_fn);
// Calculate initial completion
@@ -55,7 +55,7 @@ pub fn regex_prompt(
prompt,
history_register,
completion_fn,
- move |cx: &mut helix_view::compositor::Context, input: &str, event: PromptEvent| {
+ move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| {
match event {
PromptEvent::Abort => {
let (view, doc) = current!(cx.editor);
@@ -111,7 +111,7 @@ pub fn regex_prompt(
cx.push_layer(Box::new(prompt));
}
-pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePicker<PathBuf> {
+pub fn file_picker(root: PathBuf, config: &crate::editor::Config) -> FilePicker<PathBuf> {
use ignore::{types::TypesBuilder, WalkBuilder};
use std::time::Instant;
@@ -188,12 +188,12 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
}
pub mod completers {
+ use crate::document::SCRATCH_BUFFER_NAME;
+ use crate::theme;
use crate::ui::prompt::Completion;
+ use crate::{editor::Config, Editor};
use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
use fuzzy_matcher::FuzzyMatcher;
- use helix_view::document::SCRATCH_BUFFER_NAME;
- use helix_view::theme;
- use helix_view::{editor::Config, Editor};
use once_cell::sync::Lazy;
use std::borrow::Cow;
use std::cmp::Reverse;
diff --git a/helix-term/src/ui/overlay.rs b/helix-view/src/ui/overlay.rs
index c0e52654..c7e153d1 100644
--- a/helix-term/src/ui/overlay.rs
+++ b/helix-view/src/ui/overlay.rs
@@ -1,10 +1,10 @@
use helix_core::Position;
-use helix_view::{
+use crate::{
graphics::{CursorKind, Rect},
Editor,
};
-use helix_view::compositor::{Component, Context, Event, EventResult, RenderContext};
+use crate::compositor::{Component, Context, Event, EventResult, RenderContext};
/// Contains a component placed in the center of the parent component
pub struct Overlay<T> {
diff --git a/helix-term/src/ui/picker.rs b/helix-view/src/ui/picker.rs
index c7381c99..2fbacab3 100644
--- a/helix-term/src/ui/picker.rs
+++ b/helix-view/src/ui/picker.rs
@@ -2,7 +2,7 @@ use crate::{
ctrl, key, shift,
ui::{self, EditorView},
};
-use helix_view::compositor::{Component, Compositor, Context, Event, EventResult, RenderContext};
+use crate::compositor::{Component, Compositor, Context, Event, EventResult, RenderContext};
use tui::widgets::{Block, BorderType, Borders};
use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
@@ -20,7 +20,7 @@ use std::{
use crate::ui::{Prompt, PromptEvent};
use helix_core::{movement::Direction, Position};
-use helix_view::{
+use crate::{
editor::Action,
graphics::{Color, CursorKind, Margin, Modifier, Rect, Style},
Document, Editor,
diff --git a/helix-term/src/ui/popup.rs b/helix-view/src/ui/popup.rs
index c58146e5..c8de7e74 100644
--- a/helix-term/src/ui/popup.rs
+++ b/helix-view/src/ui/popup.rs
@@ -1,8 +1,8 @@
use crate::{ctrl, key};
-use helix_view::compositor::{Callback, Component, Context, Event, EventResult, RenderContext};
+use crate::compositor::{Callback, Component, Context, Event, EventResult, RenderContext};
use helix_core::Position;
-use helix_view::{
+use crate::{
graphics::{Margin, Rect},
Editor,
};
diff --git a/helix-term/src/ui/prompt.rs b/helix-view/src/ui/prompt.rs
index 1b85758e..183d5de4 100644
--- a/helix-term/src/ui/prompt.rs
+++ b/helix-view/src/ui/prompt.rs
@@ -1,17 +1,17 @@
-use helix_view::compositor::{Component, Compositor, Context, Event, EventResult, RenderContext};
+use crate::compositor::{Component, Compositor, Context, Event, EventResult, RenderContext};
+use crate::input::KeyEvent;
+use crate::keyboard::KeyCode;
use crate::{alt, ctrl, key, shift, ui};
-use helix_view::input::KeyEvent;
-use helix_view::keyboard::KeyCode;
use std::{borrow::Cow, ops::RangeFrom};
use tui::widgets::{Block, Borders, Widget};
-use helix_core::{
- unicode::segmentation::GraphemeCursor, unicode::width::UnicodeWidthStr, Position,
-};
-use helix_view::{
+use crate::{
graphics::{CursorKind, Margin, Rect},
Editor,
};
+use helix_core::{
+ unicode::segmentation::GraphemeCursor, unicode::width::UnicodeWidthStr, Position,
+};
pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
diff --git a/helix-term/src/ui/spinner.rs b/helix-view/src/ui/spinner.rs
index 68965469..68965469 100644
--- a/helix-term/src/ui/spinner.rs
+++ b/helix-view/src/ui/spinner.rs
diff --git a/helix-term/src/ui/text.rs b/helix-view/src/ui/text.rs
index 4097deb5..224aa230 100644
--- a/helix-term/src/ui/text.rs
+++ b/helix-view/src/ui/text.rs
@@ -1,6 +1,5 @@
-use helix_view::compositor::{Component, RenderContext};
-
-use helix_view::graphics::Rect;
+use crate::compositor::{Component, RenderContext};
+use crate::graphics::Rect;
pub struct Text {
pub(crate) contents: tui::text::Text<'static>,