[Feat] add breadcrumbs to display file path

This commit is contained in:
Mist 2024-03-17 22:34:01 +08:00
parent 38ee8c463d
commit 272e89ff8e
9 changed files with 141 additions and 4 deletions

View file

@ -1,3 +1,5 @@
use regex::Regex;
const MIN_WIDTH: f32 = 100.; const MIN_WIDTH: f32 = 100.;
fn min_width(width: f32) -> f32 { fn min_width(width: f32) -> f32 {
@ -9,7 +11,8 @@ fn min_width(width: f32) -> f32 {
} }
pub fn calc_wh(text: &str, char_wdith: f32, line_height: f32) -> (f32, f32) { pub fn calc_wh(text: &str, char_wdith: f32, line_height: f32) -> (f32, f32) {
let lines = text.lines(); let trimmed_text = trim_space(text);
let lines = trimmed_text.lines();
let max_length_line = lines.clone().into_iter().fold("", |max_length_line, cur| { let max_length_line = lines.clone().into_iter().fold("", |max_length_line, cur| {
if cur.len() > max_length_line.len() { if cur.len() > max_length_line.len() {
cur cur
@ -22,3 +25,25 @@ pub fn calc_wh(text: &str, char_wdith: f32, line_height: f32) -> (f32, f32) {
(min_width(width), height) (min_width(width), height)
} }
pub fn trim_space(text: &str) -> String {
let lines = text.split("\n").collect::<Vec<&str>>();
let first_line = lines.first().unwrap();
let head_spaces = Regex::new(r"^(\s*)").unwrap().find(first_line);
match head_spaces {
Some(head_spaces) => {
return lines
.into_iter()
.map(|line| {
Regex::new(format!("^{}", head_spaces.as_str()).as_ref())
.unwrap()
.replace(line, "")
.to_string()
})
.collect::<Vec<String>>()
.join("\n");
}
None => text.to_string(),
}
}

View file

@ -1,4 +1,5 @@
pub mod background; pub mod background;
pub mod breadcrumbs;
pub mod container; pub mod container;
pub mod editor; pub mod editor;
pub mod interface; pub mod interface;

View file

@ -0,0 +1,89 @@
use cosmic_text::{Attrs, Color, Family};
use regex::Regex;
use crate::{code::calc_wh, edges::margin::Margin, text::FontRenderer};
use super::interface::{
component::Component,
style::{RawComponentStyle, Size},
};
pub struct Breadcrumbs {
children: Vec<Box<dyn Component>>,
path: String,
line_height: f32,
has_breadcrumbs: bool,
}
impl Component for Breadcrumbs {
fn children(&self) -> &Vec<Box<dyn Component>> {
&self.children
}
fn style(&self) -> RawComponentStyle {
let style = RawComponentStyle::default();
if self.has_breadcrumbs {
let (w, h) = calc_wh(&self.path, 8., self.line_height);
style.size(Size::Num(w), Size::Num(h)).margin(Margin {
top: 5.,
..Margin::default()
})
} else {
style
}
}
fn draw_self(
&self,
pixmap: &mut tiny_skia::Pixmap,
context: &super::interface::component::ComponentContext,
render_params: &super::interface::component::RenderParams,
style: &super::interface::style::ComponentStyle,
) -> super::interface::render_error::Result<()> {
if self.has_breadcrumbs {
let attrs = Attrs::new()
.color(Color::rgb(128, 132, 139))
.family(Family::Name(&context.take_snapshot_params.code_font_family));
FontRenderer::new(
12.,
self.line_height,
context.scale_factor,
&context.take_snapshot_params.fonts_folder,
)
.draw_text(
render_params.x,
render_params.y,
style.width,
self.line_height,
vec![(&self.path, attrs)],
pixmap,
);
}
Ok(())
}
}
impl Breadcrumbs {
pub fn from_path(
path: String,
line_height: f32,
separator: String,
has_breadcrumbs: bool,
) -> Breadcrumbs {
let path = Regex::new("/")
.unwrap()
.replace_all(&path, separator)
.to_string();
Breadcrumbs {
children: vec![],
path,
line_height,
has_breadcrumbs,
}
}
}

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
code::calc_wh, code::{calc_wh, trim_space},
components::interface::{ components::interface::{
component::{Component, ComponentContext, RenderParams}, component::{Component, ComponentContext, RenderParams},
render_error, render_error,
@ -42,7 +42,7 @@ impl Component for Code {
) -> render_error::Result<()> { ) -> render_error::Result<()> {
let params = &context.take_snapshot_params; let params = &context.take_snapshot_params;
let highlight = Highlight::new( let highlight = Highlight::new(
params.code.clone(), self.value.clone(),
params.code_font_family.clone(), params.code_font_family.clone(),
params.language.clone(), params.language.clone(),
params.extension.clone(), params.extension.clone(),
@ -71,7 +71,7 @@ impl Component for Code {
impl Code { impl Code {
pub fn new(value: String, line_height: f32, font_size: f32) -> Code { pub fn new(value: String, line_height: f32, font_size: f32) -> Code {
Code { Code {
value, value: trim_space(&value),
line_height, line_height,
font_size, font_size,
children: vec![], children: vec![],

View file

@ -19,6 +19,9 @@ pub struct TakeSnapshotParams {
pub theme: String, pub theme: String,
pub bg_theme: String, pub bg_theme: String,
pub bg_color: Option<String>, pub bg_color: Option<String>,
pub file_path: String,
pub breadcrumbs_separator: String,
pub has_breadcrumbs: bool,
} }
impl FromObject for TakeSnapshotParams { impl FromObject for TakeSnapshotParams {

View file

@ -3,6 +3,7 @@ use std::sync::Arc;
use tiny_skia::Pixmap; use tiny_skia::Pixmap;
use crate::components::background::Background; use crate::components::background::Background;
use crate::components::breadcrumbs::Breadcrumbs;
use crate::components::container::Container; use crate::components::container::Container;
use crate::components::editor::code::Code; use crate::components::editor::code::Code;
use crate::components::editor::mac_title_bar::MacTitleBar; use crate::components::editor::mac_title_bar::MacTitleBar;
@ -26,6 +27,12 @@ pub fn take_snapshot(params: TakeSnapshotParams) -> render_error::Result<Pixmap>
16., 16.,
vec![ vec![
Box::new(MacTitleBar::from_radius(8.)), Box::new(MacTitleBar::from_radius(8.)),
Box::new(Breadcrumbs::from_path(
params.file_path,
15.,
params.breadcrumbs_separator,
params.has_breadcrumbs,
)),
Box::new(Code::new(params.code, 20., 15.)), Box::new(Code::new(params.code, 20., 15.)),
], ],
)), )),

View file

@ -3,6 +3,7 @@ local table_utils = require("codesnap.utils.table")
local generator = require("generator") local generator = require("generator")
local string_utils = require("codesnap.utils.string") local string_utils = require("codesnap.utils.string")
local visual_utils = require("codesnap.utils.visual") local visual_utils = require("codesnap.utils.visual")
local path_utils = require("codesnap.utils.path")
local assets_folder = static.cwd .. "/assets" local assets_folder = static.cwd .. "/assets"
@ -40,6 +41,7 @@ local function get_config()
fonts_folder = assets_folder .. "/fonts", fonts_folder = assets_folder .. "/fonts",
themes_folder = assets_folder .. "/themes", themes_folder = assets_folder .. "/themes",
theme = "base16-onedark", theme = "base16-onedark",
file_path = static.config.has_breadcrumbs and path_utils.get_relative_path() or "",
}, static.config) }, static.config)
end end

View file

@ -8,6 +8,8 @@ return {
watermark_font_family = "Pacifico", watermark_font_family = "Pacifico",
watermark = "CodeSnap.nvim", watermark = "CodeSnap.nvim",
bg_theme = "default", bg_theme = "default",
breadcrumbs_separator = "/",
has_breadcrumbs = false,
}, },
cwd = path_utils.back(path_utils.back(debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])"))), cwd = path_utils.back(path_utils.back(debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])"))),
preview_switch = true, preview_switch = true,

View file

@ -1,3 +1,4 @@
local string_utils = require("codesnap.utils.string")
local path_utils = {} local path_utils = {}
function path_utils.back(path) function path_utils.back(path)
@ -6,4 +7,11 @@ function path_utils.back(path)
return parsed_path return parsed_path
end end
function path_utils.get_relative_path()
local full_file_path = vim.fn.expand("%:p")
local cwd = vim.fn.getcwd()
return full_file_path:gsub(string_utils.escape(cwd), ""):sub(2)
end
return path_utils return path_utils