mirror of
https://github.com/mistricky/codesnap.nvim.git
synced 2024-12-26 19:36:29 +00:00
[Feat] support highlight code block
This commit is contained in:
parent
00e2156364
commit
9836ad1163
18 changed files with 228 additions and 17 deletions
|
@ -3,6 +3,7 @@ pub mod breadcrumbs;
|
|||
pub mod code_block;
|
||||
pub mod container;
|
||||
pub mod editor;
|
||||
pub mod highlight_code_block;
|
||||
pub mod interface;
|
||||
pub mod line_number;
|
||||
pub mod rect;
|
||||
|
|
|
@ -35,6 +35,7 @@ impl Component for Background {
|
|||
context: &ComponentContext,
|
||||
_render_params: &RenderParams,
|
||||
_style: &ComponentStyle,
|
||||
_parent_style: &ComponentStyle,
|
||||
) -> render_error::Result<()> {
|
||||
let mut paint = Paint::default();
|
||||
let w = pixmap.width() as f32;
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{code::calc_wh, edges::margin::Margin, text::FontRenderer};
|
|||
|
||||
use super::interface::{
|
||||
component::Component,
|
||||
style::{RawComponentStyle, Size},
|
||||
style::{ComponentStyle, RawComponentStyle, Size},
|
||||
};
|
||||
|
||||
pub struct Breadcrumbs {
|
||||
|
@ -41,6 +41,7 @@ impl Component for Breadcrumbs {
|
|||
context: &super::interface::component::ComponentContext,
|
||||
render_params: &super::interface::component::RenderParams,
|
||||
style: &super::interface::style::ComponentStyle,
|
||||
_parent_style: &ComponentStyle,
|
||||
) -> super::interface::render_error::Result<()> {
|
||||
if self.has_breadcrumbs {
|
||||
let attrs = Attrs::new()
|
||||
|
|
|
@ -33,6 +33,7 @@ impl Component for Code {
|
|||
context: &ComponentContext,
|
||||
render_params: &RenderParams,
|
||||
style: &ComponentStyle,
|
||||
_parent_style: &ComponentStyle,
|
||||
) -> render_error::Result<()> {
|
||||
let params = &context.take_snapshot_params;
|
||||
let highlight = Highlight::new(
|
||||
|
|
|
@ -33,6 +33,7 @@ impl Component for MacTitleBar {
|
|||
context: &ComponentContext,
|
||||
render_params: &RenderParams,
|
||||
_style: &ComponentStyle,
|
||||
_parent_style: &ComponentStyle,
|
||||
) -> render_error::Result<()> {
|
||||
self.draw_control_buttons(
|
||||
// Control bar construct by draw circles, after drawn, the path will be at the center,
|
||||
|
|
76
generator/src/components/highlight_code_block.rs
Normal file
76
generator/src/components/highlight_code_block.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
use super::{
|
||||
interface::{component::Component, style::ComponentStyle},
|
||||
rect::EDITOR_PADDING,
|
||||
};
|
||||
use tiny_skia::{Color, Paint, Rect, Transform};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct HighlightCodeBlock {
|
||||
children: Vec<Box<dyn Component>>,
|
||||
line_height: f32,
|
||||
start_line_number: usize,
|
||||
end_line_number: usize,
|
||||
render_condition: bool,
|
||||
}
|
||||
|
||||
impl Component for HighlightCodeBlock {
|
||||
fn children(&self) -> &Vec<Box<dyn Component>> {
|
||||
&self.children
|
||||
}
|
||||
|
||||
fn render_condition(&self) -> bool {
|
||||
self.render_condition
|
||||
}
|
||||
|
||||
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,
|
||||
parent_style: &ComponentStyle,
|
||||
) -> super::interface::render_error::Result<()> {
|
||||
let mut paint = Paint::default();
|
||||
let start_y_offset = (self.start_line_number - 1) as f32 * self.line_height;
|
||||
|
||||
paint.anti_alias = false;
|
||||
paint.set_color(Color::from_rgba8(255, 255, 255, 18));
|
||||
pixmap.fill_rect(
|
||||
Rect::from_xywh(
|
||||
render_params.x - EDITOR_PADDING,
|
||||
render_params.y + start_y_offset,
|
||||
parent_style.width + EDITOR_PADDING * 2.,
|
||||
(self.end_line_number - self.start_line_number + 1) as f32 * self.line_height,
|
||||
)
|
||||
.unwrap(),
|
||||
&paint,
|
||||
Transform::from_scale(context.scale_factor, context.scale_factor),
|
||||
None,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HighlightCodeBlock {
|
||||
pub fn from_line_number(
|
||||
start_line_number: Option<usize>,
|
||||
end_line_number: Option<usize>,
|
||||
line_height: f32,
|
||||
) -> HighlightCodeBlock {
|
||||
if end_line_number < start_line_number {
|
||||
panic!("end_line_number should be greater than start_line_number")
|
||||
}
|
||||
|
||||
match start_line_number {
|
||||
Some(start_line_number) => HighlightCodeBlock {
|
||||
render_condition: true,
|
||||
children: vec![],
|
||||
line_height,
|
||||
start_line_number,
|
||||
end_line_number: end_line_number.unwrap(),
|
||||
},
|
||||
None => HighlightCodeBlock::default(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -70,6 +70,7 @@ pub trait Component {
|
|||
_context: &ComponentContext,
|
||||
_render_params: &RenderParams,
|
||||
_style: &ComponentStyle,
|
||||
_parent_style: &ComponentStyle,
|
||||
) -> render_error::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -113,13 +114,13 @@ pub trait Component {
|
|||
let style = self.parsed_style();
|
||||
let render_params = self.initialize(
|
||||
&component_render_params.parse_into_render_params_with_style(
|
||||
parent_style,
|
||||
parent_style.clone(),
|
||||
sibling_style,
|
||||
style.clone(),
|
||||
),
|
||||
);
|
||||
|
||||
self.draw_self(pixmap, context, &render_params, &style)?;
|
||||
self.draw_self(pixmap, context, &render_params, &style, &parent_style)?;
|
||||
|
||||
let children = self.children();
|
||||
let mut sibling_render_params = RenderParams {
|
||||
|
|
|
@ -44,6 +44,7 @@ impl Component for LineNumber {
|
|||
context: &ComponentContext,
|
||||
render_params: &RenderParams,
|
||||
style: &ComponentStyle,
|
||||
_parent_style: &ComponentStyle,
|
||||
) -> render_error::Result<()> {
|
||||
FontRenderer::new(
|
||||
FONT_SIZE,
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use crate::edges::padding::Padding;
|
||||
|
||||
use super::interface::{
|
||||
component::{Component, ComponentContext, RenderParams},
|
||||
render_error,
|
||||
style::{ComponentAlign, ComponentStyle, RawComponentStyle, Style},
|
||||
};
|
||||
use crate::edges::padding::Padding;
|
||||
use tiny_skia::{FillRule, Paint, PathBuilder, Pixmap, Transform};
|
||||
|
||||
pub const EDITOR_PADDING: f32 = 20.;
|
||||
|
||||
pub struct Rect {
|
||||
radius: f32,
|
||||
children: Vec<Box<dyn Component>>,
|
||||
|
@ -20,7 +21,7 @@ impl Component for Rect {
|
|||
fn style(&self) -> RawComponentStyle {
|
||||
Style::default()
|
||||
.align(ComponentAlign::Column)
|
||||
.padding(Padding::from_value(20.))
|
||||
.padding(Padding::from_value(EDITOR_PADDING))
|
||||
}
|
||||
|
||||
fn draw_self(
|
||||
|
@ -29,6 +30,7 @@ impl Component for Rect {
|
|||
context: &ComponentContext,
|
||||
render_params: &RenderParams,
|
||||
style: &ComponentStyle,
|
||||
_parent_style: &ComponentStyle,
|
||||
) -> render_error::Result<()> {
|
||||
let mut path_builder = PathBuilder::new();
|
||||
let x = render_params.x;
|
||||
|
|
|
@ -21,6 +21,7 @@ impl Component for Watermark {
|
|||
context: &ComponentContext,
|
||||
render_params: &RenderParams,
|
||||
_style: &ComponentStyle,
|
||||
_parent_style: &ComponentStyle,
|
||||
) -> render_error::Result<()> {
|
||||
let params = &context.take_snapshot_params;
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ pub struct TakeSnapshotParams {
|
|||
pub breadcrumbs_separator: String,
|
||||
pub has_breadcrumbs: bool,
|
||||
pub start_line_number: Option<usize>,
|
||||
pub highlight_start_line_number: Option<usize>,
|
||||
pub highlight_end_line_number: Option<usize>,
|
||||
}
|
||||
|
||||
impl FromObject for TakeSnapshotParams {
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::components::code_block::CodeBlock;
|
|||
use crate::components::container::Container;
|
||||
use crate::components::editor::code::Code;
|
||||
use crate::components::editor::mac_title_bar::MacTitleBar;
|
||||
use crate::components::highlight_code_block::HighlightCodeBlock;
|
||||
use crate::components::interface::component::ComponentContext;
|
||||
use crate::components::interface::render_error;
|
||||
use crate::components::line_number::LineNumber;
|
||||
|
@ -17,6 +18,7 @@ use crate::config::TakeSnapshotParams;
|
|||
|
||||
// Scale the screenshot to 3 times its size
|
||||
const SCALE_FACTOR: f32 = 3.;
|
||||
const LINE_HEIGHT: f32 = 20.;
|
||||
|
||||
// The params is come from neovim instance
|
||||
pub fn take_snapshot(params: TakeSnapshotParams) -> render_error::Result<Pixmap> {
|
||||
|
@ -36,8 +38,17 @@ pub fn take_snapshot(params: TakeSnapshotParams) -> render_error::Result<Pixmap>
|
|||
params.has_breadcrumbs,
|
||||
)),
|
||||
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(HighlightCodeBlock::from_line_number(
|
||||
params.highlight_start_line_number,
|
||||
params.highlight_end_line_number,
|
||||
LINE_HEIGHT,
|
||||
)),
|
||||
Box::new(LineNumber::new(
|
||||
¶ms.code,
|
||||
params.start_line_number,
|
||||
LINE_HEIGHT,
|
||||
)),
|
||||
Box::new(Code::new(params.code, LINE_HEIGHT, 15.)),
|
||||
])),
|
||||
],
|
||||
)),
|
||||
|
|
54
lua/codesnap/highlight.lua
Normal file
54
lua/codesnap/highlight.lua
Normal file
|
@ -0,0 +1,54 @@
|
|||
local string_utils = require("codesnap.utils.string")
|
||||
local table_utils = require("codesnap.utils.table")
|
||||
local highlight_module = {}
|
||||
|
||||
function highlight_module.call_cb_with_parsed_config(cb_name, highlight_start_line_number, highlight_end_line_number)
|
||||
vim.api.nvim_buf_delete(0, {})
|
||||
vim.schedule(function()
|
||||
local main = require("codesnap")
|
||||
local config = table_utils.merge(main.highlight_mode_config, {
|
||||
highlight_start_line_number = highlight_start_line_number,
|
||||
highlight_end_line_number = highlight_end_line_number,
|
||||
})
|
||||
|
||||
main[cb_name](config)
|
||||
end)
|
||||
end
|
||||
|
||||
function highlight_module.create_highlight_selector_window(cb_name, code)
|
||||
local width = 100
|
||||
local height = 20
|
||||
local row = vim.fn.winheight(0) / 2 - height / 2
|
||||
local col = vim.fn.winwidth(0) / 2 - width / 2
|
||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, string_utils.split(code, "\n"))
|
||||
local window_id = vim.api.nvim_open_win(bufnr, false, {
|
||||
relative = "editor",
|
||||
width = width,
|
||||
height = height,
|
||||
col = col,
|
||||
row = row,
|
||||
style = "minimal",
|
||||
border = "rounded",
|
||||
title = "Select the code needs to be highlighted",
|
||||
title_pos = "center",
|
||||
})
|
||||
|
||||
vim.api.nvim_buf_set_option(bufnr, "modifiable", false)
|
||||
vim.api.nvim_buf_set_option(bufnr, "filetype", vim.bo.filetype)
|
||||
vim.api.nvim_buf_set_keymap(bufnr, "n", "q", ":q<CR>", {})
|
||||
vim.api.nvim_buf_set_keymap(bufnr, "", "<ESC>", ":q<CR>", {})
|
||||
vim.api.nvim_buf_set_keymap(
|
||||
bufnr,
|
||||
"v",
|
||||
"<CR>",
|
||||
":lua require('codesnap.highlight').call_cb_with_parsed_config('"
|
||||
.. cb_name
|
||||
.. "', require('codesnap.utils.visual').get_start_line_number(), require('codesnap.utils.visual').get_end_line_number())<CR>",
|
||||
{ silent = true }
|
||||
)
|
||||
vim.api.nvim_set_current_win(window_id)
|
||||
end
|
||||
|
||||
return highlight_module
|
|
@ -2,23 +2,25 @@ local static = require("codesnap.static")
|
|||
local table_utils = require("codesnap.utils.table")
|
||||
local string_utils = require("codesnap.utils.string")
|
||||
local config_module = require("codesnap.config")
|
||||
local highlight_module = require("codesnap.highlight")
|
||||
|
||||
local main = {
|
||||
cwd = static.cwd,
|
||||
preview_switch = static.preview_switch,
|
||||
highlight_mode_config = nil,
|
||||
}
|
||||
|
||||
function main.setup(config)
|
||||
static.config = table_utils.merge(static.config, config == nil and {} or config)
|
||||
end
|
||||
|
||||
function main.copy_into_clipboard(extension)
|
||||
require("generator").copy_into_clipboard(config_module.get_config(extension))
|
||||
function main.copy_into_clipboard_with_config(config)
|
||||
require("generator").copy_into_clipboard(config)
|
||||
vim.cmd("delmarks <>")
|
||||
vim.notify("Save snapshot into clipboard successfully")
|
||||
end
|
||||
|
||||
function main.save_snapshot(extension)
|
||||
function main.save_snapshot_with_config(config)
|
||||
if string_utils.is_str_empty(static.config.save_path) then
|
||||
error(
|
||||
"If you want to save snapshot in somewhere, you should config the save_path before, refer: https://github.com/mistricky/codesnap.nvim?tab=readme-ov-file#save-the-snapshot",
|
||||
|
@ -32,12 +34,32 @@ function main.save_snapshot(extension)
|
|||
error("The extension of save_path should be .png", 0)
|
||||
end
|
||||
|
||||
local config = config_module.get_config(extension)
|
||||
|
||||
require("generator").save_snapshot(config)
|
||||
vim.cmd("delmarks <>")
|
||||
---@diagnostic disable-next-line: need-check-nil
|
||||
vim.notify("Save snapshot in " .. config.save_path .. " successfully")
|
||||
end
|
||||
|
||||
-- Take a snapshot and copy it into clipboard
|
||||
function main.copy_into_clipboard(extension)
|
||||
main.copy_into_clipboard_with_config(config_module.get_config(extension))
|
||||
end
|
||||
|
||||
-- Take a snapshot and save it into the specified path
|
||||
function main.save_snapshot(extension)
|
||||
main.save_snapshot_with_config(config_module.get_config(extension))
|
||||
end
|
||||
|
||||
function main.highlight_mode_copy_into_clipboard(extension)
|
||||
main.highlight_mode_config = config_module.get_config(extension)
|
||||
|
||||
highlight_module.create_highlight_selector_window("copy_into_clipboard_with_config", main.highlight_mode_config.code)
|
||||
end
|
||||
|
||||
function main.highlight_mode_save_snapshot(extension)
|
||||
main.highlight_mode_config = config_module.get_config(extension)
|
||||
|
||||
highlight_module.create_highlight_selector_window("save_snapshot_with_config", main.highlight_mode_config.code)
|
||||
end
|
||||
|
||||
return main
|
||||
|
|
|
@ -24,4 +24,14 @@ function string_util.convert_empty_to_nil(target)
|
|||
end
|
||||
end
|
||||
|
||||
function string_util.split(str, delimiter)
|
||||
local result = {}
|
||||
|
||||
for token in string.gmatch(str, "[^" .. delimiter .. "]+") do
|
||||
table.insert(result, token)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
return string_util
|
||||
|
|
|
@ -33,7 +33,7 @@ end
|
|||
|
||||
function table_utils.serialize_array(t)
|
||||
local result = list_utils.map(t, function(ele)
|
||||
table_utils.serialize_json(ele)
|
||||
table_utils.to_string(ele)
|
||||
end)
|
||||
|
||||
return "[" .. result.concat(t, ",") .. "]"
|
||||
|
@ -43,17 +43,17 @@ function table_utils.serialize_table(t)
|
|||
local result = {}
|
||||
|
||||
for key, value in pairs(t) do
|
||||
table.insert(result, string.format('"%s":%s', key, table_utils.serialize_json(value)))
|
||||
table.insert(result, string.format("%s = %s", key, table_utils.to_string(value)))
|
||||
end
|
||||
|
||||
return "{" .. table.concat(result, ",") .. "}"
|
||||
end
|
||||
|
||||
function table_utils.serialize_string(value)
|
||||
return '"' .. value .. '"'
|
||||
return "[[" .. value .. "]]"
|
||||
end
|
||||
|
||||
function table_utils.serialize_json(t)
|
||||
function table_utils.to_string(t)
|
||||
local complex_type_parser = {
|
||||
array = table_utils.serialize_array,
|
||||
table = table_utils.serialize_table,
|
||||
|
@ -67,4 +67,14 @@ function table_utils.serialize_json(t)
|
|||
return parse(t)
|
||||
end
|
||||
|
||||
-- function table_utils.to_string(t)
|
||||
-- local result = ""
|
||||
--
|
||||
-- for key, value in pairs(t) do
|
||||
-- result = result .. key .. ":" .. tostring(value) .. ","
|
||||
-- end
|
||||
--
|
||||
-- return "{" .. result .. "}"
|
||||
-- end
|
||||
|
||||
return table_utils
|
||||
|
|
|
@ -18,6 +18,10 @@ function visual_utils.get_start_line_number()
|
|||
return vim.fn.line("'<")
|
||||
end
|
||||
|
||||
function visual_utils.get_end_line_number()
|
||||
return vim.fn.line("'>")
|
||||
end
|
||||
|
||||
function visual_utils.get_selected_text()
|
||||
local selected_text = vim.fn.getline("'<", "'>")
|
||||
|
||||
|
|
|
@ -22,3 +22,15 @@ end
|
|||
vim.api.nvim_create_user_command("CodeSnap", take_snapshot(codesnap.copy_into_clipboard), { nargs = "*", range = "%" })
|
||||
|
||||
vim.api.nvim_create_user_command("CodeSnapSave", take_snapshot(codesnap.save_snapshot), { nargs = "*", range = "%" })
|
||||
|
||||
vim.api.nvim_create_user_command(
|
||||
"CodeSnapHighlight",
|
||||
take_snapshot(codesnap.highlight_mode_copy_into_clipboard),
|
||||
{ nargs = "*", range = "%" }
|
||||
)
|
||||
|
||||
vim.api.nvim_create_user_command(
|
||||
"CodeSnapSaveHighlight",
|
||||
take_snapshot(codesnap.highlight_mode_save_snapshot),
|
||||
{ nargs = "*", range = "%" }
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue