Skip to content

Commit 24b2f11

Browse files
authored
Fix explore searching (#17289)
This closes #17285. The `explore` searching should now work again. I also fixed a bug with `e` and `t` and they should work better now too. ## Release notes summary - What our users need to know N/A ## Tasks after submitting N/A
1 parent c65c807 commit 24b2f11

File tree

2 files changed

+150
-29
lines changed

2 files changed

+150
-29
lines changed

crates/nu-explore/src/explore/pager/mod.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,24 @@ fn handle_general_key_events2<V>(
853853
}
854854
}
855855
}
856+
KeyCode::Char('N') => {
857+
if !search.search_results.is_empty() {
858+
if search.buf_cmd_input.is_empty() {
859+
search.buf_cmd_input.clone_from(&search.buf_cmd);
860+
}
861+
862+
if search.search_index == 0 {
863+
search.search_index = search.search_results.len() - 1;
864+
} else {
865+
search.search_index -= 1;
866+
}
867+
868+
let pos = search.search_results[search.search_index];
869+
if let Some(view) = view {
870+
view.show_data(pos);
871+
}
872+
}
873+
}
856874
_ => {}
857875
}
858876
}
@@ -882,6 +900,19 @@ fn search_input_key_event(
882900
buf.buf_cmd.clone_from(&buf.buf_cmd_input);
883901
buf.is_search_input = false;
884902

903+
if let Some(view) = view
904+
&& !buf.buf_cmd.is_empty()
905+
{
906+
let data = view.collect_data().into_iter().map(|(text, _)| text);
907+
buf.search_results = search_pattern(data, &buf.buf_cmd, buf.is_reversed);
908+
buf.search_index = 0;
909+
910+
if !buf.search_results.is_empty() {
911+
let pos = buf.search_results[buf.search_index];
912+
view.show_data(pos);
913+
}
914+
}
915+
885916
true
886917
}
887918
KeyCode::Backspace => {

crates/nu-explore/src/explore/views/record/mod.rs

Lines changed: 119 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use super::{
1616
};
1717
use anyhow::Result;
1818
use crossterm::event::{KeyCode, KeyEvent};
19-
use nu_color_config::StyleComputer;
19+
use nu_color_config::{StyleComputer, TextStyle};
2020
use nu_protocol::{
21-
Config, Value,
21+
Config, Record, Value,
2222
engine::{EngineState, Stack},
2323
};
2424
use ratatui::{layout::Rect, widgets::Block};
@@ -284,13 +284,111 @@ impl View for RecordView {
284284
}
285285
}
286286

287+
fn collect_data(&self) -> Vec<NuText> {
288+
let layer = self.get_top_layer();
289+
let mut texts = Vec::new();
290+
291+
// Add headers
292+
for name in &layer.column_names {
293+
texts.push((name.clone(), TextStyle::default()));
294+
}
295+
296+
// Add data
297+
for row in &layer.record_values {
298+
for value in row {
299+
let text = value.to_abbreviated_string(&Config::default());
300+
let text = strip_string(&text);
301+
texts.push((text, TextStyle::default()));
302+
}
303+
}
304+
305+
texts
306+
}
307+
308+
fn show_data(&mut self, pos: usize) -> bool {
309+
let layer = self.get_top_layer();
310+
let num_headers = layer.column_names.len();
311+
312+
if pos < num_headers {
313+
// Header
314+
let column = pos;
315+
let row = 0;
316+
self.get_top_layer_mut()
317+
.cursor
318+
.set_window_start_position(row, column);
319+
return true;
320+
} else {
321+
let data_pos = pos - num_headers;
322+
let mut i = 0;
323+
for (data_row, cells) in layer.record_values.iter().enumerate() {
324+
if data_pos >= i && data_pos < i + cells.len() {
325+
let column = data_pos - i;
326+
let row = data_row + 1; // +1 for header row
327+
self.get_top_layer_mut()
328+
.cursor
329+
.set_window_start_position(row, column);
330+
return true;
331+
}
332+
i += cells.len();
333+
}
334+
}
335+
336+
false
337+
}
338+
287339
fn update(&mut self, _info: &mut ViewInfo) -> bool {
288340
false
289341
}
290342

