forked from mirror/codesnap.nvim
[Feat] support line number & remove unused module (#91)
parent
ef08881e1a
commit
3b7dd6a3ad
|
@ -2,6 +2,7 @@ use cached::proc_macro::cached;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
const MIN_WIDTH: f32 = 100.;
|
const MIN_WIDTH: f32 = 100.;
|
||||||
|
pub const CHAR_WIDTH: f32 = 9.05;
|
||||||
|
|
||||||
fn min_width(width: f32) -> f32 {
|
fn min_width(width: f32) -> f32 {
|
||||||
if width < MIN_WIDTH {
|
if width < MIN_WIDTH {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
pub mod background;
|
pub mod background;
|
||||||
pub mod breadcrumbs;
|
pub mod breadcrumbs;
|
||||||
|
pub mod code_block;
|
||||||
pub mod container;
|
pub mod container;
|
||||||
pub mod editor;
|
pub mod editor;
|
||||||
pub mod interface;
|
pub mod interface;
|
||||||
|
pub mod line_number;
|
||||||
pub mod rect;
|
pub mod rect;
|
||||||
pub mod watermark;
|
pub mod watermark;
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
use crate::edges::margin::Margin;
|
||||||
|
|
||||||
|
use super::interface::{
|
||||||
|
component::Component,
|
||||||
|
style::{RawComponentStyle, Style},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct CodeBlock {
|
||||||
|
children: Vec<Box<dyn Component>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for CodeBlock {
|
||||||
|
fn children(&self) -> &Vec<Box<dyn Component>> {
|
||||||
|
&self.children
|
||||||
|
}
|
||||||
|
|
||||||
|
fn style(&self) -> RawComponentStyle {
|
||||||
|
Style::default().margin(Margin {
|
||||||
|
top: 10.,
|
||||||
|
..Margin::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeBlock {
|
||||||
|
pub fn from_children(children: Vec<Box<dyn Component>>) -> CodeBlock {
|
||||||
|
CodeBlock { children }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
code::{calc_wh, prepare_code},
|
code::{calc_wh, prepare_code, CHAR_WIDTH},
|
||||||
components::interface::{
|
components::interface::{
|
||||||
component::{Component, ComponentContext, RenderParams},
|
component::{Component, ComponentContext, RenderParams},
|
||||||
render_error,
|
render_error,
|
||||||
style::{ComponentStyle, RawComponentStyle, Size, Style},
|
style::{ComponentStyle, RawComponentStyle, Size, Style},
|
||||||
},
|
},
|
||||||
edges::margin::Margin,
|
|
||||||
highlight::Highlight,
|
highlight::Highlight,
|
||||||
text::FontRenderer,
|
text::FontRenderer,
|
||||||
};
|
};
|
||||||
|
@ -23,14 +22,9 @@ impl Component for Code {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> RawComponentStyle {
|
fn style(&self) -> RawComponentStyle {
|
||||||
let (w, h) = calc_wh(&self.value, 9.05, self.line_height);
|
let (w, h) = calc_wh(&self.value, CHAR_WIDTH, self.line_height);
|
||||||
|
|
||||||
Style::default()
|
Style::default().size(Size::Num(w), Size::Num(h))
|
||||||
.size(Size::Num(w), Size::Num(h))
|
|
||||||
.margin(Margin {
|
|
||||||
top: 10.,
|
|
||||||
..Margin::default()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_self(
|
fn draw_self(
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
use super::interface::{
|
||||||
|
component::{Component, ComponentContext, RenderParams},
|
||||||
|
render_error,
|
||||||
|
style::{ComponentStyle, RawComponentStyle, Size, Style},
|
||||||
|
};
|
||||||
|
use crate::{code::CHAR_WIDTH, edges::margin::Margin, text::FontRenderer};
|
||||||
|
use cosmic_text::{Attrs, Color, Family};
|
||||||
|
|
||||||
|
const FONT_SIZE: f32 = 14.;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct LineNumber {
|
||||||
|
children: Vec<Box<dyn Component>>,
|
||||||
|
line_height: f32,
|
||||||
|
render_condition: bool,
|
||||||
|
line_number_content: Vec<String>,
|
||||||
|
number_of_digit: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for LineNumber {
|
||||||
|
fn render_condition(&self) -> bool {
|
||||||
|
return self.render_condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> &Vec<Box<dyn Component>> {
|
||||||
|
&self.children
|
||||||
|
}
|
||||||
|
|
||||||
|
fn style(&self) -> RawComponentStyle {
|
||||||
|
Style::default()
|
||||||
|
.size(
|
||||||
|
Size::Num(CHAR_WIDTH * self.number_of_digit as f32),
|
||||||
|
Size::Num(self.line_number_content.len() as f32 * self.line_height),
|
||||||
|
)
|
||||||
|
.margin(Margin {
|
||||||
|
right: 10.,
|
||||||
|
..Margin::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_self(
|
||||||
|
&self,
|
||||||
|
pixmap: &mut tiny_skia::Pixmap,
|
||||||
|
context: &ComponentContext,
|
||||||
|
render_params: &RenderParams,
|
||||||
|
style: &ComponentStyle,
|
||||||
|
) -> render_error::Result<()> {
|
||||||
|
FontRenderer::new(
|
||||||
|
FONT_SIZE,
|
||||||
|
self.line_height,
|
||||||
|
context.scale_factor,
|
||||||
|
&context.take_snapshot_params.fonts_folder,
|
||||||
|
)
|
||||||
|
.draw_text(
|
||||||
|
render_params.x,
|
||||||
|
render_params.y,
|
||||||
|
style.width,
|
||||||
|
style.height,
|
||||||
|
vec![(
|
||||||
|
&self.line_number_content.join("\n"),
|
||||||
|
Attrs::new()
|
||||||
|
.color(Color::rgb(73, 81, 98))
|
||||||
|
.family(Family::Name(&context.take_snapshot_params.code_font_family)),
|
||||||
|
)],
|
||||||
|
pixmap,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LineNumber {
|
||||||
|
pub fn new(content: &str, start_line_number: Option<usize>, line_height: f32) -> LineNumber {
|
||||||
|
match start_line_number {
|
||||||
|
None => LineNumber::default(),
|
||||||
|
Some(start_line_number) => {
|
||||||
|
let lines = content.split("\n").collect::<Vec<&str>>();
|
||||||
|
let max_line_number = lines.len() + start_line_number;
|
||||||
|
let number_of_digit = (max_line_number - 1).to_string().len();
|
||||||
|
|
||||||
|
LineNumber {
|
||||||
|
line_number_content: (start_line_number..max_line_number)
|
||||||
|
.map(|line_number| {
|
||||||
|
format!(
|
||||||
|
"{:>width$}",
|
||||||
|
line_number.to_string(),
|
||||||
|
width = number_of_digit
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>(),
|
||||||
|
number_of_digit,
|
||||||
|
children: vec![],
|
||||||
|
render_condition: true,
|
||||||
|
line_height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ pub struct TakeSnapshotParams {
|
||||||
pub file_path: String,
|
pub file_path: String,
|
||||||
pub breadcrumbs_separator: String,
|
pub breadcrumbs_separator: String,
|
||||||
pub has_breadcrumbs: bool,
|
pub has_breadcrumbs: bool,
|
||||||
|
pub start_line_number: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromObject for TakeSnapshotParams {
|
impl FromObject for TakeSnapshotParams {
|
||||||
|
|
|
@ -4,11 +4,13 @@ use tiny_skia::Pixmap;
|
||||||
|
|
||||||
use crate::components::background::Background;
|
use crate::components::background::Background;
|
||||||
use crate::components::breadcrumbs::Breadcrumbs;
|
use crate::components::breadcrumbs::Breadcrumbs;
|
||||||
|
use crate::components::code_block::CodeBlock;
|
||||||
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;
|
||||||
use crate::components::interface::component::ComponentContext;
|
use crate::components::interface::component::ComponentContext;
|
||||||
use crate::components::interface::render_error;
|
use crate::components::interface::render_error;
|
||||||
|
use crate::components::line_number::LineNumber;
|
||||||
use crate::components::rect::Rect;
|
use crate::components::rect::Rect;
|
||||||
use crate::components::watermark::Watermark;
|
use crate::components::watermark::Watermark;
|
||||||
use crate::config::TakeSnapshotParams;
|
use crate::config::TakeSnapshotParams;
|
||||||
|
@ -33,7 +35,10 @@ pub fn take_snapshot(params: TakeSnapshotParams) -> render_error::Result<Pixmap>
|
||||||
params.breadcrumbs_separator,
|
params.breadcrumbs_separator,
|
||||||
params.has_breadcrumbs,
|
params.has_breadcrumbs,
|
||||||
)),
|
)),
|
||||||
Box::new(Code::new(params.code, 20., 15.)),
|
Box::new(CodeBlock::from_children(vec![
|
||||||
|
Box::new(LineNumber::new(¶ms.code, params.start_line_number, 20.)),
|
||||||
|
Box::new(Code::new(params.code, 20., 15.)),
|
||||||
|
])),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
Box::new(Watermark::new(params.watermark)),
|
Box::new(Watermark::new(params.watermark)),
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
local logger = require("codesnap.utils.logger")
|
|
||||||
local static = require("codesnap.static")
|
|
||||||
|
|
||||||
local client = {
|
|
||||||
job_id = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
local cwd = static.cwd .. "/snap-server"
|
|
||||||
|
|
||||||
function client:connect()
|
|
||||||
return vim.fn.jobstart({
|
|
||||||
cwd .. "/target/release/snap-server",
|
|
||||||
}, {
|
|
||||||
cwd = cwd,
|
|
||||||
stderr_buffered = true,
|
|
||||||
rpc = true,
|
|
||||||
on_stderr = function(_, err)
|
|
||||||
vim.fn.jobstop(self.job_id)
|
|
||||||
logger.error(err)
|
|
||||||
end,
|
|
||||||
on_exit = function()
|
|
||||||
vim.fn.chanclose(self.job_id)
|
|
||||||
self.job_id = 0
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
function client:init()
|
|
||||||
return self.job_id == 0 and client:connect() or self.job_id
|
|
||||||
end
|
|
||||||
|
|
||||||
function client:start()
|
|
||||||
self.job_id = client:init()
|
|
||||||
|
|
||||||
if self.job_id == 0 then
|
|
||||||
logger.error("cannot start rpc process")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.job_id == -1 then
|
|
||||||
logger.error("rpc process is not executable")
|
|
||||||
vim.fn.jobstop(self.job_id)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function client:send(event, message)
|
|
||||||
vim.fn.rpcnotify(self.job_id, event, message)
|
|
||||||
end
|
|
||||||
|
|
||||||
function client:stop()
|
|
||||||
if self.job_id == 0 or self.job_id == -1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.fn.jobstop(self.job_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
return client
|
|
|
@ -27,6 +27,7 @@ end
|
||||||
|
|
||||||
function config_module.get_config(extension)
|
function config_module.get_config(extension)
|
||||||
local code = visual_utils.get_selected_text()
|
local code = visual_utils.get_selected_text()
|
||||||
|
local start_line_number = visual_utils.get_start_line_number()
|
||||||
|
|
||||||
if string_utils.is_str_empty(code) then
|
if string_utils.is_str_empty(code) then
|
||||||
error("No code is selected", 0)
|
error("No code is selected", 0)
|
||||||
|
@ -41,6 +42,7 @@ function config_module.get_config(extension)
|
||||||
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 "",
|
file_path = static.config.has_breadcrumbs and path_utils.get_relative_path() or "",
|
||||||
|
start_line_number = static.config.has_line_number and start_line_number or nil,
|
||||||
}, static.config)
|
}, static.config)
|
||||||
|
|
||||||
config.save_path = parse_save_path(config.save_path)
|
config.save_path = parse_save_path(config.save_path)
|
||||||
|
|
|
@ -36,6 +36,7 @@ function main.save_snapshot(extension)
|
||||||
|
|
||||||
require("generator").save_snapshot(config)
|
require("generator").save_snapshot(config)
|
||||||
vim.cmd("delmarks <>")
|
vim.cmd("delmarks <>")
|
||||||
|
---@diagnostic disable-next-line: need-check-nil
|
||||||
vim.notify("Save snapshot in " .. config.save_path .. " successfully")
|
vim.notify("Save snapshot in " .. config.save_path .. " successfully")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ return {
|
||||||
bg_theme = "default",
|
bg_theme = "default",
|
||||||
breadcrumbs_separator = "/",
|
breadcrumbs_separator = "/",
|
||||||
has_breadcrumbs = false,
|
has_breadcrumbs = false,
|
||||||
|
has_line_number = 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,
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
local logger = {}
|
|
||||||
|
|
||||||
function logger.log(level, message)
|
|
||||||
vim.api.nvim_notify("[" .. level .. "] CodeSnap: " .. tostring(vim.inspect(message)), vim.log.levels[level], {})
|
|
||||||
end
|
|
||||||
|
|
||||||
function logger.error(message)
|
|
||||||
logger.log("ERROR", message)
|
|
||||||
end
|
|
||||||
|
|
||||||
return logger
|
|
|
@ -2,7 +2,6 @@ local visual_utils = {}
|
||||||
|
|
||||||
-- Get all the lines from "from" to "to" and return them as a single string
|
-- Get all the lines from "from" to "to" and return them as a single string
|
||||||
-- If "from" and "to" are the same, return the line at "from"
|
-- If "from" and "to" are the same, return the line at "from"
|
||||||
|
|
||||||
local function get_whole_lines(from, to)
|
local function get_whole_lines(from, to)
|
||||||
local lines = {}
|
local lines = {}
|
||||||
if from == to then
|
if from == to then
|
||||||
|
@ -15,6 +14,10 @@ local function get_whole_lines(from, to)
|
||||||
return table.concat(lines, "\n")
|
return table.concat(lines, "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function visual_utils.get_start_line_number()
|
||||||
|
return vim.fn.line("'<")
|
||||||
|
end
|
||||||
|
|
||||||
function visual_utils.get_selected_text()
|
function visual_utils.get_selected_text()
|
||||||
local selected_text = vim.fn.getline("'<", "'>")
|
local selected_text = vim.fn.getline("'<", "'>")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue