Number and search result highlighting
This commit is contained in:
parent
be4a866a0c
commit
7c6c06e10f
102
src/editor.rs
102
src/editor.rs
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user