diff --git a/.github/workflows/contributor_list.yml b/.github/workflows/contributor_list.yml new file mode 100644 index 0000000..346ffe1 --- /dev/null +++ b/.github/workflows/contributor_list.yml @@ -0,0 +1,19 @@ +name: Auto Generate Contributor List + +on: + push: + branches: + main + +permissions: + contents: write + +jobs: + generate-contributor-list: + name: Auto generate contributor list + runs-on: ubuntu-latest + steps: + - uses: wow-actions/contributors-list@v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + svgPath: CONTRIBUTORS.svg diff --git a/.github/workflows/generate_toc.yml b/.github/workflows/generate_toc.yml new file mode 100644 index 0000000..4a26134 --- /dev/null +++ b/.github/workflows/generate_toc.yml @@ -0,0 +1,21 @@ +name: Generate TOC + +on: + push: + paths: + README.md + branches: + main + +permissions: + contents: write + +jobs: + generate-toc: + name: TOC Generator + runs-on: ubuntu-latest + steps: + - uses: technote-space/toc-generator@v4 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TOC_TITLE: '' diff --git a/CONTRIBUTORS.svg b/CONTRIBUTORS.svg new file mode 100644 index 0000000..cad2e85 --- /dev/null +++ b/CONTRIBUTORS.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 571dfa8..d565a30 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,66 @@

-Neovim - -made with lua +Neovim release action status release action status + + Issues + + + License + + + stars + + +made with lua + +written in rust + + + + +

CodeSnap.nvim

📸 Snapshot plugin with rich features that can make pretty code snapshots for Neovim