291343
fn exit(&mut self) -> Option<Value> {
292-
None
344+
Some(build_last_value(self))
345+
}
346+
}
347+
348+
fn build_last_value(v: &RecordView) -> Value {
349+
if v.mode == UIMode::Cursor {
350+
v.get_current_value().clone()
351+
} else if v.get_top_layer().count_rows() < 2 {
352+
build_table_as_record(v)
353+
} else {
354+
build_table_as_list(v)
355+
}
356+
}
357+
358+
fn build_table_as_list(v: &RecordView) -> Value {
359+
let layer = v.get_top_layer();
360+
361+
let vals = layer
362+
.record_values
363+
.iter()
364+
.map(|vals| {
365+
let record = layer
366+
.column_names
367+
.iter()
368+
.cloned()
369+
.zip(vals.iter().cloned())
370+
.collect();
371+
Value::record(record, NuSpan::unknown())
372+
})
373+
.collect();
374+
375+
Value::list(vals, NuSpan::unknown())
376+
}
377+
378+
fn build_table_as_record(v: &RecordView) -> Value {
379+
let layer = v.get_top_layer();
380+
381+
let mut record = Record::new();
382+
if let Some(row) = layer.record_values.first() {
383+
record = layer
384+
.column_names
385+
.iter()
386+
.cloned()
387+
.zip(row.iter().cloned())
388+
.collect();
293389
}
390+
391+
Value::record(record, NuSpan::unknown())
294392
}
295393

296394
fn get_element_info(
@@ -583,11 +681,7 @@ fn transpose_from(layer: &mut RecordLayer) {
583681
let count_rows = layer.record_values.len();
584682
let count_columns = layer.column_names.len();
585683

586-
if let Some(data) = &mut layer.record_text {
587-
pop_first_column(data);
588-
*data = _transpose_table(data, count_rows, count_columns - 1);
589-
}
590-
684+
// Extract the original column names from the first column
591685
let headers = pop_first_column(&mut layer.record_values);
592686
let headers = headers
593687
.into_iter()
@@ -601,40 +695,36 @@ fn transpose_from(layer: &mut RecordLayer) {
601695

602696
layer.record_values = data;
603697
layer.column_names = headers;
698+
// Invalidate the text cache so it gets regenerated with the new structure
699+
layer.record_text = None;
700+
}
701+
702+
fn pop_first_column<T>(values: &mut [Vec<T>]) -> Vec<T>
703+
where
704+
T: Default + Clone,
705+
{
706+
let mut data = vec![T::default(); values.len()];
707+
for (row, values) in values.iter_mut().enumerate() {
708+
data[row] = values.remove(0);
709+
}
710+
711+
data
604712
}
605713

606714
fn transpose_to(layer: &mut RecordLayer) {
607715
let count_rows = layer.record_values.len();
608716
let count_columns = layer.column_names.len();
609717

610-
if let Some(data) = &mut layer.record_text {
611-
*data = _transpose_table(data, count_rows, count_columns);
612-
for (column, column_name) in layer.column_names.iter().enumerate() {
613-
let value = (column_name.to_owned(), Default::default());
614-
data[column].insert(0, value);
615-
}
616-
}
617-
618718
let mut data = _transpose_table(&layer.record_values, count_rows, count_columns);
619719
for (column, column_name) in layer.column_names.iter().enumerate() {
620720
let value = Value::string(column_name, NuSpan::unknown());
621721
data[column].insert(0, value);
622722
}
623723

624724
layer.record_values = data;
625-
layer.column_names = (1..count_rows + 1 + 1).map(|i| i.to_string()).collect();
626-
}
627-
628-
fn pop_first_column<T>(values: &mut [Vec<T>]) -> Vec<T>
629-
where
630-
T: Default + Clone,
631-
{
632-
let mut data = vec![T::default(); values.len()];
633-
for (row, values) in values.iter_mut().enumerate() {
634-
data[row] = values.remove(0);
635-
}
636-
637-
data
725+
layer.column_names = (1..=count_rows + 1).map(|i| i.to_string()).collect();
726+
// Invalidate the text cache so it gets regenerated with the new structure
727+
layer.record_text = None;
638728
}
639729

640730
fn _transpose_table<T>(values: &[Vec<T>], count_rows: usize, count_columns: usize) -> Vec<Vec<T>>

0 commit comments

Comments
 (0)