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_TAB_STOP: usize = 4;
|
||||||
const KILO_QUIT_TIMES: u8 = 3;
|
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
|
/// A representation of a line in the editor
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct EditorRow {
|
pub struct EditorRow {
|
||||||
chars: String,
|
chars: String,
|
||||||
render: String,
|
render: String,
|
||||||
|
highlight: Vec<Highlight>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditorRow {
|
impl EditorRow {
|
||||||
@ -137,7 +145,14 @@ impl Editor {
|
|||||||
let mut br = BufReader::with_capacity(5, stdin);
|
let mut br = BufReader::with_capacity(5, stdin);
|
||||||
|
|
||||||
let mut first_read = [0; 1];
|
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());
|
let first_str = String::from_utf8(first_read.to_vec());
|
||||||
if first_str.is_err() {
|
if first_str.is_err() {
|
||||||
return None;
|
return None;
|
||||||
@ -164,7 +179,14 @@ impl Editor {
|
|||||||
// Match escape sequence
|
// Match escape sequence
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
let mut seq = [0; 4];
|
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());
|
let seq_str = String::from_utf8(seq.to_vec());
|
||||||
|
|
||||||
// On error, just continue the input loop
|
// 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
|
// Input
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
@ -505,6 +552,10 @@ impl Editor {
|
|||||||
self.output_buffer.push_str(str);
|
self.output_buffer.push_str(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn append_out_char(&mut self, ch: char) {
|
||||||
|
self.output_buffer.push(ch);
|
||||||
|
}
|
||||||
|
|
||||||
fn scroll(&mut self) {
|
fn scroll(&mut self) {
|
||||||
self.render_x = 0;
|
self.render_x = 0;
|
||||||
if self.cursor_y < self.rows.len() {
|
if self.cursor_y < self.rows.len() {
|
||||||
@ -556,15 +607,27 @@ impl Editor {
|
|||||||
self.append_out("~");
|
self.append_out("~");
|
||||||
}
|
}
|
||||||
} else {
|
} 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 output = self.rows[file_row].render.clone();
|
||||||
// let mut output = self.rows[file_row].render.clone();
|
let mut current_color: i32 = -1;
|
||||||
// output.truncate(len);
|
|
||||||
self.append_out(&output[self.col_offset..len]);
|
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");
|
self.append_out("\x1b[K");
|
||||||
@ -672,9 +735,8 @@ impl Editor {
|
|||||||
fn row_cx_to_rx(&mut self, index: usize, cx: usize) -> usize {
|
fn row_cx_to_rx(&mut self, index: usize, cx: usize) -> usize {
|
||||||
let mut rx: usize = 0;
|
let mut rx: usize = 0;
|
||||||
let mut i: 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' {
|
if char == '\t' {
|
||||||
rx += (KILO_TAB_STOP - 1) - (rx % KILO_TAB_STOP);
|
rx += (KILO_TAB_STOP - 1) - (rx % KILO_TAB_STOP);
|
||||||
} else {
|
} else {
|
||||||
@ -694,9 +756,8 @@ impl Editor {
|
|||||||
fn row_rx_to_cx(&mut self, index: usize, rx: usize) -> usize {
|
fn row_rx_to_cx(&mut self, index: usize, rx: usize) -> usize {
|
||||||
let mut current_rx: usize = 0;
|
let mut current_rx: usize = 0;
|
||||||
let mut cx: 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' {
|
if char == '\t' {
|
||||||
current_rx += (KILO_TAB_STOP - 1) - (current_rx % KILO_TAB_STOP);
|
current_rx += (KILO_TAB_STOP - 1) - (current_rx % KILO_TAB_STOP);
|
||||||
} else {
|
} else {
|
||||||
@ -721,6 +782,8 @@ impl Editor {
|
|||||||
// Cheat at rendering tabs as spaces
|
// Cheat at rendering tabs as spaces
|
||||||
let str = str.replace('\t', " ");
|
let str = str.replace('\t', " ");
|
||||||
row.render = str;
|
row.render = str;
|
||||||
|
|
||||||
|
self.update_syntax(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_row(&mut self, at: usize, row: &str) {
|
fn insert_row(&mut self, at: usize, row: &str) {
|
||||||
@ -938,8 +1001,7 @@ impl Editor {
|
|||||||
current = 0;
|
current = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let row = &self.rows[current as usize];
|
match self.rows[current as usize].render.find(query) {
|
||||||
match row.render.find(query) {
|
|
||||||
None => (),
|
None => (),
|
||||||
Some(start) => {
|
Some(start) => {
|
||||||
self.search_last_match = current;
|
self.search_last_match = current;
|
||||||
@ -947,6 +1009,12 @@ impl Editor {
|
|||||||
self.cursor_x = self.row_rx_to_cx(x, start);
|
self.cursor_x = self.row_rx_to_cx(x, start);
|
||||||
self.row_offset = self.rows.len();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -959,7 +1027,7 @@ impl Editor {
|
|||||||
let saved_coloff = self.col_offset;
|
let saved_coloff = self.col_offset;
|
||||||
let saved_rowoff = self.row_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() {
|
if query.is_empty() {
|
||||||
self.cursor_x = saved_cx;
|
self.cursor_x = saved_cx;
|
||||||
|
Loading…
Reference in New Issue
Block a user