Skip to content

Commit

Permalink
Show messages for no search results.
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulJuliusMartinez committed Jan 30, 2022
1 parent 606bb96 commit 9a81088
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 22 deletions.
94 changes: 77 additions & 17 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::flatjson;
use crate::input::TuiEvent;
use crate::input::TuiEvent::{KeyEvent, MouseEvent, WinChEvent};
use crate::options::Opt;
use crate::screenwriter::{AnsiTTYWriter, ScreenWriter};
use crate::screenwriter::{AnsiTTYWriter, MessageSeverity, ScreenWriter};
use crate::search::{JumpDirection, SearchDirection, SearchState};
use crate::types::TTYDimensions;
use crate::viewer::{Action, JsonViewer};
Expand All @@ -21,6 +21,7 @@ pub struct App {
input_buffer: Vec<u8>,
input_filename: String,
search_state: SearchState,
message: Option<(String, MessageSeverity)>,
}

pub const MAX_BUFFER_SIZE: usize = 9;
Expand Down Expand Up @@ -54,6 +55,7 @@ impl App {
input_buffer: vec![],
input_filename,
search_state: SearchState::empty(),
message: None,
})
}

Expand All @@ -66,6 +68,7 @@ impl App {
&self.input_buffer,
&self.input_filename,
&self.search_state,
&self.message,
);