+ + + +- [🚣Migration](#migration) +- [✨Features](#features) +- [Prerequirements](#prerequirements) +- [Install](#install) + - [Compile from source](#compile-from-source) + - [Compile on ARM](#compile-on-arm) + - [Keymappings](#keymappings) +- [Usage](#usage) + - [Copy into the clipboard](#copy-into-the-clipboard) + - [Copy into clipboard on Linux Wayland](#copy-into-clipboard-on-linux-wayland) + - [Save the snapshot](#save-the-snapshot) + - [Highlight code block](#highlight-code-block) + - [How to use](#how-to-use) + - [Specify language extension](#specify-language-extension) +- [Breadcrumbs](#breadcrumbs) + - [Show workspace in breadcrumbs](#show-workspace-in-breadcrumbs) + - [Custom path separator](#custom-path-separator) +- [Line number](#line-number) +- [Custom background](#custom-background) + - [Solid color background](#solid-color-background) +- [Watermark](#watermark) +- [Commands](#commands) +- [Configuration](#configuration) +- [Contribution](#contribution) + - [Contributors](#contributors) +- [License](#license) + + ## 🚣Migration If you have installed v0.x before, this chapter will show you what break changes version v1.x introduced. @@ -34,7 +81,7 @@ v1.x has a different architecture and better performance than v0.x, and v1.x can - 🤖 Generate snapshots using only a single command - 🍞 Breadcrumbs for display file path - 🌊 More beautiful background theme -- 🔢 [WIP] Column number +- 🔢 Support for display line number make sharing code snapshot easier ## Prerequirements - Neovim 0.9.0+ @@ -85,6 +132,24 @@ sudo dnf install libuv libuv-devel # On RHEL based systems sudo apt-get install libtool libuv1-dev # On Debian based systems ``` +### Keymappings +If you use `Lazy.nvim` as your package manager, here are some examples show you how to configure keymappings for CodeSnap: +```lua +{ + "mistricky/codesnap.nvim", + build = "make build_generator", + keys = { + { "cc", "CodeSnap", mode = "x", desc = "Save selected code snapshot into clipboard" }, + { "cs", "CodeSnapSave", mode = "x", desc = "Save selected code snapshot in ~/Pictures" }, + }, + opts = { + save_path = "~/Pictures", + has_breadcrumbs = true, + bg_theme = "bamboo", + }, +} +``` + ## Usage `CodeSnap.nvim` provides the following two ways to take snapshots of currently selected code @@ -122,6 +187,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. @@ -144,6 +228,16 @@ require("codesnap").setup({ The breadcrumbs look like: ![image](https://github.com/mistricky/codesnap.nvim/assets/22574136/23274faa-36a9-4d41-88a5-e48c44b4d5bf) +### Show workspace in breadcrumbs +Breadcrumbs hide the workspace name by default, if you want to display workspace in breadcrumbs, you can just set `show_workspace` as true. +```lua +require("codesnap").setup({ + -- ... + has_breadcrumbs = true + show_workspace = true +}) +``` + ### Custom path separator The CodeSnap.nvim uses `/` as the separator of the file path by default, of course, you can specify any symbol you prefer as the custom separator: ```lua @@ -157,6 +251,17 @@ require("codesnap").setup({ ![image](https://github.com/mistricky/codesnap.nvim/assets/22574136/84b80d0f-1467-4bdf-9cbd-aede868f93aa) +## Line number +We also support displaying line number, you can set `has_line_number` to true to display line number. +```lua +require("codesnap").setup({ + // ... + has_line_number = true, +}) +``` + +![image](https://github.com/mistricky/codesnap.nvim/assets/22574136/3a5999b1-bb2a-4646-8d69-609be1d28140) + ## Custom background The `CodeSnap.nvim` comes with many beautiful backgrounds preset, you can set any background you like by setting `bg_theme` to its name, just like: @@ -236,6 +341,16 @@ CodeSnap # Take a snapshot of the currently selected code and copy the snapshot CodeSnapSave # Save the snapshot of the currently selected code and save it on the disk ``` +**Lua** +```lua +local codesnap = require("codesnap") + +-- Take a snapshot of the currently selected code and copy the snapshot into the clipboard +codesnap.copy_into_clipboard() + +-- Save the snapshot of the currently selected code and save it on the disk +codesnap.save_snapshot() +``` ## Configuration Define your custom config using `setup` function @@ -254,6 +369,8 @@ There is a default config: bg_theme = "default", breadcrumbs_separator = "/", has_breadcrumbs = false, + has_line_number = false, + min_width = 0 } ``` @@ -262,5 +379,10 @@ CodeSnap.nvim is a project that will be maintained for the long term, and we alw The commit message convention of this project is following [commitlint-wizardoc](https://github.com/wizardoc/commitlint-wizardoc). +### Contributors +Thanks to all contributors for their contributions and works they have done. + + + ## License MIT. diff --git a/doc/plugin-name.txt b/doc/plugin-name.txt index ed33c2f..0e473b7 100644 --- a/doc/plugin-name.txt +++ b/doc/plugin-name.txt @@ -1,4 +1,4 @@ **codesnap.nvim** 📸 Snapshot plugin that can make pretty code snapshots with real-time previews for Neovim Author: Mist -version: 1.1.12 +version: 1.3.1 diff --git a/generator/Cargo.lock b/generator/Cargo.lock index 06a04d1..90603f3 100644 --- a/generator/Cargo.lock +++ b/generator/Cargo.lock @@ -8,6 +8,18 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -17,6 +29,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "arboard" version = "3.3.2" @@ -87,7 +105,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.52", ] [[package]] @@ -120,6 +138,39 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cached" +version = "0.49.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8e463fceca5674287f32d252fb1d94083758b8709c160efae66d263e5f4eba" +dependencies = [ + "ahash", + "cached_proc_macro", + "cached_proc_macro_types", + "hashbrown", + "instant", + "once_cell", + "thiserror", +] + +[[package]] +name = "cached_proc_macro" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9f16c0d84de31a2ab7fdf5f7783c14631f7075cf464eb3bb43119f61c9cb2a" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" + [[package]] name = "cc" version = "1.0.90" @@ -245,6 +296,41 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + [[package]] name = "deranged" version = "0.3.11" @@ -262,7 +348,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.52", ] [[package]] @@ -386,7 +472,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.52", ] [[package]] @@ -400,6 +486,7 @@ name = "generator" version = "0.1.0" dependencies = [ "arboard", + "cached", "cosmic-text", "nvim-oxi", "regex", @@ -433,6 +520,10 @@ name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "home" @@ -443,6 +534,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "image" version = "0.24.9" @@ -467,6 +564,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "1.0.10" @@ -762,7 +868,7 @@ checksum = "7fa77de5791207f41bab307dadb91e66a2bbbd19433e4243ef98c9d45e03a007" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.52", ] [[package]] @@ -1033,7 +1139,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.52", ] [[package]] @@ -1055,7 +1161,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.52", ] [[package]] @@ -1091,6 +1197,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "swash" version = "0.1.12" @@ -1102,6 +1214,17 @@ dependencies = [ "zeno", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.52" @@ -1183,7 +1306,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.52", ] [[package]] @@ -1669,3 +1792,23 @@ name = "zeno" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] diff --git a/generator/Cargo.toml b/generator/Cargo.toml index 1d298fa..8ddc8d8 100644 --- a/generator/Cargo.toml +++ b/generator/Cargo.toml @@ -13,6 +13,7 @@ arboard = {features = ["wayland-data-control"], version = "3.3.2"} thiserror = "1.0.58" regex = "1.10.3" two-face = "0.3.0" +cached = "0.49.3" wsl = "0.1.0" sys-info = "0.9.1" diff --git a/generator/src/code.rs b/generator/src/code.rs index c1e6cde..2b0849a 100644 --- a/generator/src/code.rs +++ b/generator/src/code.rs @@ -1,6 +1,8 @@ +use cached::proc_macro::cached; use regex::Regex; const MIN_WIDTH: f32 = 100.; +pub const CHAR_WIDTH: f32 = 9.05; fn min_width(width: f32) -> f32 { if width < MIN_WIDTH { @@ -10,6 +12,9 @@ fn min_width(width: f32) -> f32 { } } +// Because the code block is input by users, we need to calculate the width and height +// to make sure render the width and height of the "editor" shape correctly +#[cached(key = "String", convert = r#"{ format!("{}", text) }"#)] pub fn calc_wh(text: &str, char_wdith: f32, line_height: f32) -> (f32, f32) { let trimmed_text = prepare_code(text); let lines = trimmed_text.lines(); @@ -34,29 +39,33 @@ fn replace_tab_to_space(text: &str) -> String { str::replace(text, "\t", &spaces) } -// If the first line have indention, remove the same indention from subsequent lines +// Find min indention of code lines, and remove the same indention from subsequent lines fn trim_space(text: &str) -> String { let lines = text.split("\n").collect::>(); - let first_line = lines.first().unwrap(); - let head_spaces = Regex::new(r"^(\s*)").unwrap().find(first_line); + let regex = Regex::new(r"(?:^|\n)(\s*)").unwrap(); + let captures_iter = regex.captures_iter(text); + let space_lengths = captures_iter + .map(|capture| capture.get(1).unwrap().as_str().len()) + .collect::>(); - 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::>() - .join("\n"); - } - None => text.to_string(), + if space_lengths.len() < lines.len() { + return text.to_string(); } + + let need_to_remove_spaces = " ".repeat(space_lengths.into_iter().min().unwrap()); + + lines + .into_iter() + .map(|line| { + Regex::new(format!("^{}", need_to_remove_spaces).as_ref()) + .unwrap() + .replace(line, "") + .to_string() + }) + .collect::>() + .join("\n") } pub fn prepare_code(code: &str) -> String { - replace_tab_to_space(&trim_space(&code)) + trim_space(&replace_tab_to_space(&code)) } diff --git a/generator/src/components.rs b/generator/src/components.rs index c14e6db..6a31557 100644 --- a/generator/src/components.rs +++ b/generator/src/components.rs @@ -1,7 +1,10 @@ pub mod background; 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; pub mod watermark; diff --git a/generator/src/components/background.rs b/generator/src/components/background.rs index 8b4ca83..6fa69e2 100644 --- a/generator/src/components/background.rs +++ b/generator/src/components/background.rs @@ -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; diff --git a/generator/src/components/breadcrumbs.rs b/generator/src/components/breadcrumbs.rs index e096dda..a41d44b 100644 --- a/generator/src/components/breadcrumbs.rs +++ b/generator/src/components/breadcrumbs.rs @@ -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() diff --git a/generator/src/components/code_block.rs b/generator/src/components/code_block.rs new file mode 100644 index 0000000..d103ba8 --- /dev/null +++ b/generator/src/components/code_block.rs @@ -0,0 +1,29 @@ +use crate::edges::margin::Margin; + +use super::interface::{ + component::Component, + style::{RawComponentStyle, Style}, +}; + +pub struct CodeBlock { + children: Vec>, +} + +impl Component for CodeBlock { + fn children(&self) -> &Vec> { + &self.children + } + + fn style(&self) -> RawComponentStyle { + Style::default().margin(Margin { + top: 10., + ..Margin::default() + }) + } +} + +impl CodeBlock { + pub fn from_children(children: Vec>) -> CodeBlock { + CodeBlock { children } + } +} diff --git a/generator/src/components/editor/code.rs b/generator/src/components/editor/code.rs index 40f8c06..7219d44 100644 --- a/generator/src/components/editor/code.rs +++ b/generator/src/components/editor/code.rs @@ -1,11 +1,10 @@ use crate::{ - code::{calc_wh, prepare_code}, + code::{calc_wh, prepare_code, CHAR_WIDTH}, components::interface::{ component::{Component, ComponentContext, RenderParams}, render_error, style::{ComponentStyle, RawComponentStyle, Size, Style}, }, - edges::margin::Margin, highlight::Highlight, text::FontRenderer, }; @@ -23,14 +22,9 @@ impl Component for Code { } 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() - .size(Size::Num(w), Size::Num(h)) - .margin(Margin { - top: 10., - ..Margin::default() - }) + Style::default().size(Size::Num(w), Size::Num(h)) } fn draw_self( @@ -39,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( diff --git a/generator/src/components/editor/mac_title_bar.rs b/generator/src/components/editor/mac_title_bar.rs index acf67c2..e112ad3 100644 --- a/generator/src/components/editor/mac_title_bar.rs +++ b/generator/src/components/editor/mac_title_bar.rs @@ -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, diff --git a/generator/src/components/highlight_code_block.rs b/generator/src/components/highlight_code_block.rs new file mode 100644 index 0000000..cbefc09 --- /dev/null +++ b/generator/src/components/highlight_code_block.rs @@ -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>, + line_height: f32, + start_line_number: usize, + end_line_number: usize, + render_condition: bool, +} + +impl Component for HighlightCodeBlock { + fn children(&self) -> &Vec> { + &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, + end_line_number: Option, + 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(), + } + } +} diff --git a/generator/src/components/interface/component.rs b/generator/src/components/interface/component.rs index 2bef71a..0275748 100644 --- a/generator/src/components/interface/component.rs +++ b/generator/src/components/interface/component.rs @@ -1,13 +1,10 @@ -use std::sync::Arc; - -use tiny_skia::Pixmap; - -use crate::{config::TakeSnapshotParams, edges::edge::Edge}; - use super::{ render_error, style::{ComponentAlign, ComponentStyle, RawComponentStyle, Size, Style}, }; +use crate::{config::TakeSnapshotParams, edges::edge::Edge}; +use std::sync::Arc; +use tiny_skia::Pixmap; pub struct ComponentContext { pub scale_factor: f32, @@ -73,6 +70,7 @@ pub trait Component { _context: &ComponentContext, _render_params: &RenderParams, _style: &ComponentStyle, + _parent_style: &ComponentStyle, ) -> render_error::Result<()> { Ok(()) } @@ -91,11 +89,17 @@ pub trait Component { fn parsed_style(&self) -> Style { let style = self.style(); let (width, height) = self.get_dynamic_wh(); + let width = self.parse_size(style.width, width) + + style.padding.horizontal() + + style.margin.horizontal(); Style { - width: self.parse_size(style.width, width) - + style.padding.horizontal() - + style.margin.horizontal(), + min_width: style.min_width, + width: if width > style.min_width { + width + } else { + style.min_width + }, height: self.parse_size(style.height, height) + style.padding.vertical() + style.margin.vertical(), @@ -116,13 +120,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 { @@ -152,6 +156,8 @@ pub trait Component { Ok(render_params.clone()) } + // Dynamic calculate width and height of children, if the children is empty, get_dynamic_wh + // will return (0., 0.) fn get_dynamic_wh(&self) -> (f32, f32) { let children = self.children(); let calc_children_wh = |cb: fn((f32, f32), &Box) -> (f32, f32)| { @@ -160,11 +166,13 @@ pub trait Component { let style = self.style(); match style.align { + // If align is row, width is sum of children width, height is max of children height ComponentAlign::Row => calc_children_wh(|(w, h), child| { let style = child.parsed_style(); (w + style.width, h.max(style.height)) }), + // If align is column, width is max of children width, height is sum of children height ComponentAlign::Column => calc_children_wh(|(w, h), child| { let style = child.parsed_style(); diff --git a/generator/src/components/interface/style.rs b/generator/src/components/interface/style.rs index 94a6f09..bdc5fec 100644 --- a/generator/src/components/interface/style.rs +++ b/generator/src/components/interface/style.rs @@ -15,6 +15,7 @@ pub enum Size { pub struct Style { pub width: T, pub height: T, + pub min_width: f32, pub align: ComponentAlign, pub padding: Padding, pub margin: Margin, @@ -26,6 +27,7 @@ pub type ComponentStyle = Style; impl Default for RawComponentStyle { fn default() -> Self { Style { + min_width: 0., width: Size::Dynamic, height: Size::Dynamic, align: ComponentAlign::Row, @@ -38,6 +40,7 @@ impl Default for RawComponentStyle { impl Default for ComponentStyle { fn default() -> Self { Style { + min_width: 0., width: 0., height: 0., align: ComponentAlign::Row, @@ -54,6 +57,12 @@ impl RawComponentStyle { self } + // Only works if the width is calculate dynamically + pub fn min_width(mut self, min_width: f32) -> Self { + self.min_width = min_width; + self + } + pub fn align(mut self, align: ComponentAlign) -> Self { self.align = align; self diff --git a/generator/src/components/line_number.rs b/generator/src/components/line_number.rs new file mode 100644 index 0000000..b2a9ca1 --- /dev/null +++ b/generator/src/components/line_number.rs @@ -0,0 +1,100 @@ +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>, + line_height: f32, + render_condition: bool, + line_number_content: Vec, + number_of_digit: usize, +} + +impl Component for LineNumber { + fn render_condition(&self) -> bool { + return self.render_condition; + } + + fn children(&self) -> &Vec> { + &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, + _parent_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, line_height: f32) -> LineNumber { + match start_line_number { + None => LineNumber::default(), + Some(start_line_number) => { + let lines = content.split("\n").collect::>(); + 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::>(), + number_of_digit, + children: vec![], + render_condition: true, + line_height, + } + } + } + } +} diff --git a/generator/src/components/rect.rs b/generator/src/components/rect.rs index 2fdc489..dd97b2d 100644 --- a/generator/src/components/rect.rs +++ b/generator/src/components/rect.rs @@ -1,14 +1,16 @@ -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, + min_width: f32, children: Vec>, } @@ -19,8 +21,9 @@ impl Component for Rect { fn style(&self) -> RawComponentStyle { Style::default() + .min_width(self.min_width) .align(ComponentAlign::Column) - .padding(Padding::from_value(20.)) + .padding(Padding::from_value(EDITOR_PADDING)) } fn draw_self( @@ -29,6 +32,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; @@ -92,7 +96,11 @@ impl Component for Rect { } impl Rect { - pub fn new(radius: f32, children: Vec>) -> Rect { - Rect { radius, children } + pub fn new(radius: f32, min_width: Option, children: Vec>) -> Rect { + Rect { + radius, + children, + min_width: min_width.unwrap_or(0.), + } } } diff --git a/generator/src/components/watermark.rs b/generator/src/components/watermark.rs index 8007413..7cb6f8a 100644 --- a/generator/src/components/watermark.rs +++ b/generator/src/components/watermark.rs @@ -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; diff --git a/generator/src/config.rs b/generator/src/config.rs index c1e955a..8b6158e 100644 --- a/generator/src/config.rs +++ b/generator/src/config.rs @@ -26,6 +26,10 @@ pub struct TakeSnapshotParams { pub file_path: String, pub breadcrumbs_separator: String, pub has_breadcrumbs: bool, + pub start_line_number: Option, + pub highlight_start_line_number: Option, + pub highlight_end_line_number: Option, + pub min_width: Option, } impl FromObject for TakeSnapshotParams { diff --git a/generator/src/highlight.rs b/generator/src/highlight.rs index 3d2096f..3df50e1 100644 --- a/generator/src/highlight.rs +++ b/generator/src/highlight.rs @@ -53,6 +53,9 @@ impl Highlight { ))?, }; + // The Syntect clearly distinguish between PHP and PHP Source + // Should use PHP as highlight language if the source content contains " attrs.weight(Weight::BOLD), + FontStyle::ITALIC => attrs.style(Style::Italic), + FontStyle::UNDERLINE => attrs.style(Style::Normal), + _ => attrs, + }; + + (str, attrs.color(cosmic_text::Color::rgb(r, g, b))) + }) + .collect::() + }) .fold(vec![], |acc, cur| [acc, cur].concat()) .into_iter() - .map(move |(style, str)| { - let syntect::highlighting::Color { r, g, b, a: _ } = style.foreground; - let attrs = match style.font_style { - FontStyle::BOLD => attrs.weight(Weight::BOLD), - FontStyle::ITALIC => attrs.style(Style::Italic), - FontStyle::UNDERLINE => attrs.style(Style::Normal), - _ => attrs, - }; - - (str, attrs.color(cosmic_text::Color::rgb(r, g, b))) - }) .collect::()) } } diff --git a/generator/src/snapshot.rs b/generator/src/snapshot.rs index daeb410..cbf14bc 100644 --- a/generator/src/snapshot.rs +++ b/generator/src/snapshot.rs @@ -4,17 +4,21 @@ use tiny_skia::Pixmap; use crate::components::background::Background; use crate::components::breadcrumbs::Breadcrumbs; +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; use crate::components::rect::Rect; use crate::components::watermark::Watermark; 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 { @@ -25,6 +29,7 @@ pub fn take_snapshot(params: TakeSnapshotParams) -> render_error::Result let pixmap = Container::from_children(vec![Box::new(Background::from_children(vec![ Box::new(Rect::new( 16., + params.min_width, vec![ Box::new(MacTitleBar::from_radius(8., params.mac_window_bar)), Box::new(Breadcrumbs::from_path( @@ -33,7 +38,19 @@ pub fn take_snapshot(params: TakeSnapshotParams) -> render_error::Result params.breadcrumbs_separator, params.has_breadcrumbs, )), - Box::new(Code::new(params.code, 20., 15.)), + Box::new(CodeBlock::from_children(vec![ + 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.)), + ])), ], )), Box::new(Watermark::new(params.watermark)), diff --git a/lua/codesnap/client.lua b/lua/codesnap/client.lua deleted file mode 100644 index c0ec413..0000000 --- a/lua/codesnap/client.lua +++ /dev/null @@ -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 diff --git a/lua/codesnap/config.lua b/lua/codesnap/config.lua index 0d7cded..a91121b 100644 --- a/lua/codesnap/config.lua +++ b/lua/codesnap/config.lua @@ -25,8 +25,15 @@ local function parse_save_path(save_path) return parsed_save_path .. auto_generate_snap_filename() end +local function get_file_path(show_workspace) + local relative_path = path_utils.get_relative_path() + + return show_workspace and path_utils.get_workspace() .. "/" .. relative_path or relative_path +end + function config_module.get_config(extension) 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 error("No code is selected", 0) @@ -40,7 +47,8 @@ function config_module.get_config(extension) fonts_folder = assets_folder .. "/fonts", themes_folder = assets_folder .. "/themes", theme = "base16-onedark", - file_path = static.config.has_breadcrumbs and path_utils.get_relative_path() or "", + file_path = static.config.has_breadcrumbs and get_file_path(static.config.show_workspace) or "", + start_line_number = static.config.has_line_number and start_line_number or nil, }, static.config) config.save_path = parse_save_path(config.save_path) diff --git a/lua/codesnap/highlight.lua b/lua/codesnap/highlight.lua new file mode 100644 index 0000000..7f7c952 --- /dev/null +++ b/lua/codesnap/highlight.lua @@ -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", {}) + vim.api.nvim_buf_set_keymap(bufnr, "", "", ":q", {}) + vim.api.nvim_buf_set_keymap( + bufnr, + "v", + "", + ":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())", + { silent = true } + ) + vim.api.nvim_set_current_win(window_id) +end + +return highlight_module diff --git a/lua/codesnap/init.lua b/lua/codesnap/init.lua index 8340208..2b3f2ea 100644 --- a/lua/codesnap/init.lua +++ b/lua/codesnap/init.lua @@ -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", @@ -32,11 +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 diff --git a/lua/codesnap/static.lua b/lua/codesnap/static.lua index 518158e..4ae9869 100644 --- a/lua/codesnap/static.lua +++ b/lua/codesnap/static.lua @@ -10,6 +10,9 @@ return { bg_theme = "default", breadcrumbs_separator = "/", has_breadcrumbs = false, + has_line_number = false, + show_workspace = false, + min_width = 0, }, cwd = path_utils.back(path_utils.back(debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])"))), preview_switch = true, diff --git a/lua/codesnap/utils/logger.lua b/lua/codesnap/utils/logger.lua deleted file mode 100644 index 168de3a..0000000 --- a/lua/codesnap/utils/logger.lua +++ /dev/null @@ -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 diff --git a/lua/codesnap/utils/path.lua b/lua/codesnap/utils/path.lua index ebf4a54..6318c3e 100644 --- a/lua/codesnap/utils/path.lua +++ b/lua/codesnap/utils/path.lua @@ -1,17 +1,29 @@ local string_utils = require("codesnap.utils.string") local path_utils = {} +function path_utils.get_escaped_cwd() + local cwd = vim.fn.getcwd() + + return string_utils.escape(cwd) +end + function path_utils.back(path) local parsed_path, _ = path:gsub("/[^\\/]+/?$", "") return parsed_path end +function path_utils.get_workspace() + local cwd = vim.fn.getcwd() + local _, _, workspace = string.find(cwd, "/([^/]+)$") + + return workspace == nil and "" or workspace +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) + return full_file_path:gsub(path_utils.get_escaped_cwd(), ""):sub(2) end return path_utils diff --git a/lua/codesnap/utils/string.lua b/lua/codesnap/utils/string.lua index 00c6648..3398eb2 100644 --- a/lua/codesnap/utils/string.lua +++ b/lua/codesnap/utils/string.lua @@ -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 diff --git a/lua/codesnap/utils/table.lua b/lua/codesnap/utils/table.lua index 732912a..bfb993a 100644 --- a/lua/codesnap/utils/table.lua +++ b/lua/codesnap/utils/table.lua @@ -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 diff --git a/lua/codesnap/utils/visual.lua b/lua/codesnap/utils/visual.lua index f834ec4..49fff13 100644 --- a/lua/codesnap/utils/visual.lua +++ b/lua/codesnap/utils/visual.lua @@ -2,7 +2,6 @@ local visual_utils = {} -- 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" - local function get_whole_lines(from, to) local lines = {} if from == to then @@ -15,10 +14,20 @@ local function get_whole_lines(from, to) return table.concat(lines, "\n") end -function visual_utils.get_selected_text() - local selected_text = vim.fn.getline("'<", "'>") +function visual_utils.get_start_line_number() + return vim.fn.line("'<") +end - return table.concat(selected_text, "\n") +function visual_utils.get_end_line_number() + return vim.fn.line("'>") +end + +function visual_utils.get_selected_lines() + return vim.fn.getline("'<", "'>") +end + +function visual_utils.get_selected_text() + return table.concat(visual_utils.get_selected_lines(), "\n") end function visual_utils.get_selected_text_realtime() diff --git a/lua/linux-x86_64generator.so b/lua/linux-x86_64generator.so index 4252183..275c31c 100755 Binary files a/lua/linux-x86_64generator.so and b/lua/linux-x86_64generator.so differ diff --git a/lua/mac-aarch64generator.so b/lua/mac-aarch64generator.so index d6f512c..96f1be3 100755 Binary files a/lua/mac-aarch64generator.so and b/lua/mac-aarch64generator.so differ diff --git a/lua/mac-x86_64generator.so b/lua/mac-x86_64generator.so index c23f09a..6e988a5 100755 Binary files a/lua/mac-x86_64generator.so and b/lua/mac-x86_64generator.so differ diff --git a/plugin/codesnap.lua b/plugin/codesnap.lua index ab6ed18..845a9a8 100644 --- a/plugin/codesnap.lua +++ b/plugin/codesnap.lua @@ -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 = "%" } +) diff --git a/project.toml b/project.toml index fe4409e..27ec611 100644 --- a/project.toml +++ b/project.toml @@ -1,6 +1,6 @@ [project] name = "codesnap.nvim" -version = "1.1.12" +version = "1.3.1" description = "📸 Snapshot plugin that can make pretty code snapshots with real-time previews for Neovim" author = "Mist" email = "mist.zzh@gmail.com"