summaryrefslogtreecommitdiffstats
path: root/src/layout.rs
diff options
context:
space:
mode:
authorKyohei Uto <im@kyoheiu.dev>2022-10-29 16:26:34 +0900
committerKyohei Uto <im@kyoheiu.dev>2022-10-29 16:26:34 +0900
commit3f1d538f03c8aefed293954152924967f1dd7f21 (patch)
tree265b77265392b845574e400484ae0dd9575f6e96 /src/layout.rs
parent4210a55841aec7134a811a11b1e994cbe5d324cb (diff)
MVP: Add syntax highlighting if possible
Diffstat (limited to 'src/layout.rs')
-rw-r--r--src/layout.rs104
1 files changed, 88 insertions, 16 deletions
diff --git a/src/layout.rs b/src/layout.rs
index a701fe8..7f37876 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -4,6 +4,11 @@ use super::functions::*;
use super::state::{FileType, ItemInfo, BEGINNING_ROW};
use super::term::*;
+use syntect::easy::HighlightLines;
+use syntect::highlighting::ThemeSet;
+use syntect::parsing::SyntaxSet;
+use syntect::util::{as_24_bit_terminal_escaped, split_at, LinesWithEndings};
+
/// cf: https://docs.rs/image/latest/src/image/image.rs.html#84-112
pub const MAX_SIZE_TO_PREVIEW: u64 = 1_000_000_000;
pub const IMAGE_EXTENSION: [&str; 20] = [
@@ -74,7 +79,7 @@ impl Layout {
print!("(file too big for preview)");
}
PreviewType::Directory => {
- self.preview_content(item, true);
+ self.preview_directory(item);
}
PreviewType::Image => {
if self.has_chafa {
@@ -93,7 +98,7 @@ impl Layout {
}
}
PreviewType::Text => {
- self.preview_content(item, false);
+ self.preview_text(item);
}
PreviewType::Binary => {
print!("(Binary file)");
@@ -113,9 +118,87 @@ impl Layout {
print!("{}", file_name);
}
- /// Print text preview on the right half of the terminal.
- fn preview_content(&self, item: &ItemInfo, is_dir: bool) {
- let content = if is_dir {
+ fn preview_text(&self, item: &ItemInfo) {
+ let ps = SyntaxSet::load_defaults_newlines();
+ if let Ok(Some(syntax)) = ps.find_syntax_for_file(item.file_path.clone()) {
+ let ts = ThemeSet::load_defaults();
+ let mut h = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]);
+ if let Ok(content) = std::fs::read_to_string(item.file_path.clone()) {
+ move_to(self.preview_start_column, BEGINNING_ROW);
+ let mut result = vec![];
+ let max_row = match self.split {
+ Split::Vertical => self.terminal_row - BEGINNING_ROW,
+ Split::Horizontal => self.terminal_row - 1,
+ };
+ 'outer: for line in LinesWithEndings::from(&content) {
+ let count = line.len() / self.preview_width as usize;
+ let mut range = h.highlight_line(line, &ps).unwrap();
+ for _ in 0..=count + 1 {
+ let ranges = split_at(&range, self.preview_width.into());
+ if !ranges.0.is_empty() {
+ result.push(ranges.0);
+ }
+ if result.len() == max_row as usize {
+ break 'outer;
+ } else {
+ range = ranges.1;
+ continue;
+ }
+ }
+ }
+ for (i, line) in result.iter().enumerate() {
+ let escaped = as_24_bit_terminal_escaped(line, false);
+ match self.split {
+ Split::Vertical => {
+ move_to(self.preview_start_column, BEGINNING_ROW + i as u16);
+ }
+ Split::Horizontal => {
+ move_to(1, self.preview_start_row + i as u16);
+ }
+ }
+ print!("{}", escaped);
+ }
+ reset_color();
+ }
+ } else {
+ let content = {
+ if let Ok(content) = std::fs::read_to_string(item.file_path.clone()) {
+ let content = content.replace('\t', " ");
+ format_txt(&content, self.terminal_column - 1, false)
+ } else {
+ vec![]
+ }
+ };
+ match self.split {
+ Split::Vertical => {
+ for (i, line) in content.iter().enumerate() {
+ move_to(self.preview_start_column, BEGINNING_ROW + i as u16);
+ set_color(&TermColor::ForeGround(&Colorname::LightBlack));
+ print!("{}", line);
+ reset_color();
+ if BEGINNING_ROW + i as u16 == self.terminal_row - 1 {
+ break;
+ }
+ }
+ }
+ Split::Horizontal => {
+ for (i, line) in content.iter().enumerate() {
+ let row = self.preview_start_row + i as u16;
+ move_to(1, row);
+ set_color(&TermColor::ForeGround(&Colorname::LightBlack));
+ print!("{}", line);
+ reset_color();
+ if row == self.terminal_row - 1 {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fn preview_directory(&self, item: &ItemInfo) {
+ let content = {
let contents = match &item.symlink_dir_path {
None => list_up_contents(&item.file_path),
Some(p) => list_up_contents(p),
@@ -129,16 +212,6 @@ impl Layout {
} else {
vec![]
}
- } else {
- let item = item.file_path.clone();
- let column = self.terminal_column;
- let content = std::fs::read_to_string(item);
- if let Ok(content) = content {
- let content = content.replace('\t', " ");
- format_txt(&content, column - 1, false)
- } else {
- vec![]
- }
};
//Print preview (wrapping)
@@ -168,7 +241,6 @@ impl Layout {
}
}
}
-
/// Print text preview on the right half of the terminal (Experimental).
fn preview_image(&self, item: &ItemInfo, y: u16) -> Result<(), FxError> {
let wxh = match self.split {