Skip to content

Commit

Permalink
add case insensitive search
Browse files Browse the repository at this point in the history
  • Loading branch information
Kl4rry committed Nov 24, 2023
1 parent 5b7366b commit ea0ff53
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 19 deletions.
1 change: 1 addition & 0 deletions config/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ watch_recursive = true
watch_workspace = true
show_indent_rulers = true
always_prompt_on_exit = false
case_insensitive_search = true

[picker]
show_hidden = false
Expand Down
11 changes: 8 additions & 3 deletions src/ferrite_core/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1355,11 +1355,16 @@ impl Buffer {
start..end
}

pub fn start_search(&mut self, proxy: TuiEventLoopProxy, query: String) {
pub fn start_search(
&mut self,
proxy: TuiEventLoopProxy,
query: String,
case_insensitive: bool,
) {
if let Some(searcher) = &mut self.searcher {
searcher.update_query(query);
searcher.update_query(query, case_insensitive);
} else {
let searcher = BufferSearcher::new(proxy, query, self.rope.clone());
let searcher = BufferSearcher::new(proxy, query, self.rope.clone(), case_insensitive);
self.searcher = Some(searcher);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ferrite_core/buffer/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Buffer {
}

if let Some(searcher) = &mut self.searcher {
searcher.update_buffer(self.rope.clone());
searcher.update_buffer(self.rope.clone(), None);
}

Ok(respone)
Expand Down
47 changes: 35 additions & 12 deletions src/ferrite_core/buffer/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub struct SearchMatch {
}

enum QueryUpdate {
Rope(Rope),
Query(String),
Rope(Rope, Option<bool>),
Query(String, bool),
}

pub struct BufferSearcher {
Expand All @@ -27,10 +27,15 @@ pub struct BufferSearcher {
}

impl BufferSearcher {
pub fn new(proxy: TuiEventLoopProxy, query: String, rope: Rope) -> Self {
pub fn new(
proxy: TuiEventLoopProxy,
query: String,
rope: Rope,
case_insensitive: bool,
) -> Self {
let matches = Arc::new(Mutex::new(Vec::new()));
let (tx, rx) = mpsc::channel();
let _ = tx.send(QueryUpdate::Rope(rope.clone()));
let _ = tx.send(QueryUpdate::Rope(rope.clone(), Some(case_insensitive)));
let thread_rope = rope.clone();

let thread_matches = matches.clone();
Expand All @@ -39,26 +44,35 @@ impl BufferSearcher {
let matches = thread_matches;
let mut query = query;
let mut rope = thread_rope;
let mut case_insensitive = case_insensitive;

let mut match_buffer = Vec::new();

// TODO don't block on every update do batch reciving
while let Ok(update) = rx.recv() {
match update {
QueryUpdate::Rope(r) => rope = r,
QueryUpdate::Query(q) => query = q,
QueryUpdate::Rope(r, case) => {
if let Some(case) = case {
case_insensitive = case;
}
rope = r;
}
QueryUpdate::Query(q, case) => {
case_insensitive = case;
query = q;
}
}

let chars: Vec<_> = query.chars().collect();
let mut query_idx = 0;
let mut current_char = 1;

for ch in rope.chars() {
if ch == chars[query_idx] {
if compare_char(&ch, &chars[query_idx], case_insensitive) {
query_idx += 1;
} else {
query_idx = 0;
if ch == chars[query_idx] {
if compare_char(&ch, &chars[query_idx], case_insensitive) {
query_idx += 1;
}
}
Expand Down Expand Up @@ -112,17 +126,26 @@ impl BufferSearcher {
guard.get(self.match_index).copied()
}

pub fn update_query(&mut self, query: String) {
let _ = self.tx.send(QueryUpdate::Query(query));
pub fn update_query(&mut self, query: String, case_insensitive: bool) {
let _ = self.tx.send(QueryUpdate::Query(query, case_insensitive));
}

pub fn update_buffer(&mut self, rope: Rope) {
pub fn update_buffer(&mut self, rope: Rope, case_insensitive: Option<bool>) {
if !self.last_rope.is_instance(&rope) {
let _ = self.tx.send(QueryUpdate::Rope(rope));
let _ = self.tx.send(QueryUpdate::Rope(rope, case_insensitive));
}
}

pub fn get_matches(&self) -> Arc<Mutex<Vec<SearchMatch>>> {
self.matches.clone()
}
}

#[inline(always)]
pub fn compare_char(lhs: &char, rhs: &char, case_insensitive: bool) -> bool {
if case_insensitive {
lhs.to_ascii_lowercase() == rhs.to_ascii_lowercase()
} else {
lhs == rhs
}
}
2 changes: 1 addition & 1 deletion src/ferrite_core/buffer/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn write(
.create(true)
.truncate(true)
.write(true)
.open(&path)?,
.open(path)?,
);

let mut output_rope = RopeBuilder::new();
Expand Down
2 changes: 2 additions & 0 deletions src/ferrite_core/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub struct Config {
pub show_indent_rulers: bool,
#[serde(default = "get_false")]
pub always_prompt_on_exit: bool,
#[serde(default = "get_true")]
pub case_insensitive_search: bool,
#[serde(default)]
pub picker: PickerConfig,
#[serde(default)]
Expand Down
16 changes: 16 additions & 0 deletions src/ferrite_core/palette.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ impl CommandPalette {
};
}

pub fn update_prompt(&mut self, new_prompt: impl Into<String>) {
match &mut self.state {
PaletteState::Input { prompt, .. } => *prompt = new_prompt.into(),
PaletteState::Prompt { prompt, .. } => *prompt = new_prompt.into(),
_ => (),
}
}

pub fn set_prompt(
&mut self,
prompt: impl Into<String>,
Expand Down Expand Up @@ -141,6 +149,14 @@ impl CommandPalette {
pub fn state(&mut self) -> &mut PaletteState {
&mut self.state
}

pub fn mode(&self) -> Option<&str> {
if let PaletteState::Input { mode, .. } = &self.state {
Some(mode)
} else {
None
}
}
}

impl CommandPalette {
Expand Down
24 changes: 22 additions & 2 deletions src/tui_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,11 +425,17 @@ impl TuiApp {
self.file_finder = None;
self.buffer_finder = None;
self.palette.focus(
"search: ",
self.get_search_prompt(),
"search",
CompleterContext::new(&self.themes),
);
}
InputCommand::CaseInsensitive => {
self.config.case_insensitive_search = !self.config.case_insensitive_search;
if let Some("search") = self.palette.mode() {
self.palette.update_prompt(self.get_search_prompt());
}
}
InputCommand::Escape
if self.file_finder.is_some() | self.buffer_finder.is_some() =>
{
Expand Down Expand Up @@ -608,7 +614,11 @@ impl TuiApp {
}
}
"search" => {
self.buffers[self.current_buffer_id].start_search(self.proxy.clone(), content);
self.buffers[self.current_buffer_id].start_search(
self.proxy.clone(),
content,
self.config.case_insensitive_search,
);
self.palette.unfocus();
}
_ => (),
Expand Down Expand Up @@ -752,6 +762,16 @@ impl TuiApp {
None => self.buffers.insert(Buffer::new()),
}
}

pub fn get_search_prompt(&self) -> String {
let mut prompt = String::from("search");
if self.config.case_insensitive_search {
prompt += " (i): ";
} else {
prompt += ": ";
}
prompt
}
}

impl Drop for TuiApp {
Expand Down
6 changes: 6 additions & 0 deletions src/tui_app/keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub enum InputCommand {
RevertBuffer,
VerticalScroll(i64),
FileSearch,
CaseInsensitive,
NextMatch,
PrevMatch,
FocusPalette,
Expand Down Expand Up @@ -227,6 +228,11 @@ pub fn get_default_mappings() -> Vec<(Mapping, InputCommand, Exclusiveness)> {
InputCommand::FileSearch,
Exclusiveness::Exclusive,
),
(
Mapping::new(KeyCode::Char('i'), KeyModifiers::CONTROL),
InputCommand::CaseInsensitive,
Exclusiveness::Exclusive,
),
(
Mapping::new(KeyCode::Char('p'), KeyModifiers::ALT),
InputCommand::PrevMatch,
Expand Down

0 comments on commit ea0ff53

Please sign in to comment.