adjusted explorer to new helix code

imgbot
Roland Singer 2 years ago
commit 92ebab74b5

@ -26,6 +26,27 @@ macro_rules! get_theme {
}; };
} }
const ICONS: &'static [&'static str] =
&["", "", "", "", "", "ﰟ", "", "", "", "ﯤ", "", "ﬥ"];
const ICONS_EXT: &'static [&'static str] = &[
".rs", ".md", ".js", ".c", ".png", ".svg", ".css", ".html", ".lua", ".ts", ".py", ".json",
];
const ICONS_COLORS: &'static [helix_view::theme::Color] = &[
helix_view::theme::Color::Rgb(227, 134, 84),
helix_view::theme::Color::LightCyan,
helix_view::theme::Color::Yellow,
helix_view::theme::Color::Blue,
helix_view::theme::Color::Yellow,
helix_view::theme::Color::Yellow,
helix_view::theme::Color::Green,
helix_view::theme::Color::Blue,
helix_view::theme::Color::Red,
helix_view::theme::Color::Blue,
helix_view::theme::Color::Red,
];
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
enum FileType { enum FileType {
File, File,
@ -39,18 +60,24 @@ enum FileType {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct FileInfo { struct FileInfo {
file_type: FileType, file_type: FileType,
expanded: bool,
path: PathBuf, path: PathBuf,
} }
impl FileInfo { impl FileInfo {
fn new(path: PathBuf, file_type: FileType) -> Self { fn new(path: PathBuf, file_type: FileType) -> Self {
Self { path, file_type } Self {
path,
file_type,
expanded: false,
}
} }
fn root(path: PathBuf) -> Self { fn root(path: PathBuf) -> Self {
Self { Self {
file_type: FileType::Root, file_type: FileType::Root,
path, path,
expanded: true,
} }
} }
@ -59,6 +86,7 @@ impl FileInfo {
Self { Self {
file_type: FileType::Parent, file_type: FileType::Parent,
path: p.to_path_buf(), path: p.to_path_buf(),
expanded: false,
} }
} }
@ -159,6 +187,7 @@ impl TreeItem for FileInfo {
Self { Self {
file_type, file_type,
path: self.path.join(entry.file_name()), path: self.path.join(entry.file_name()),
expanded: false,
} }
}) })
}) })
@ -167,6 +196,7 @@ impl TreeItem for FileInfo {
ret.push(Self { ret.push(Self {
path: self.path.clone(), path: self.path.clone(),
file_type: FileType::Placeholder, file_type: FileType::Placeholder,
expanded: false,
}) })
} }
Ok(ret) Ok(ret)
@ -179,6 +209,33 @@ impl TreeItem for FileInfo {
self.get_text().contains(s) self.get_text().contains(s)
} }
} }
fn icon(&self) -> Option<(&'static str, &'static helix_view::theme::Color)> {
return match self.file_type {
FileType::Dir => {
if self.expanded {
//Some(("", &helix_view::theme::Color::Yellow))
Some(("", &helix_view::theme::Color::Yellow))
} else {
// Some(("", &helix_view::theme::Color::Yellow))
Some(("", &helix_view::theme::Color::Yellow))
}
}
FileType::File => {
for (i, ext) in ICONS_EXT.iter().enumerate() {
if self.get_text().ends_with(ext) {
let color = ICONS_COLORS
.iter()
.nth(i)
.unwrap_or(&helix_view::theme::Color::Blue);
return ICONS.iter().nth(i).map(|c| (*c, color));
}
}
return Some(("", &helix_view::theme::Color::LightBlue));
}
_ => None,
};
}
} }
// #[derive(Default, Debug, Clone)] // #[derive(Default, Debug, Clone)]
@ -254,7 +311,9 @@ impl Explorer {
let current_root = std::env::current_dir().unwrap_or_else(|_| "./".into()); let current_root = std::env::current_dir().unwrap_or_else(|_| "./".into());
let items = Self::get_items(current_root.clone(), cx)?; let items = Self::get_items(current_root.clone(), cx)?;
Ok(Self { Ok(Self {
tree: Tree::build_tree(items).with_enter_fn(Self::toggle_current), tree: Tree::build_tree(items)
.with_enter_fn(Self::toggle_current)
.with_folded_fn(Self::fold_current),
state: State::new(true, current_root), state: State::new(true, current_root),
repeat_motion: None, repeat_motion: None,
prompt: None, prompt: None,
@ -266,8 +325,9 @@ impl Explorer {
let current_root = std::env::current_dir().unwrap_or_else(|_| "./".into()); let current_root = std::env::current_dir().unwrap_or_else(|_| "./".into());
let parent = FileInfo::parent(&current_root); let parent = FileInfo::parent(&current_root);
let root = FileInfo::root(current_root.clone()); let root = FileInfo::root(current_root.clone());
let mut tree = let mut tree = Tree::build_from_root(root, usize::MAX / 2)?
Tree::build_from_root(root, usize::MAX / 2)?.with_enter_fn(Self::toggle_current); .with_enter_fn(Self::toggle_current)
.with_folded_fn(Self::fold_current);
tree.insert_current_level(parent); tree.insert_current_level(parent);
Ok(Self { Ok(Self {
tree, tree,
@ -319,7 +379,12 @@ impl Explorer {
if item.file_type == FileType::Placeholder { if item.file_type == FileType::Placeholder {
return; return;
} }
let head_area = render_block(area.clip_bottom(area.height - 2), surface, Borders::BOTTOM); let head_area = render_block(
area.clip_bottom(area.height - 2),
surface,
Borders::BOTTOM,
None,
);
let path_str = format!("{}", item.path.display()); let path_str = format!("{}", item.path.display());
surface.set_stringn( surface.set_stringn(
head_area.x, head_area.x,
@ -434,6 +499,12 @@ impl Explorer {
)); ));
} }
fn fold_current(item: &mut FileInfo, _cx: &mut Context, _state: &mut State) {
if item.path.is_dir() {
item.expanded = false;
}
}
fn toggle_current( fn toggle_current(
item: &mut FileInfo, item: &mut FileInfo,
cx: &mut Context, cx: &mut Context,
@ -453,7 +524,7 @@ impl Explorer {
} }
}; };
if meta.is_file() { if meta.is_file() {
if let Err(e) = cx.editor.open(&item.path, Action::Replace) { if let Err(e) = cx.editor.open(&item.path.clone(), Action::Replace) {
cx.editor.set_error(format!("{e}")); cx.editor.set_error(format!("{e}"));
} }
state.focus = false; state.focus = false;
@ -461,6 +532,7 @@ impl Explorer {
} }
if item.path.is_dir() { if item.path.is_dir() {
item.expanded = true;
if cx.editor.config().explorer.is_list() || item.file_type == FileType::Parent { if cx.editor.config().explorer.is_list() || item.file_type == FileType::Parent {
match Self::get_items(item.path.clone(), cx) { match Self::get_items(item.path.clone(), cx) {
Ok(items) => { Ok(items) => {
@ -481,19 +553,28 @@ impl Explorer {
let background = cx.editor.theme.get("ui.background"); let background = cx.editor.theme.get("ui.background");
let column_width = cx.editor.config().explorer.column_width as u16; let column_width = cx.editor.config().explorer.column_width as u16;
surface.clear_with(area, background); surface.clear_with(area, background);
let area = render_block(area, surface, Borders::ALL); let area = render_block(area, surface, Borders::ALL, None);
let mut preview_area = area.clip_left(column_width + 1); let mut preview_area = area.clip_left(column_width + 1);
if let Some((_, prompt)) = self.prompt.as_mut() { if let Some((_, prompt)) = self.prompt.as_mut() {
let area = preview_area.clip_bottom(2); let area = preview_area.clip_bottom(2);
let promp_area = let promp_area = render_block(
render_block(preview_area.clip_top(area.height), surface, Borders::TOP); preview_area.clip_top(area.height),
surface,
Borders::TOP,
None,
);
prompt.render(promp_area, surface, cx); prompt.render(promp_area, surface, cx);
preview_area = area; preview_area = area;
} }
self.render_preview(preview_area, surface, cx.editor); self.render_preview(preview_area, surface, cx.editor);
let list_area = render_block(area.clip_right(preview_area.width), surface, Borders::RIGHT); let list_area = render_block(
area.clip_right(preview_area.width),
surface,
Borders::RIGHT,
None,
);
self.tree.render(list_area, surface, cx, &mut self.state); self.tree.render(list_area, surface, cx, &mut self.state);
} }
@ -502,14 +583,21 @@ impl Explorer {
let side_area = area let side_area = area
.with_width(area.width.min(config.column_width as u16 + 2)) .with_width(area.width.min(config.column_width as u16 + 2))
.clip_bottom(1); .clip_bottom(1);
let background = cx.editor.theme.get("ui.background");
let background = cx.editor.theme.get("ui.statusline");
surface.clear_with(side_area, background); surface.clear_with(side_area, background);
let preview_area = area.clip_left(side_area.width).clip_bottom(2); let preview_area = area.clip_left(side_area.width).clip_bottom(2);
let prompt_area = area.clip_top(side_area.height); let prompt_area = area.clip_top(side_area.height);
let list_area = let border_style = cx.editor.theme.get("ui.explorer.border");
render_block(side_area.clip_left(1), surface, Borders::RIGHT).clip_bottom(1); let list_area = render_block(
side_area.clip_left(1),
surface,
Borders::RIGHT,
Some(border_style),
)
.clip_bottom(1);
self.tree.render(list_area, surface, cx, &mut self.state); self.tree.render(list_area, surface, cx, &mut self.state);
{ {
@ -543,7 +631,7 @@ impl Explorer {
} }
let area = Rect::new(preview_area.x, y, width, height); let area = Rect::new(preview_area.x, y, width, height);
surface.clear_with(area, background); surface.clear_with(area, background);
let area = render_block(area, surface, Borders::all()); let area = render_block(area, surface, Borders::all(), None);
self.render_preview(area, surface, cx.editor); self.render_preview(area, surface, cx.editor);
} }
@ -757,7 +845,9 @@ impl Component for Explorer {
match Self::get_items(p.to_path_buf(), cx) { match Self::get_items(p.to_path_buf(), cx) {
Ok(items) => { Ok(items) => {
self.state.current_root = p.to_path_buf(); self.state.current_root = p.to_path_buf();
self.tree = Tree::build_tree(items).with_enter_fn(Self::toggle_current); self.tree = Tree::build_tree(items)
.with_enter_fn(Self::toggle_current)
.with_folded_fn(Self::fold_current);
} }
Err(e) => cx.editor.set_error(format!("{e}")), Err(e) => cx.editor.set_error(format!("{e}")),
} }
@ -859,8 +949,17 @@ fn get_preview(p: impl AsRef<Path>, max_line: usize) -> Result<Vec<String>> {
.collect()) .collect())
} }
fn render_block(area: Rect, surface: &mut Surface, borders: Borders) -> Rect { fn render_block(
let block = Block::default().borders(borders); area: Rect,
surface: &mut Surface,
borders: Borders,
border_style: Option<helix_view::theme::Style>,
) -> Rect {
let mut block = Block::default().borders(borders);
if let Some(style) = border_style {
block = block.border_style(style);
}
//let block = Block::default();
let inner = block.inner(area); let inner = block.inner(area);
block.render(area, surface); block.render(area, surface);
inner inner

@ -20,6 +20,7 @@ pub trait TreeItem: Sized {
fn text(&self, cx: &mut Context, selected: bool, params: &mut Self::Params) -> Spans; fn text(&self, cx: &mut Context, selected: bool, params: &mut Self::Params) -> Spans;
fn is_child(&self, other: &Self) -> bool; fn is_child(&self, other: &Self) -> bool;
fn cmp(&self, other: &Self) -> Ordering; fn cmp(&self, other: &Self) -> Ordering;
fn icon(&self) -> Option<(&'static str, &'static helix_view::theme::Color)>;
fn filter(&self, cx: &mut Context, s: &str, params: &mut Self::Params) -> bool { fn filter(&self, cx: &mut Context, s: &str, params: &mut Self::Params) -> bool {
self.text(cx, false, params) self.text(cx, false, params)
@ -178,7 +179,7 @@ impl<T: TreeItem> Tree<T> {
col: 0, col: 0,
max_len: 0, max_len: 0,
count: 0, count: 0,
tree_symbol_style: "ui.text".into(), tree_symbol_style: "ui.explorer.guide".into(),
pre_render: None, pre_render: None,
on_opened_fn: None, on_opened_fn: None,
on_folded_fn: None, on_folded_fn: None,
@ -471,6 +472,7 @@ impl<T: TreeItem> Tree<T> {
self.max_len = 0; self.max_len = 0;
self.row = std::cmp::min(self.row, area.height.saturating_sub(1) as usize); self.row = std::cmp::min(self.row, area.height.saturating_sub(1) as usize);
let style = cx.editor.theme.get(&self.tree_symbol_style); let style = cx.editor.theme.get(&self.tree_symbol_style);
let folder_style = cx.editor.theme.get("special");
let last_item_index = self.items.len().saturating_sub(1); let last_item_index = self.items.len().saturating_sub(1);
let skip = self.selected.saturating_sub(self.row); let skip = self.selected.saturating_sub(self.row);
let iter = self let iter = self
@ -484,9 +486,9 @@ impl<T: TreeItem> Tree<T> {
let mut area = Rect::new(area.x, area.y + row, area.width, 1); let mut area = Rect::new(area.x, area.y + row, area.width, 1);
let indent = if elem.level > 0 { let indent = if elem.level > 0 {
if index + skip != last_item_index { if index + skip != last_item_index {
format!("{}├─", "│ ".repeat(elem.level - 1)) format!("{}", "│ ".repeat(elem.level - 1))
} else { } else {
format!("└─{}", "┴─".repeat(elem.level - 1)) format!("{}", "".repeat(elem.level - 1))
} }
} else { } else {
"".to_string() "".to_string()
@ -502,14 +504,20 @@ impl<T: TreeItem> Tree<T> {
}; };
let mut start_index = self.col.saturating_sub(indent_len); let mut start_index = self.col.saturating_sub(indent_len);
let mut text = elem.item.text(cx, skip + index == self.selected, params); let mut text = elem.item.text(cx, skip + index == self.selected, params);
self.max_len = self.max_len.max(text.width() + indent.len()); self.max_len = self.max_len.max(text.width() + indent.len() - 2);
for span in text.0.iter_mut() { for span in text.0.iter_mut() {
if area.width == 0 { if area.width == 0 {
return; return;
} }
if start_index == 0 { if start_index == 0 {
surface.set_span(area.x, area.y, span, area.width); let mut icon_offset = 0;
area = area.clip_left(span.width() as u16); if let Some((icon, color)) = elem.item.icon() {
let style = folder_style.fg(*color);
surface.set_string(area.x, area.y, icon, style);
icon_offset = 2;
}
surface.set_span(area.x + icon_offset, area.y, span, area.width - icon_offset);
area = area.clip_left((span.width() - icon_offset as usize) as u16);
} else { } else {
let span_width = span.width(); let span_width = span.width();
if start_index > span_width { if start_index > span_width {
@ -527,10 +535,13 @@ impl<T: TreeItem> Tree<T> {
} }
}) })
.collect(); .collect();
let mut cont = String::new();
cont.push_str("");
cont.push_str(&content);
surface.set_string_truncated( surface.set_string_truncated(
area.x, area.x,
area.y, area.y,
&content, &cont,
area.width as usize, area.width as usize,
|_| span.style, |_| span.style,
false, false,

@ -78,6 +78,12 @@
"ui.explorer.focus" = { modifiers = ["reversed"] } "ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "bg3" } "ui.explorer.unfocus" = { bg = "bg3" }
"ui.explorer.file" = { fg = "fg" }
"ui.explorer.dir" = { fg = "blue" }
"ui.explorer.exe" = { fg = "fg" }
"ui.explorer.focus" = { modifiers = ["reversed"] }
"ui.explorer.unfocus" = { bg = "bg3" }
[palette] [palette]
bg0 = "#323437" bg0 = "#323437"

Loading…
Cancel
Save