for event in input {
Expand Down Expand Up @@ -143,12 +146,12 @@ impl App {
Key::Char('n') => {
let count = self.parse_input_buffer_as_number();
jumped_to_search_match = true;
Some(self.jump_to_next_search_match(count))
self.jump_to_next_search_match(count)
}
Key::Char('N') => {
let count = self.parse_input_buffer_as_number();
jumped_to_search_match = true;
Some(self.jump_to_prev_search_match(count))
self.jump_to_prev_search_match(count)
}
Key::Char('.') => {
let count = self.parse_input_buffer_as_number();
Expand Down Expand Up @@ -215,23 +218,55 @@ impl App {
let search_term = self.screen_writer.get_command("/").unwrap();
self.initialize_freeform_search(SearchDirection::Forward, search_term);
jumped_to_search_match = true;
Some(self.jump_to_next_search_match(1))

if !self.search_state.any_matches() {
self.message = Some((
self.search_state.no_matches_message(),
MessageSeverity::Warn,
));
None
} else {
self.jump_to_next_search_match(1)
}
}
Key::Char('?') => {
let search_term = self.screen_writer.get_command("?").unwrap();
self.initialize_freeform_search(SearchDirection::Reverse, search_term);
jumped_to_search_match = true;
Some(self.jump_to_next_search_match(1))

if !self.search_state.any_matches() {
self.message = Some((
self.search_state.no_matches_message(),
MessageSeverity::Warn,
));
None
} else {
self.jump_to_next_search_match(1)
}
}
Key::Char('*') => {
self.initialize_object_key_search(SearchDirection::Forward);
jumped_to_search_match = true;
Some(self.jump_to_next_search_match(1))
if self.initialize_object_key_search(SearchDirection::Forward) {
jumped_to_search_match = true;
self.jump_to_next_search_match(1)
} else {
self.message = Some((
"Must be focused on Object key to use '*'".to_string(),
MessageSeverity::Warn,
));
None
}
}
Key::Char('#') => {
self.initialize_object_key_search(SearchDirection::Reverse);
jumped_to_search_match = true;
Some(self.jump_to_next_search_match(1))
if self.initialize_object_key_search(SearchDirection::Reverse) {
jumped_to_search_match = true;
self.jump_to_next_search_match(1)
} else {
self.message = Some((
"Must be focused on Object key to use '#'".to_string(),
MessageSeverity::Warn,
));
None
}
}
_ => {
print!("{}Got: {:?}\r", BELL, event);
Expand Down Expand Up @@ -293,7 +328,9 @@ impl App {
&self.input_buffer,
&self.input_filename,
&self.search_state,
&self.message,
);
self.message = None;
}
}

Expand Down Expand Up @@ -332,32 +369,55 @@ impl App {
SearchState::initialize_search(search_term, &self.viewer.flatjson.1, direction);
}

fn initialize_object_key_search(&mut self, direction: SearchDirection) {
fn initialize_object_key_search(&mut self, direction: SearchDirection) -> bool {
if let Some(key_range) = &self.viewer.flatjson[self.viewer.focused_row].key_range {
// Note key_range already includes quotes around key.
let needle = format!("{}: ", &self.viewer.flatjson.1[key_range.clone()]);
self.search_state =
SearchState::initialize_search(needle, &self.viewer.flatjson.1, direction);
true
} else {
panic!("Handle object key search initialized not on object key");
false
}
}

fn jump_to_next_search_match(&mut self, _jumps: usize) -> Action {
fn jump_to_next_search_match(&mut self, _jumps: usize) -> Option<Action> {
if !self.search_state.ever_searched {
self.message = Some(("Type / to search".to_string(), MessageSeverity::Info));
return None;
} else if !self.search_state.any_matches() {
self.message = Some((
self.search_state.no_matches_message(),
MessageSeverity::Warn,
));
return None;
}

let destination = self.search_state.jump_to_match(
self.viewer.focused_row,
&self.viewer.flatjson,
JumpDirection::Next,
);
Action::MoveTo(destination)
Some(Action::MoveTo(destination))
}

fn jump_to_prev_search_match(&mut self, _jumps: usize) -> Action {
fn jump_to_prev_search_match(&mut self, _jumps: usize) -> Option<Action> {
if !self.search_state.ever_searched {
self.message = Some(("Type / to search".to_string(), MessageSeverity::Info));
return None;
} else if !self.search_state.any_matches() {
self.message = Some((
self.search_state.no_matches_message(),
MessageSeverity::Warn,
));
return None;
}

let destination = self.search_state.jump_to_match(
self.viewer.focused_row,
&self.viewer.flatjson,
JumpDirection::Prev,
);
Action::MoveTo(destination)
Some(Action::MoveTo(destination))
}
}
34 changes: 31 additions & 3 deletions src/screenwriter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ pub struct ScreenWriter {
truncated_row_value_views: HashMap<Index, TruncatedStrView>,
}

pub enum MessageSeverity {
Info,
Warn,
Error,
}

impl MessageSeverity {
pub fn color(&self) -> Color {
match self {
MessageSeverity::Info => Color::White,
MessageSeverity::Warn => Color::Yellow,
MessageSeverity::Error => Color::Red,
}
}
}

const PATH_BASE: &'static str = "input";
const SPACE_BETWEEN_PATH_AND_FILENAME: isize = 3;

Expand All @@ -77,9 +93,10 @@ impl ScreenWriter {
input_buffer: &[u8],
input_filename: &str,
search_state: &SearchState,
message: &Option<(String, MessageSeverity)>,
) {
self.print_viewer(viewer, search_state);
self.print_status_bar(viewer, input_buffer, input_filename, search_state);
self.print_status_bar(viewer, input_buffer, input_filename, search_state, message);
}

pub fn print_viewer(&mut self, viewer: &JsonViewer, search_state: &SearchState) {
Expand All @@ -97,8 +114,15 @@ impl ScreenWriter {
input_buffer: &[u8],
input_filename: &str,
search_state: &SearchState,
message: &Option<(String, MessageSeverity)>,
) {
match self.print_status_bar_impl(viewer, input_buffer, input_filename, search_state) {
match self.print_status_bar_impl(
viewer,
input_buffer,
input_filename,
search_state,
message,
) {
Ok(_) => {}
Err(e) => {
eprintln!("Error while printing status bar: {}", e);
Expand Down Expand Up @@ -342,6 +366,7 @@ impl ScreenWriter {
input_buffer: &[u8],
input_filename: &str,
search_state: &SearchState,
message: &Option<(String, MessageSeverity)>,
) -> std::io::Result<()> {
self.tty_writer
.position_cursor(1, self.dimensions.height - 1)?;
Expand All @@ -360,7 +385,10 @@ impl ScreenWriter {
self.reset_style()?;
self.tty_writer.position_cursor(1, self.dimensions.height)?;

if let Some((match_num, just_wrapped)) = search_state.active_search_state() {
if let Some((contents, severity)) = message {
self.tty_writer.set_fg_color(severity.color())?;
write!(self.tty_writer, "{}", contents)?;
} else if let Some((match_num, just_wrapped)) = search_state.active_search_state() {
self.tty_writer
.write_char(search_state.direction.prompt_char())?;
write!(self.tty_writer, "{}", &search_state.search_term)?;
Expand Down
14 changes: 12 additions & 2 deletions src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct SearchState {
matches: Vec<Range<usize>>,

immediate_state: ImmediateSearchState,
pub ever_searched: bool,
}

pub enum ImmediateSearchState {
Expand All @@ -55,6 +56,7 @@ impl SearchState {
compiled_regex: Regex::new("").unwrap(),
matches: vec![],
immediate_state: ImmediateSearchState::NotSearching,
ever_searched: false,
}
}

Expand All @@ -72,6 +74,7 @@ impl SearchState {
compiled_regex: regex,
matches,
immediate_state: ImmediateSearchState::NotSearching,
ever_searched: true,
}
}

Expand All @@ -90,6 +93,14 @@ impl SearchState {
self.matches.len()
}

pub fn any_matches(&self) -> bool {
self.matches.len() > 0
}

pub fn no_matches_message(&self) -> String {
format!("Pattern not found: {}", self.search_term)
}

pub fn set_no_longer_actively_searching(&mut self) {
self.immediate_state = ImmediateSearchState::NotSearching;
}
Expand All @@ -101,8 +112,7 @@ impl SearchState {
jump_direction: JumpDirection,
) -> usize {
if self.matches.is_empty() {
eprintln!("NEED TO HANDLE NO MATCHES");
return 0;
panic!("Shouldn't call jump_to_match if no matches");
}

let true_direction = self.true_direction(jump_direction);
Expand Down

0 comments on commit 9a81088

Please sign in to comment.