Number and search result highlighting

This commit is contained in:
Timothy Warren 2019-09-04 11:20:57 -04:00
parent be4a866a0c
commit 7c6c06e10f
1 changed files with 85 additions and 17 deletions

View File

@ -13,11 +13,19 @@ use self::EditorKey::*;
const KILO_TAB_STOP: usize = 4;
const KILO_QUIT_TIMES: u8 = 3;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Highlight {
Normal,
Number,
SearchMatch,
}
/// A representation of a line in the editor
#[derive(Debug, Default)]
pub struct EditorRow {
chars: String,
render: String,
highlight: Vec<Highlight>,
}
impl EditorRow {
@ -137,7 +145,14 @@ impl Editor {
let mut br = BufReader::with_capacity(5, stdin);
let mut first_read = [0; 1];
br.read_exact(&mut first_read);
match br.read_exact(&mut first_read) {
Ok(_) => (),
Err(e) => {
if e.kind() != io::ErrorKind::UnexpectedEof {
panic!(e);
}
}
}
let first_str = String::from_utf8(first_read.to_vec());
if first_str.is_err() {
return None;
@ -164,7 +179,14 @@ impl Editor {
// Match escape sequence
// --------------------------------------------------------------------
let mut seq = [0; 4];
br.read_exact(&mut seq);
match br.read_exact(&mut seq) {
Ok(_) => (),
Err(e) => {
if e.kind() != io::ErrorKind::UnexpectedEof {
panic!(e);
}
}
}
let seq_str = String::from_utf8(seq.to_vec());
// On error, just continue the input loop
@ -279,6 +301,31 @@ impl Editor {
}
}
// ------------------------------------------------------------------------
// Syntax Highlighting
// ------------------------------------------------------------------------
fn update_syntax(&mut self, index: usize) {
let row = &mut self.rows[index];
row.highlight = vec![Highlight::Normal; row.render.len()];
for (x, ch) in row.render.char_indices() {
if ch.is_ascii_digit() {
row.highlight[x] = Highlight::Number;
}
}
}
fn syntax_to_color(&self, syntax_type: Highlight) -> i32 {
use Highlight::*;
match syntax_type {
Normal => 37,
Number => 31, // Red
SearchMatch => 34, // Blue
}
}
// ------------------------------------------------------------------------
// Input
// ------------------------------------------------------------------------
@ -505,6 +552,10 @@ impl Editor {
self.output_buffer.push_str(str);
}
fn append_out_char(&mut self, ch: char) {
self.output_buffer.push(ch);
}
fn scroll(&mut self) {
self.render_x = 0;
if self.cursor_y < self.rows.len() {
@ -556,15 +607,27 @@ impl Editor {
self.append_out("~");
}
} else {
let mut len = self.rows[file_row].render.len() - self.col_offset;
if len > self.screen_cols {
len = self.screen_cols;
}
let output = self.rows[file_row].render.clone();
// let mut output = self.rows[file_row].render.clone();
// output.truncate(len);
self.append_out(&output[self.col_offset..len]);
let mut current_color: i32 = -1;
for (x, ch) in output.char_indices() {
if self.rows[file_row].highlight[x] == Highlight::Normal {
if current_color != -1 {
self.append_out("\x1b[39m");
current_color = -1;
}
self.append_out_char(ch);
} else {
let color = self.syntax_to_color(self.rows[file_row].highlight[x]);
if color != current_color {
current_color = color;
let code = format!("\x1b[{}m", color);
self.append_out(&code);
}
self.append_out_char(ch);
}
}
self.append_out("\x1b[39m");
}
self.append_out("\x1b[K");
@ -672,9 +735,8 @@ impl Editor {
fn row_cx_to_rx(&mut self, index: usize, cx: usize) -> usize {
let mut rx: usize = 0;
let mut i: usize = 0;
let row = &mut self.rows[index];
for char in row.chars.chars() {
for char in self.rows[index].chars.chars() {
if char == '\t' {
rx += (KILO_TAB_STOP - 1) - (rx % KILO_TAB_STOP);
} else {
@ -694,9 +756,8 @@ impl Editor {
fn row_rx_to_cx(&mut self, index: usize, rx: usize) -> usize {
let mut current_rx: usize = 0;
let mut cx: usize = 0;
let row = &mut self.rows[index];
for char in row.chars.chars() {
for char in self.rows[index].chars.chars() {
if char == '\t' {
current_rx += (KILO_TAB_STOP - 1) - (current_rx % KILO_TAB_STOP);
} else {
@ -721,6 +782,8 @@ impl Editor {
// Cheat at rendering tabs as spaces
let str = str.replace('\t', " ");
row.render = str;
self.update_syntax(index);
}
fn insert_row(&mut self, at: usize, row: &str) {
@ -938,8 +1001,7 @@ impl Editor {
current = 0;
}
let row = &self.rows[current as usize];
match row.render.find(query) {
match self.rows[current as usize].render.find(query) {
None => (),
Some(start) => {
self.search_last_match = current;
@ -947,6 +1009,12 @@ impl Editor {
self.cursor_x = self.row_rx_to_cx(x, start);
self.row_offset = self.rows.len();
// Highlight matching search result
let len = start + query.len();
for x in start..len {
self.rows[current as usize].highlight[x] = Highlight::SearchMatch;
}
break;
}
}
@ -959,7 +1027,7 @@ impl Editor {
let saved_coloff = self.col_offset;
let saved_rowoff = self.row_offset;
let query = self.prompt("Search (ESC to cancel):", Some(&mut Self::find_callback));
let query = self.prompt("Search (Use ESC/Arrows/Enter):", Some(&mut Self::find_callback));
if query.is_empty() {
self.cursor_x = saved_cx;