aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src')
-rw-r--r--helix-term/src/commands.rs56
-rw-r--r--helix-term/src/ui/mod.rs33
2 files changed, 46 insertions, 43 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 51a1ede9..fdad31a8 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -3,6 +3,7 @@ pub(crate) mod lsp;
pub(crate) mod typed;
pub use dap::*;
+use helix_stdx::rope::{self, RopeSliceExt};
use helix_vcs::Hunk;
pub use lsp::*;
use tui::widgets::Row;
@@ -19,7 +20,7 @@ use helix_core::{
match_brackets,
movement::{self, move_vertically_visual, Direction},
object, pos_at_coords,
- regex::{self, Regex, RegexBuilder},
+ regex::{self, Regex},
search::{self, CharMatcher},
selection, shellwords, surround,
syntax::LanguageServerFeature,
@@ -1907,11 +1908,7 @@ fn split_selection(cx: &mut Context) {
fn split_selection_on_newline(cx: &mut Context) {
let (view, doc) = current!(cx.editor);
let text = doc.text().slice(..);
- // only compile the regex once
- #[allow(clippy::trivial_regex)]
- static REGEX: Lazy<Regex> =
- Lazy::new(|| Regex::new(r"\r\n|[\n\r\u{000B}\u{000C}\u{0085}\u{2028}\u{2029}]").unwrap());
- let selection = selection::split_on_matches(text, doc.selection(view.id), &REGEX);
+ let selection = selection::split_on_newline(text, doc.selection(view.id));
doc.set_selection(view.id, selection);
}
@@ -1930,8 +1927,7 @@ fn merge_consecutive_selections(cx: &mut Context) {
#[allow(clippy::too_many_arguments)]
fn search_impl(
editor: &mut Editor,
- contents: &str,
- regex: &Regex,
+ regex: &rope::Regex,
movement: Movement,
direction: Direction,
scrolloff: usize,
@@ -1959,23 +1955,20 @@ fn search_impl(
// do a reverse search and wraparound to the end, we don't need to search
// the text before the current cursor position for matches, but by slicing
// it out, we need to add it back to the position of the selection.
- let mut offset = 0;
+ let doc = doc!(editor).text().slice(..);
// use find_at to find the next match after the cursor, loop around the end
// Careful, `Regex` uses `bytes` as offsets, not character indices!
let mut mat = match direction {
- Direction::Forward => regex.find_at(contents, start),
- Direction::Backward => regex.find_iter(&contents[..start]).last(),
+ Direction::Forward => regex.find(doc.regex_input_at_bytes(start..)),
+ Direction::Backward => regex.find_iter(doc.regex_input_at_bytes(..start)).last(),
};
if mat.is_none() {
if wrap_around {
mat = match direction {
- Direction::Forward => regex.find(contents),
- Direction::Backward => {
- offset = start;
- regex.find_iter(&contents[start..]).last()
- }
+ Direction::Forward => regex.find(doc.regex_input()),
+ Direction::Backward => regex.find_iter(doc.regex_input_at_bytes(start..)).last(),
};
}
if show_warnings {
@@ -1992,8 +1985,8 @@ fn search_impl(
let selection = doc.selection(view.id);
if let Some(mat) = mat {
- let start = text.byte_to_char(mat.start() + offset);
- let end = text.byte_to_char(mat.end() + offset);
+ let start = text.byte_to_char(mat.start());
+ let end = text.byte_to_char(mat.end());
if end == 0 {
// skip empty matches that don't make sense
@@ -2037,13 +2030,7 @@ fn searcher(cx: &mut Context, direction: Direction) {
let scrolloff = config.scrolloff;
let wrap_around = config.search.wrap_around;
- let doc = doc!(cx.editor);
-
// TODO: could probably share with select_on_matches?
-
- // HAXX: sadly we can't avoid allocating a single string for the whole buffer since we can't
- // feed chunks into the regex yet
- let contents = doc.text().slice(..).to_string();
let completions = search_completions(cx, Some(reg));
ui::regex_prompt(
@@ -2065,7 +2052,6 @@ fn searcher(cx: &mut Context, direction: Direction) {
}
search_impl(
cx.editor,
- &contents,
&regex,
Movement::Move,
direction,
@@ -2085,8 +2071,6 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir
let config = cx.editor.config();
let scrolloff = config.scrolloff;
if let Some(query) = cx.editor.registers.first(register, cx.editor) {
- let doc = doc!(cx.editor);
- let contents = doc.text().slice(..).to_string();
let search_config = &config.search;
let case_insensitive = if search_config.smart_case {
!query.chars().any(char::is_uppercase)
@@ -2094,15 +2078,17 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir
false
};
let wrap_around = search_config.wrap_around;
- if let Ok(regex) = RegexBuilder::new(&query)
- .case_insensitive(case_insensitive)
- .multi_line(true)
- .build()
+ if let Ok(regex) = rope::RegexBuilder::new()
+ .syntax(
+ rope::Config::new()
+ .case_insensitive(case_insensitive)
+ .multi_line(true),
+ )
+ .build(&query)
{
for _ in 0..count {
search_impl(
cx.editor,
- &contents,
&regex,
movement,
direction,
@@ -2239,7 +2225,7 @@ fn global_search(cx: &mut Context) {
let reg = cx.register.unwrap_or('/');
let completions = search_completions(cx, Some(reg));
- ui::regex_prompt(
+ ui::raw_regex_prompt(
cx,
"global-search:".into(),
Some(reg),
@@ -2250,7 +2236,7 @@ fn global_search(cx: &mut Context) {
.map(|comp| (0.., std::borrow::Cow::Owned(comp.clone())))
.collect()
},
- move |cx, regex, event| {
+ move |cx, _, input, event| {
if event != PromptEvent::Validate {
return;
}
@@ -2265,7 +2251,7 @@ fn global_search(cx: &mut Context) {
if let Ok(matcher) = RegexMatcherBuilder::new()
.case_smart(smart_case)
- .build(regex.as_str())
+ .build(input)
{
let search_root = helix_stdx::env::current_working_dir();
if !search_root.exists() {
diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs
index 0873116c..a4b148af 100644
--- a/helix-term/src/ui/mod.rs
+++ b/helix-term/src/ui/mod.rs
@@ -18,6 +18,7 @@ use crate::filter_picker_entry;
use crate::job::{self, Callback};
pub use completion::{Completion, CompletionItem};
pub use editor::EditorView;
+use helix_stdx::rope;
pub use markdown::Markdown;
pub use menu::Menu;
pub use picker::{DynamicPicker, FileLocation, Picker};
@@ -26,8 +27,6 @@ pub use prompt::{Prompt, PromptEvent};
pub use spinner::{ProgressSpinners, Spinner};
pub use text::Text;
-use helix_core::regex::Regex;
-use helix_core::regex::RegexBuilder;
use helix_view::Editor;
use std::path::PathBuf;
@@ -63,7 +62,22 @@ pub fn regex_prompt(
prompt: std::borrow::Cow<'static, str>,
history_register: Option<char>,
completion_fn: impl FnMut(&Editor, &str) -> Vec<prompt::Completion> + 'static,
- fun: impl Fn(&mut crate::compositor::Context, Regex, PromptEvent) + 'static,
+ fun: impl Fn(&mut crate::compositor::Context, rope::Regex, PromptEvent) + 'static,
+) {
+ raw_regex_prompt(
+ cx,
+ prompt,
+ history_register,
+ completion_fn,
+ move |cx, regex, _, event| fun(cx, regex, event),
+ );
+}
+pub fn raw_regex_prompt(
+ cx: &mut crate::commands::Context,
+ prompt: std::borrow::Cow<'static, str>,
+ history_register: Option<char>,
+ completion_fn: impl FnMut(&Editor, &str) -> Vec<prompt::Completion> + 'static,
+ fun: impl Fn(&mut crate::compositor::Context, rope::Regex, &str, PromptEvent) + 'static,
) {
let (view, doc) = current!(cx.editor);
let doc_id = view.doc;
@@ -94,10 +108,13 @@ pub fn regex_prompt(
false
};
- match RegexBuilder::new(input)
- .case_insensitive(case_insensitive)
- .multi_line(true)
- .build()
+ match rope::RegexBuilder::new()
+ .syntax(
+ rope::Config::new()
+ .case_insensitive(case_insensitive)
+ .multi_line(true),
+ )
+ .build(input)
{
Ok(regex) => {
let (view, doc) = current!(cx.editor);
@@ -110,7 +127,7 @@ pub fn regex_prompt(
view.jumps.push((doc_id, snapshot.clone()));
}
- fun(cx, regex, event);
+ fun(cx, regex, input, event);
let (view, doc) = current!(cx.editor);
view.ensure_cursor_in_view(doc, config.scrolloff);