Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add supports for take code snapshot with highlighted code block #92

Merged
merged 6 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,25 @@ require("codesnap").setup({

https://github.com/mistricky/codesnap.nvim/assets/22574136/69b27e77-3dce-4bc3-8516-89ce636fe02d

### Highlight code block

CodeSnap allows you to take code snapshots with highlights code blocks, we provide two commands for this scenario:

```shell
CodeSnapHighlight # Take code snapshot with highlights code blocks and copy it into the clipboard
CodeSnapSaveHighlight # Take code snapshot with highlights code blocks and save it somewhere
```

#### How to use
For take a code snapshot with highlights code blocks and save it somewhere. First you need to select code which you want to snapshot, then enter the command `CodeSnapSaveHighlight` to open a window show you the selected code which from previous step, now you can select code which you want to highlight, finally press the Enter key, CodeSnap will generate a snapshot with highlight blocks and save it in save_path.

Here is an example video:

https://github.com/mistricky/codesnap.nvim/assets/22574136/bea0bf6c-8fc9-4d09-9cab-4e1e6f47899c




### Specify language extension
In some scenarios, CodeSnap.nvim cannot auto-detect what language syntax should used to highlight code, for example, shell script can have no extension, they specify interpreters using shebang.

Expand Down
1 change: 1 addition & 0 deletions generator/src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions generator/src/components/background.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion generator/src/components/breadcrumbs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions generator/src/components/editor/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions generator/src/components/editor/mac_title_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
76 changes: 76 additions & 0 deletions generator/src/components/highlight_code_block.rs
Original file line number Diff line number Diff line change
@@ -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, 10));
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(),
}
}
}
5 changes: 3 additions & 2 deletions generator/src/components/interface/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub trait Component {
_context: &ComponentContext,
_render_params: &RenderParams,
_style: &ComponentStyle,
_parent_style: &ComponentStyle,
) -> render_error::Result<()> {
Ok(())
}
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions generator/src/components/line_number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 5 additions & 3 deletions generator/src/components/rect.rs
Original file line number Diff line number Diff line change
@@ -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>>,
Expand All @@ -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(
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions generator/src/components/watermark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 2 additions & 0 deletions generator/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
15 changes: 13 additions & 2 deletions generator/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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> {
Expand All @@ -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(&params.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(
&params.code,
params.start_line_number,
LINE_HEIGHT,
)),
Box::new(Code::new(params.code, LINE_HEIGHT, 15.)),
])),
],
)),
Expand Down
55 changes: 55 additions & 0 deletions lua/codesnap/highlight.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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 = #code + 2
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, code)

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 highlight lines",
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
36 changes: 31 additions & 5 deletions lua/codesnap/init.lua
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
local static = require("codesnap.static")
local visual_utils = require("codesnap.utils.visual")
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",
Expand All @@ -32,12 +35,35 @@ 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",
visual_utils.get_selected_lines()
)
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", visual_utils.get_selected_lines())
end

return main
Loading
Loading