diff --git a/.github/workflows/luarocks.yml b/.github/workflows/luarocks.yml new file mode 100644 index 0000000..c927624 --- /dev/null +++ b/.github/workflows/luarocks.yml @@ -0,0 +1,42 @@ +name: Luarocks + +on: + push: + tags: + - '*' + release: + types: + - created + pull_request: # Tests packaging on PR + workflow_dispatch: + +jobs: + luarocks-upload: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required to get the tags + - name: Get Version + run: echo "LUAROCKS_VERSION=$(git describe --abbrev=0 --tags)" >> $GITHUB_ENV + + # Needed to build the tree-sitter parser dependencies + - name: Install C/C++ Compiler + uses: rlalik/setup-cpp-compiler@master + with: + compiler: clang-latest + - name: Install tree-sitter CLI + uses: baptiste0928/cargo-install@v3 + with: + crate: tree-sitter-cli + + - name: LuaRocks Upload + uses: nvim-neorocks/luarocks-tag-release@v7 + env: + LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} + with: + version: ${{ env.LUAROCKS_VERSION }} + dependencies: | + tree-sitter-markdown + nvim-web-devicons + diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..933c9f9 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,27 @@ +# vim:nospell: +name: Release Please + +on: + push: + branches: + - dev + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v4 + with: + # this assumes that you have created a personal access token + # (PAT) and configured it as a GitHub action secret named + # `MY_RELEASE_PLEASE_TOKEN` (this secret name is not important). + token: ${{ secrets.RELEASE_PLEASE_TOKEN }} + # this is a built-in strategy in release-please, see "Action Inputs" + # for more options + + target-branch: dev + release-type: simple diff --git a/.gitmodules b/.gitmodules index 203bc8a..7a4def7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "wiki"] path = wiki url = https://github.com/OXY2DEV/markview.nvim.wiki.git +[submodule "markview.nvim.wiki"] + path = markview.nvim.wiki + url = https://github.com/OXY2DEV/markview.nvim.wiki.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 892400b..c01fc31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,30 @@ # Changelog -## 1.0.0 (2024-07-31) +## [19.0.0](https://github.com/OXY2DEV/markview.nvim/compare/v18.0.0...v19.0.0) (2024-08-05) +### ⚠ BREAKING CHANGES + +* **renderer:** Added support for simple html elements +* **renderer:** Support for tables that don't start at the start of the line + ### Features +* Added support for HTML entites ([3b270c1](https://github.com/OXY2DEV/markview.nvim/commit/3b270c1dedbf02b4849341ff9e490a001041e248)) +* **renderer:** Added basic language names to code blocks ([c9b4f77](https://github.com/OXY2DEV/markview.nvim/commit/c9b4f77e880eb0ab9afd370ad82e3758513a4a3a)), closes [#72](https://github.com/OXY2DEV/markview.nvim/issues/72) +* **renderer:** Added better validation for html tags in table cells ([ab0e54e](https://github.com/OXY2DEV/markview.nvim/commit/ab0e54e2992b3806fe2b3a68a49d050f1118159e)) +* **renderer:** Added hybrid-mode support to the plugin ([4a93e15](https://github.com/OXY2DEV/markview.nvim/commit/4a93e155261508b89d5c6146ba6cc0da91be0883)), closes [#64](https://github.com/OXY2DEV/markview.nvim/issues/64) +* **renderer:** Added support for simple html elements ([94ce522](https://github.com/OXY2DEV/markview.nvim/commit/94ce522302f78167e278d3c7d82ff0206c74b4e3)) +* **renderer:** Support for tables that don't start at the start of the line ([3c8b0dc](https://github.com/OXY2DEV/markview.nvim/commit/3c8b0dc5a9b02264f94137b23279db7d3198ac7a)) * replace tbl_islist to islist ([f1e66c7](https://github.com/OXY2DEV/markview.nvim/commit/f1e66c78ba28b3b2399a4b76febc42ceb3211fd1)) + + +### Bug Fixes + +* **parser:** Added logic for supporting markers inside code blocks ([a38dd1f](https://github.com/OXY2DEV/markview.nvim/commit/a38dd1f01c31b4201b4355fe8ebaa439621e5b35)), closes [#69](https://github.com/OXY2DEV/markview.nvim/issues/69) +* **parser:** Improved validation of pending checkboxes ([a6392dd](https://github.com/OXY2DEV/markview.nvim/commit/a6392ddeb627a4ebd218718bc4f80b5fca1a1803)) +* **renderer:** Fixed a bug causing inconsistency between the left & right padding in inline codes ([0eb84e5](https://github.com/OXY2DEV/markview.nvim/commit/0eb84e5721dfd2ded1c598eba3ec018d5fd1cd9d)) +* **renderer:** Fixed a bug causing the last line to have border placed on the wrong column ([e102b06](https://github.com/OXY2DEV/markview.nvim/commit/e102b060907173fcafaa8e5e4edde993452a9808)) +* **renderer:** Fixed a bug leading to extmarks on the current line not being removed ([777c6aa](https://github.com/OXY2DEV/markview.nvim/commit/777c6aa50d623eed5a17fb39be60f23fbc7bd4bc)) +* **renderer:** Fixed screen not updating in "no" mode ([60bc13b](https://github.com/OXY2DEV/markview.nvim/commit/60bc13b9492570d4d321391517eb9677918f540e)), closes [#70](https://github.com/OXY2DEV/markview.nvim/issues/70) +* **renderer:** Made headings use decorations around the text instead of replacing the main text ([41d57ab](https://github.com/OXY2DEV/markview.nvim/commit/41d57ab40603b702cd7b7b920c71f7b20ba202aa)) diff --git a/README.md b/README.md index 4709425..b16ded7 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,94 @@ # 📜 Markview.nvim -

Simple markdown previewer for neovim

+An experimental `markdown` previewer for Neovim. ->[!IMPORTANT] -> Presets have been reworked, though you can still use the old presets. It is recommended that you switch to the newer ones as the old ones will be removed in the future. +

+ Wiki page +

-![headings](./images/headings.jpg) -![lists](./images/lists.jpg) -![tables](./images/tables.jpg) +![hybrid_mode_showcase](https://github.com/OXY2DEV/markview.nvim/blob/images/Main/hybrid_mode_showcase.gif) +![html_showcase](https://github.com/OXY2DEV/markview.nvim/blob/images/Main/html_showcase.gif) +![screenshot](https://github.com/OXY2DEV/markview.nvim/blob/images/Main/plugin_showcase_landscape.jpg) +![screenshot_small](https://github.com/OXY2DEV/markview.nvim/blob/images/Main/plugin_showcase_mobile.jpg) ->[!WARNING] -> This plugin is in it's alpha stage and may go through breaking changes. +## ✨ Features ->[!IMPORTANT] -> Highlights now use `PascalCase` so it is recommended to change your highlight group names to PascalCase. But don't worry, the previous names using `Markview_` are still supported! +Markview.nvim comes with a ton of features such as, -## 📑 Table of contents +- Close to `full render` of markdown documents. Currently supported items are, + * Block quotes(includes `callouts`/`alerts` + * Chekboxes(checked, unchecked & pending state) + * Headings(atx_headings & setext_headings) + * Horizontal rules + * Html support(only for simple tags, e.g. `Underline`) + * Html entites(both `&;` and `&` support) + * Inline codes + * Links(hyprlinks, images & email support) + * List item(ordered & unordered) + * Tables +- Fully customisable setup! You can customise everything to your needs! +- A `hybrid mode` that allows rendering in real-time! It will even unconceal nodes under the cursor. +- Dynamic `highlight groups` that allows support for almost any colorscheme! +- Can be loaded on other filetypes too! -- [Features](#-features) -- [Requirements](#-requirements) -- [Installation](#-installation) - - [Lazy.nvim](#-lazynvim) - - [Mini.deps](#-minideps) - - [Others](#-others) -- [Setup](#-setup) -- [Commands](#-commands) -- [Showcases](#-showcases) +And a lot more to come! -## 🛸 Features +## 📦 Requirements -- Fully customisable markdown `headings`. -- Custom `block quotes` with support for `callouts` & `alerts`. -- Custom `code blocks` with different style supports. -- Statusline-like `horizontal rules` customisation. -- Custom `links` and `image links`. -- Custom `inline codes`. -- Padded list items(with nested list support). -- Custom `checkboxes` for different checkbox states. -- Fully customisable `tables`. +- Neovim version: `0.10.0` or above. +- Tree-sitter parsers, + * markdown + * markdown_inline + * html +- Nerd font. -## 🔭 Requirements +Optional: +- A tree-sitter supported colorscheme. -- Neovim version: 0.10 or higher(unless API changes occurred). -- `nvim-treesitter` for easy installation of treesitter parsers. -- `markdown` and `markdown_inline` treesitter parsers. -- `nvim-web-devicons` for the icons. +## 🚀 Installation -## 📦 Installation +Markview can be installed via your favourite `package manager`. ### 💤 Lazy.nvim -For `plugins.lua` or `lazy.lua` users. +>[!CAUTION] +> It is not recommended to lazy-load this plugin as it does that by default. + +For `lazy.lua` users. ```lua { "OXY2DEV/markview.nvim", - ft = "markdown", + lazy = false, -- Recommended + -- ft = "markdown" -- If you decide to lazy-load anyway dependencies = { - -- You may not need this if you don't lazy load + -- You will not need this if you installed the + -- parsers manually -- Or if the parsers are in your $RUNTIMEPATH "nvim-treesitter/nvim-treesitter", "nvim-tree/nvim-web-devicons" - }, + } } ``` -For `plugins/markview.lua` users +For `plugins/markview.lua` users. ```lua return { "OXY2DEV/markview.nvim", - ft = "markdown", + lazy = false, -- Recommended + -- ft = "markdown" -- If you decide to lazy-load anyway dependencies = { - -- You may not need this if you don't lazy load + -- You will not need this if you installed the + -- parsers manually -- Or if the parsers are in your $RUNTIMEPATH "nvim-treesitter/nvim-treesitter", "nvim-tree/nvim-web-devicons" - }, + } } ``` @@ -102,76 +110,209 @@ MiniDeps.add({ }) ``` -### 🤔 Others +### 🌒 Rocks.nvim + +You can install the plugin by running the following command. + +```vim +:Rocks install markview.nvim +``` -The installation process for any other plugin manager(s) is the same. +### 👾 Github releases -If your plugin manager doesn't support `dependencies` then you can always load the plugins in the right order. +You can also download one of the [releases](https://github.com/OXY2DEV/markview.nvim/releases/tag/v1.0.0). + +### 🛸 Testing + +If you don't mind a slightly `unstable` version of the plugin then you can use the [dev branch](https://github.com/OXY2DEV/markview.nvim/tree/dev). + +## 🌇 Commands + +Markview comes with a single command. ```vim -Plug "nvim-treesitter/nvim-treesitter" -Plug "nvim-tree/nvim-web-devicons" +:Markview +``` + +It has the following `sub-commands`, + +- toggleAll, Toggles the plugin. Will set all **attached buffers** state to the plugin state. +- enableAll, Enables the plugin in all **attached buffers**. Will refresh the decorations if the plugin is already enabled. +- disableAll, Disables the plugin in all **attached buffers**. Will try to remove any remaining decorations if the plugin is already disabled. +- toggle {buffer}, Toggles the state of buffer. +- enable {buffer}, Enables/Refreshes the plugin on a specific buffer. +- disable {buffer}, Disables the plugin & clears decorations on a specific buffer. + -Plug "OXY2DEV/markview.nvim" +## 🧭 Configuration + +You can use the `setup()` function to change how the plugin looks. + +```lua +local markview = require("markview"); +local presets = require("markview.presets"); + +markview.setup({ + headings = presets.headings.glow_labels +}); + +vim.cmd("Markview enableAll"); ``` -## 🧭 Setup +This can also be used at runtime. So, you can hot-swap the config anytime you want! + +Go ahead try running it. + +--- + +You can configure the plugin in 2 ways, + +### 📂 Presets + +Presets are an easy way to change the looks of some part of the plugin. + +Currently there are presets for the following items, + +- Headings +- Tables + +You can find more on presets on the [wiki page](). + +### 🎨 Manual + +The plugin was created with the sole purpose of being **customisable**. ->[!NOTE] -> This plugin does not use `setup()` to initialize. So, it is completely optional to call it. +So, you can change everything to fit your needs. -Configuration table for the `setup()` function is given below. +A simple example is given below, ```lua require("markview").setup({ - buf_ignore = { "nofile" }, - modes = { "n", "no" }, - - options = { - on_enable = {}, - on_disable = {} - }, - - block_quotes = {}, - checkboxes = {}, - code_blocks = {}, - headings = {}, - horizontal_rules = {}, - inline_codes = {}, - links = {}, - list_items = {}, - tables = {} + headings = { + enable = true, + + heading_1 = { + style = "label", + + padding_left = " ", + padding_right = " ", + + hl = "MarkviewHeading1" + } + } }); ``` - For customisation related options check the [wiki pages](https://github.com/OXY2DEV/markview.nvim/wiki). +You can check the [wiki](https://github.com/OXY2DEV/markview.nvim/wiki) to learn more about configuration. + +You can also check the [starter guide]() for some simple examples. + +## 🌃 highlight groups + +To make configuration easier `markview.nvim` comes with the following highlight groups. + +### 📦 Block quote + +Block quotes have the following highlight group by default, + +- MarkviewBlockQuoteDefault, also used by `Quote`. + +Various callouts/alerts use the following highlight groups, + +- MarkviewBlockQuoteOk, used by `Tip`, `Success`. +- MarkviewBlockQuoteWarn, used by `Question`, `Custom`, `Warning`. +- MarkviewBlockQuoteError, used by `Caution`, `Bug`, `Danger`, `Failure`. +- MarkviewBlockQuoteNote, used by `Note`, `Todo`, `Abstract`. +- MarkviewBlockQuoteSpecial, used `Important`, `Example`. + +### 🎯 Checkboxes + +Checkboxes use these highlight groups, + +- MarkviewCheckboxChecked, from `DiagnosticOk`. +- MarkviewCheckboxUnhecked, from `DiagnosticError`. +- MarkviewCheckboxPending, from `DiagnosticWarn`. + +### 💻 Code blocks & inline codes + +Code blocks use the following highlight group, -## 🎹 Commands +- MarkviewCode ->[!NOTE] -> Commands are a test feature. +Inline codes use the following highlight group, -There is only a single command for now, `:Markview`. +- MarkviewInlineCode -When called without any arguments, it toggles the plugin. +### 🔖 Headings -Possible subcommands are, +Headings are highlighted with the following groups, -- `toggleAll`, toggles the plugin -- `enableAll`, enables the plugin -- `disableAll`, disables the plugin -- `toggle`, toggles the plugin for the specified buffer(default is the current buffer) -- `enable`, enables the plugin for the specified buffer(default is the current buffer) -- `disable`, disables the plugin for the specified buffer(default is the current buffer) +- MarkviewHeading1, from `DiagnosticVirtualTextOk` +- MarkviewHeading2, from `DiagnosticVirtualTextHint` +- MarkviewHeading3, from `DiagnosticVirtualTextInfo` +- MarkviewHeading4, from `Special` +- MarkviewHeading5, from `DiagnosticVirtualTextWarn` +- MarkviewHeading6, from `DiagnosticVirtualTextError` -## 👾 Showcases +Signs are highlighted with the following groups, ->[!IMPORTANT] -> Screenshots on a phone are very blurry(Yes, the plugin was made on my phone). -> -> If you have screenshots of the plugin, you can submit them in the special issue. And yes, credit will be provided. +- MarkviewHeading1Sign, from `DiagnosticOk` +- MarkviewHeading2Sign, from `DiagnosticHint` +- MarkviewHeading3Sign, from `DiagnosticInfo` +- MarkviewHeading4Sign, from `Special` +- MarkviewHeading5Sign, from `DiagnosticWarn` +- MarkviewHeading6Sign, from `DiagnosticError` -![showcase_1](./images/preview_1.png) +### 📏 Horizontal rules + +Horizontal rules use the following highlight groups for the gradient. + +- MarkviewGradient1, from `Normal`. +- MarkviewGradient2 +- MarkviewGradient3 +- MarkviewGradient4 +- MarkviewGradient5 +- MarkviewGradient6 +- MarkviewGradient7 +- MarkviewGradient8 +- MarkviewGradient9 +- MarkviewGradient10, from `Cursor`. + +### 🔗 Links + +Links use the following highlight groups, + +- MarkviewHyperlink, from `markdownLinkText`. +- MarkviewImageLink, from `markdownLinkText`. +- MarkviewEmail, from `@markup.link.url.markdown_inline`. + +### 📝 List items + +List items use the following highlight groups, + +- MarkviewListItemMinus, from `DiagnosticWarn`. +- MarkviewListItemPlus, from `DiagnosticOk`. +- MarkviewListItemStar, from `@comment.note`. + +### 📐 Tables + +Tables use the following highlight group for the border, + +- MarkviewTableBorder, from `Title`. + +For the column alignment markers these highlight groups are used, + +- MarkviewTableAlignLeft, from `Title`. +- MarkviewTableAlignRight, from `Title`. +- MarkviewTableAlignCenter, from `Title`. + +## ⭐ Plugin showcase + +![showcase_1](https://github.com/OXY2DEV/markview.nvim/blob/images/Submitted/sc_scottmckendry.png) Taken by @scottmckendry + + diff --git a/doc/markview.txt b/doc/markview.txt new file mode 100644 index 0000000..d1515e4 --- /dev/null +++ b/doc/markview.txt @@ -0,0 +1,1333 @@ +*markview.nvim* An experimental markdown previewer for Neovim + + Created by `OXY2DEV` + +============================================================================== +Table of contents *markview.nvim-toc* + +Features ............................................ |markview.nvim-features| +Requirements .................................... |markview.nvim-requirements| + +Installation .................................... |markview.nvim-installation| + 💤 Lazy.nvim ...................................... |markview.nvim-i-lazy| + 🦠 Mini.deps .................................. |markview.nvim-i-minideps| + 🌒 Rocks.nvim .................................... |markview.nvim-i-rocks| + +Highlight groups ......................................... |markview.nvim-hls| +Commands ............................................ |markview.nvim-commands| + +Plugin configuration .................................. |markview.nvim-config| + Block quotes .............................. |markview.nvim-c-block_quotes| + Checkboxes .................................. |markview.nvim-c-checkboxes| + Code blocks ................................ |markview.nvim-c-code_blocks| + Headings ...................................... |markview.nvim-c-headings| + Horizontal rules ................................... |markview.nvim-c-hrs| + Inline codes .............................. |markview.nvim-c-inline_codes| + Links ............................................ |markview.nvim-c-links| + List items .................................. |markview.nvim-c-list_items| + Tables .......................................... |markview.nvim-c-tables| + +Helper functions ..................................... |markview.nvim-helpers| + +============================================================================== +Features *markview.nvim-features* + +- Fully stylized preview of `markdown` documents! Currently supported elements + are, + * atx_headings(uses `#`) & setext_headings(uses `---` or `===`) + * inline codes + * code blocks + * block quotes + * list items(both ordered & unordered) + * tables + * hyperlinks, image links & email urls + * horizontal rules + * checkboxes +- Fully customisable elements. From icons, highlight groups to concealments, + padding almost everything can be customised. +- `Dynamically` generated highlight groups. Useful for colorschemes that don't + support various highlight groups. + Note: The plugin will respect highlight groups set by the colorschemes + when available. +- `Hybrid-mode` for editing and previewing at the same time. +- Commands to quickly toggle the plugin(globally or per buffer). + +And so much more! + +============================================================================== +Requirements *markview.nvim-requirements* + +- Neovim version `0.10.0` or higher. +- `Tree-sitter` parser for `markdown` & `markdown_inline`. +- `nvim-web-devicons` +- Optionally, a `tree-sitter` compatible colorscheme. + +============================================================================== +Installation *markview.nvim-installation* + +`markview.nvim` can be installed via your favourite package manager. + +------------------------------------------------------------------------------ +💤 Lazy.nvim *markview.nvim-i-lazy* + +For `lazy.lua` users. +>lua + { + "OXY2DEV/markview.nvim", + ft = "markdown", + + dependencies = { + -- You may not need this if you don't lazy load + -- Or if the parsers are in your $RUNTIMEPATH + "nvim-treesitter/nvim-treesitter", + + "nvim-tree/nvim-web-devicons" + }, + } +< +For `plugins/markview.lua` users. +>lua + return { + "OXY2DEV/markview.nvim", + ft = "markdown", + + dependencies = { + -- You may not need this if you don't lazy load + -- Or if the parsers are in your $RUNTIMEPATH + "nvim-treesitter/nvim-treesitter", + + "nvim-tree/nvim-web-devicons" + }, + } +< + +Note: +It is NOT recommended to lazy load this plugin as it already does that. + +Warning: +You will not be able to access help files without opening a markdown file +if you choose to lazy load. + +------------------------------------------------------------------------------ +🦠 Mini.deps *markview.nvim-i-minideps* +>lua + local MiniDeps = require("mini.deps"); + + MiniDeps.add({ + source = "OXY2DEV/markview.nvim", + + depends = { + -- You may not need this if you don't lazy load + -- Or if the parsers are in your $RUNTIMEPATH + "nvim-treesitter/nvim-treesitter", + + "nvim-tree/nvim-web-devicons" + } + }); +< +------------------------------------------------------------------------------ +🌒 Rocks.nvim *markview.nvim-i-rocks* + +`markview.nvim` can be installed using the following command. +>vim + :Rocks install markview.nvim +< +------------------------------------------------------------------------------ +Others + +Installation process for other plugin managers are similar. +>vim + Plug "nvim-treesitter/nvim-treesitter" + Plug "nvim-tree/nvim-web-devicons" + + Plug "OXY2DEV/markview.nvim" +< +============================================================================== +Highlight groups *markview.nvim-hls* + +Note: + The `$` are NOT part of the name. + +- $MarkviewHeading1$ $MarkviewHeading1Sign$ + $MarkviewHeading2$ $MarkviewHeading2Sign$ + $MarkviewHeading3$ $MarkviewHeading3Sign$ + $MarkviewHeading4$ $MarkviewHeading4Sign$ + $MarkviewHeading5$ $MarkviewHeading5Sign$ + $MarkviewHeading6$ $MarkviewHeading6Sign$ + + Highlight groups for different heading levels. `atx_headings` & + `setext_headings` both uses them + +- $MarkviewBlockQuoteDefault$ + $MarkviewBlockQuoteOk$ + $MarkviewBlockQuoteWarn$ + $MarkviewBlockQuoteError$ + $MarkviewBlockQuoteNote$ + $MarkviewBlockQuoteSpecial$ + + Highlight groups responsible for various block quotes, `callouts` & + `alerts`. + +- $MarkviewCode$ + + Highlight group for showing `code blocks` and `inline codes`. + +- $MarkviewCheckboxChecked$ + $MarkviewCheckboxUnchecked$ + $MarkviewCheckboxPending$ + + Highlight group for the different `checkbox` states. + +- $MarkviewListItemPlus$ + $MarkviewListItemMinus$ + $MarkviewListItemStar$ + + Highlight groups for `unordered lists`. The plugin doesn't add decorations + to ordered lists. + +- $MarkviewTableBorder$ + + Highlight group for the borders of `tables`. + + $MarkviewTableAlignLeft$ + $MarkviewTableAlignRight$ + $MarkviewTableAlignCenter$ + + Highlight groups for the various `alignment indicators` on rows. + +- $MarkviewGradient1$ + $MarkviewGradient2$ + $MarkviewGradient2$ + $MarkviewGradient3$ + $MarkviewGradient4$ + $MarkviewGradient5$ + $MarkviewGradient6$ + $MarkviewGradient7$ + $MarkviewGradient8$ + $MarkviewGradient9$ + $MarkviewGradient10$ + + Highlight groups used by the `horizontal rules`. + +============================================================================== +Commands *markview.nvim-commands* + +Markview comes with the following command, +>vim + :Markview +< +When used without any arguments it `toggles` the plugin state. + +It comes with the following sub-commands, + +- toggleAll + + Toggles the plugin state. This will set ALL attached buffers to the same + state. + +- enableAll + + Enables the plugin in all attached buffers. If the plugin is already enabled + then it will redraw everything. + +- disableAll + + Disables the plugin in all attached buffers. If the plugin is already + diaable it will clear any remaining decorations. + +Note: +When the {buffer} isn't provided these commands will run on the current +buffer. + +- toggle {buffer} + + Toggles the state of a buffer. Used for disabling the plugin on a specific + buffer. + +- enable {buffer} + + Enables the plugin on a buffer. Redraws decorations if it's already enabled + in that buffer. + +- disable {buffer} + + Disables the plugin on a specific buffer. Removes decorations if it's + already disabled in that buffer. + +------------------------------------------------------------------------------ + +============================================================================== +Plugin configuration *markview.nvim-config* + +The plugin can be configured via the `setup()` function. +>lua + local presets = require("markview.presets"); + + require("markview").setup({ + headings = presets.headings.glow_labels + }); +< + +The setup function comes with the following options, + +- modea `string[]` + + A list of |vim-modes| where the preview will be shown. Default is, +>lua + modes = { "n", "no" } +< +- hybrid_modes `string[] or nil` + + A list of |vim-modes| where the text under the cursor is shown as raw text + without any decorations. + + Default is nil. +>lua + hybrid_modes = nil +< +- buf_ignore `string[] or nil` + + A list of |'buftype'|s where the plugin will be disabled. Default is, +>lua + buf_ignore = { "nofile" } +< +- callbacks + { + on_enable: `function or nil`, + on_disable: `function or nil`, + + on_mode_change: `function or nil` + } + + A table containing `callbacks` that will be run by the plugin on specific + events. See |markview.nvim-callbacks| for more info. + + Example usage, +>lua + callbacks = { + on_enable = function (_, win) + vim.wo[win].cursorline = false; + end + } +< +- headings `table or nil` + + A table containing configuration for various `headings`. See + |markview.nvim-c-headings| for more info. + + Example usage, +>lua + headings = { + enable = false + } +< +- code_blocks `table or nil` + + A table containing configuration for the `fenced code blocks`. See + |markview.nvim-c-code_blocks| for more info. + + Example usage, +>lua + code_blocks = { + enable = false + } +< +- inline_codes `table or nil` + + A table containing configuration for the `inline codes`. See + |markview.nvim-c-inline_codes| for more info. + + Example usage, +>lua + inline_codes = { + enable = false + } +< +- block_quotes `table or nil` + + A table containing configuration for the `block quotes`, `alerts` and + `callouts`. See |markview.nvim-c-block_quotes| for more info. + + Example usage, +>lua + block_quotes = { + enable = false + } +< +- horizontal_rules `table or nil` + + A table containing configuration for the `horizontal rules`. See + |markview.nvim-c-hrs| for more info. + + Example usage, +>lua + horizontal_rules = { + enable = false + } +< +- links `table or nil` + + A table containing configuration for various `links`. See + |markview.nvim-c-links| for more info. + + Example usage, +>lua + links = { + enable = false + } +< +- list_items `table or nil` + + A table containing configuration for various `list items`. See + |markview.nvim-c-list_items| for more info. + + Example usage, +>lua + list_items = { + enable = false + } +< +- checkboxes `table or nil` + + A table containing configuration for various `checkboxes`. See + |markview.nvim-c-checkboxes| for more info. + + Example usage, +>lua + checkboxes = { + enable = false + } +< +- tables `table or nil` + + A table containing configuration for the `tables`. See + |markview.nvim-c-tables| for more info. + + Example usage, +>lua + tables = { + enable = false + } +< +------------------------------------------------------------------------------ + +------------------------------------------------------------------------------ +Block quote *markview.nvim-c-block_quotes* + +Allows changing how block quotes, callouts & alerts. +>lua + block_quotes = { + enable = true, + + default = { + border = "▋", + border_hl = "MarkviewBlockQuoteDefault" + }, + + callouts = { + { + match_string = "ABSTRACT" + callout_preview = "󱉫 Abstract", + callout_preview_hl = "MarkviewBlockQuoteNote", + + custom_title = true, + custom_icon = "󱉫 ", + + border = "▋", + border_hl = "MarkviewBlockQuoteDefault" + } + } + } +< +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of block quotes, callouts +& alerts. + +default ~ + `table` +Configuration for block quotes and unknown callouts/alerts. + +It comes with the following properties, + +border ~ + `string` +A string to use as the border. Preferablly a single character. + +border_hl + `string or nil` +Highlight group for the default border. + +------------------------------------------------------------------------------ +Checkboxes *markview.nvim-c-checkboxes* + +Configuration table for various checkbox states. +>lua + checkboxes = { + enable = true, + + checked = { + text = "✔", + hl = "MarkviewCheckboxChecked" + }, + unchecked = {}, + pending = {} + } +< +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of checkboxes. + +checked ~ + `table or nil` +Configuration table for checked checkboxes. + +unchecked ~ + `table or nil` +Configuration table for unchecked checkboxes. + +pending ~ + `table or nil` +Configuration table for pending checkboxes. + +------------------------------------------------------------------------------ +Code blocks *markview.nvim-c-code_blocks* + +Allows changing how code_blocks are shown. +>lua + headings = { + enable = true, + style = "minimal", + + position = "minimal", + min_width = 60, + pad_amount = 3, + pad_char = " ", + + language_names = { + "cpp", "c++", + "py", "python" + }, + + hl = "MarkviewCode", + + sign = true, + sign_hl = nil + } +< +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of headings entirely. + +style ~ + `string` +The rendering style of code blocks. + + - simple + + The lines within the code blocks are highlighted. + + - minimal + + Adds padding to the code block and surronds the block in a rectangle. + + - language + + Like minimal but adds icons, signs and language string to the blocks. + +position ~ +Only for the `minimal`, `language` styles. + `string or nil` +The {virt_text_pos} of the top & bottom border of the code block. Default is +`inline`. + +min_width ~ +Only for the `minimal`, `language` styles. + `number` +The minimum width of the code block. This is without counting the +`pad_amount`. + +pad_amount ~ +Only for the `minimal`, `language` styles. + `number` +The number of `pad_char` to add before and after the lines of the code block. + +pad_char ~ +Only for the `minimal`, `language` styles. + `string` +The text used as padding for the code blocks. + +language_names ~ + `table or nil` + +A list of `tuples` containing a `match` & a `replacement`. Useful when you +want to see `c++` instead of `cpp`. + +hl ~ + `string` +Highlight group for the code block. + +sign ~ + `boolean or nil` +When `true`, icons are shown in the |'signcolumn'| for code blocks + +sign_hl ~ + `string or nil` +A custom highlight group for the `signs`. When nil, the highlight group +provided by `nvim-web-devicons` is used. + +------------------------------------------------------------------------------ +Headings *markview.nvim-c-headings* + +Allows changing how headings are shown. +>lua + headings = { + enable = true, + shift_width = 3, + + heading_1 = {}, + heading_2 = {}, + heading_3 = {}, + heading_4 = {}, + heading_5 = {}, + heading_6 = {}, + + setext_1 = {}, + setext_2 = {}, + } +< +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of headings entirely. + +shift_width ~ +Only for the `simple`, `icon` styles. + `number or nil` +Number of `shift_char` to add per level of the headings. + +heading_<1-6> ~ + `table or nil` +`heading_1` to `heading_6` are used for styling atx_headings. They all have +the following properties. + +style ~ + `string` +`atx_headings` support the following styles, + + - simple + + Adds simple background to the headings. + + - label + + Adds padding, icons, corner text, sign etc. `statusline`-like parts + around the heading text. + + - icon + + Adds simple icons to the headings. Also hides the `#` of the heading. + +NOTE: +These styles are EXCLUSIVE to `atx_headings` and will not work with +`setext_headings`. + +`setext_headings` support the following styles. + + - simple + + Adds simple background to the headings. + + - github + + Adds an icon before the heading text and a line under the heading text. + Kinda like how headings are shown in GitHub. + +shift_char ~ + `string or nil` +Thw character to use as padding before the heading. + +------------------------------------------------------------------------------ + +corner_left ~ +Only for the `label` style. + `string or nil` +Only useful when adding different colored sections before the left padding. + +padding_left ~ +Only for the `label` style. + `string or nil` +The text to use as padding before the heading. + +icon ~ +Only for the `label` style. + `string or nil` +The text to use as an icon before the heading text. + +padding_right ~ +Only for the `label` style. + `string or nil` +The text to use as padding after the heading. + +corner_right ~ +Only for the `label` style. + `string or nil` +Only useful when adding different colored sections after the right padding. + + + +hl ~ + `string or nil` +Highlight group to be applied to the entire range of the node. It is added as +the `line_hl_group` when the style is `icon`. + +It is used as the default value for the following properties. + +corner_left_hl ~ +Only for the `label` style. + `string or nil` +Highlight group for the left corner. + +padding_left_hl ~ +Only for the `label` style. + `string or nil` +Highlight group for the left padding. + +icon_hl ~ +Only for the `label`, `icon` styles. + `string or nil` +Highlight group for icon. + +text_hl ~ +Only for the `label`, `icon` styles. + `string or nil` +Highlight group for heading text. + +padding_right_hl ~ +Only for the `label` style. + `string or nil` +Highlight group for the left padding. + +corner_right_hl ~ +Only for the `label` style. + `string or nil` +Highlight group for the left corner. + +------------------------------------------------------------------------------ +Horizontal rules *markview.nvim-c-hrs* + +Configuration table for line breaks or horizontal rules. +>lua +horizontal_rules = { + enable = true, + + parts = { + { + type = "repeating", + + text = "─", + hl = { "MarkviewGradient1", "MarkviewGradient2" }, + direction = "left", + + repeat_amount = function () + return vim.o.columns - 3; + end + }, + { + type = "text", + text = " • ", + hl = "MarkviewGradient5" + } + } + } +< +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of line breaks/horizontal +rules. + +parts ~ + `table` +A list of parts to create a horizontal rule. There are 2 types of parts +available, + +- repeating + + Repeats the provided text by a number of time. + + - text + + Renders some raw text to the screen. + +------------------------------------------------------------------------------ + +Parts: repeating ~ + *markview.nvim-hr-repeating* +Repeats a text a specific number of times. It has the following properties, + +type ~ + `string` +The type of a part. In this case it's value would be `repeating`. + +text ~ + `string` +The text to repeat. + +hl ~ + `table or nil` +A list of colors to use for the part. The `direction` property changes where +the color is applied in the final string. + +direction ~ + `string or nil` +The side of the final string where the `hl` would be applied. Possible values +are, + - left + - right + +Default is `left`. + +repeat_amount ~ + `function or number` +The number of times to repeat `text`. If the value is a `function` then the +returned value is used. + +------------------------------------------------------------------------------ + +Parts: text ~ + *markview.nvim-hr-text* +Shows some text in the horizontal rule. It has the following properties, + +text ~ + `string` +The text to show. + +hl ~ + `string or nil` +Highlight group for coloring `text` + +------------------------------------------------------------------------------ +Inline codes *markview.nvim-c-inline_codes* + +Configuration table for `inline codes`/codespans. + +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of inline codes. + +corner_left ~ + `string or nil` +Only useful when adding different colored sections before the left padding. + +padding_left ~ + `string or nil` +The text to use as padding before the heading. + +icon ~ + `string or nil` +The text to use as an icon before the heading text. + +padding_right ~ + `string or nil` +The text to use as padding after the heading. + +corner_right ~ + `string or nil` +Only useful when adding different colored sections after the right padding. + + + +hl ~ + `string or nil` +Highlight group to be applied to the entire range of the node. + +It is used as the default value for the following properties. + +corner_left_hl ~ + `string or nil` +Highlight group for the left corner. + +padding_left_hl ~ + `string or nil` +Highlight group for the left padding. + +icon_hl ~ + `string or nil` +Highlight group for icon. + +text_hl ~ + `string or nil` +Highlight group for heading text. + +padding_right_hl ~ + `string or nil` +Highlight group for the left padding. + +corner_right_hl ~ + `string or nil` +Highlight group for the left corner. + +------------------------------------------------------------------------------ +Links *markview.nvim-c-links* + +Configuration tables for various types of links. +>lua + links = { + enable = true, + + hyperlinks = { + icon = "H", + hl = "MarkviewHyperlink" + }, + images = {}, + emails = {} + } +< +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of links. + +hyperlinks ~ + `table or nil` +Configuration table for regular links(links using `[]()`). + +images ~ + `table or nil` +Configuration table for image links(links using `![]()`). + +emails ~ + `table or nil` +Configuration table for email urls(links using `<>`). + +------------------------------------------------------------------------------ + +All the options(other than `enable`) have these properties. + +corner_left ~ + `string or nil` +Only useful when adding different colored sections before the left padding. + +padding_left ~ + `string or nil` +The text to use as padding before the heading. + +icon ~ + `string or nil` +The text to use as an icon before the heading text. + +padding_right ~ + `string or nil` +The text to use as padding after the heading. + +corner_right ~ + `string or nil` +Only useful when adding different colored sections after the right padding. + + + +hl ~ + `string or nil` +Highlight group to be applied to the entire range of the node. + +It is used as the default value for the following properties. + +corner_left_hl ~ + `string or nil` +Highlight group for the left corner. + +padding_left_hl ~ + `string or nil` +Highlight group for the left padding. + +icon_hl ~ + `string or nil` +Highlight group for icon. + +text_hl ~ + `string or nil` +Highlight group for heading text. + +padding_right_hl ~ + `string or nil` +Highlight group for the left padding. + +corner_right_hl ~ + `string or nil` +Highlight group for the left corner. + +------------------------------------------------------------------------------ +List items *markview.nvim-c-list_items* + +Configuration table for various list items. +>lua + list_items = { + enable = true, + + marker_plus = { + add_padding = true, + + text = "•", + hl = "MarkviewListItemPlus" + } + } +< +Note: List items nodes have different start and end ranges for different list +level. This can cause issues when you do a lot of nesting inside lists. + +It is not recommended to use decorations that can cause items to go out of +place. + +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of list items. + +marker_plus ~ + `table or nil` +Configuration table for lists starting with `+`. + +marker_minus ~ + `table or nil` +Configuration table for lists starting with `-`. + +marker_star ~ + `table or nil` +Configuration table for lists starting with `*`. + +------------------------------------------------------------------------------ + +All the options(other than `enable`) have these properties. + +text ~ + `string or nil` +The text to use as the marker. It will `conceal` the oroginal marker and +replace it with this text. + +hl ~ + `string or nil` +Highlight group for `text`. + +------------------------------------------------------------------------------ + +All the options(other than `enable`) have these properties. + +text ~ + `string or nil` +The text to use as the checkbox. It will `conceal` the original marker and +replace it with this text. + +hl ~ + `string or nil` +Highlight group for `text`. + +------------------------------------------------------------------------------ +Tables *markview.nvim-c-tables* + +Configuration table for tables. +>lua + tables = { + enable = true, + + text = {}, + hl = {}, + + use_virt_lines = false + } +< +enable ~ + `boolean or nil` +The `enable` option is used to disable the rendering of tables. + +use_virt_lines ~ + `boolean or nil` +When `true`, the top & bottom borders are made of `virtual lines`. Useful if +you don't like having gaps between tables. + +text ~ + `table` +A list of `12` string used to create the table. +>txt + Main borders Row & column separtor + ------------------- --------------------- + "╭", "─", "╮", "┬", + "├", "│", "┤", "┼", + "╰", "─", "╯", "┴", + + Alignment markers + ----------------------------------------- + "╼", "╾", "╴", "╶" + Left Right Center +< + +hl ~ + `table or nil` +A list of `12` highlight group for the strings in `text`. + +------------------------------------------------------------------------------ +Helper functions *markview.nvim-helpers* + +The plugin comes with a few helper functions to easily create Dynamic +|highlight-groups|. + +Color related helper functions can be used either through `markview.colors` or +by requiring the file Directly. +>lua + local markview = require("markview"); + vim.print(markview.colors.get_hl_value(0, "Special", "fg")); +< +------------------------------------------------------------------------------ + + *markview.nvim-h-lerp* +colors.lerp({x}: number, {y}: number, {t}: number) -> number + + The mising `math.lerp()` function. Does `linear interpolation` between + x & y. + + Parameters: ~ + + • {x} The start value. + • {y} The stop/end value. + • {t} A float between 0.00 & 1.00 to interpolate to. + + Result: ~ + + • {number} The interpolated value. + + *markview.nvim-h-clamp* +colors.clamp({value}: number, {min}: number, {max}: number) -> number + + The mising `math.clamp()` function. Clamps a value between min & max. + + Parameters: ~ + + • {value} The value to clamp. + • {min} Minimum value. + • {max} Maximum value. + + Result: ~ + + • {number} The clamped value. + + *markview.nvim-h-name_to_hex* +colors.name_to_hex({name}: string) -> string + + Turns |gui-colors| into heaxadecimal values. + + Used for converting |'guifg'|, |'guibg'| & |'guisp'| values provided + by |nvim_get_hl()| into human readable colors. + + Parameters: ~ + + • {name} Name of the color. + + Result: ~ + + • {string} The converted hexadecimal color. + + *markview.nvim-h-name_to_rgb* +colors.name_to_rgb({name}: string) -> { r: number, g: number, b: number } + + Turns |gui-colors| into tables containing r, g, b values. + + Used for converting |'guifg'|, |'guibg'| & |'guisp'| values provided + by |nvim_get_hl()| into human readable colors. + + Parameters: ~ + + • {name} Name of the color. + + Result: ~ + + • {table} A table containing the r, g, b values. + + *markview.nvim-h-num_to_hex* +colors.num_to_hex({num}: number) -> string + + Converts numbers into hexadecimal string. A `#` is added before the + output string. + + Used for converting |'guifg'|, |'guibg'| & |'guisp'| values provided + by |nvim_get_hl()| into human readable colors. + + Parameters: ~ + + • {num} Number to convert. + + Result: ~ + + • {string} The converted hexadecimal color. + + *markview.nvim-h-num_to_rgb* +colors.num_to_rgb({num}: number) -> { r: number, g: number, b: number } + + Sperates color numbers into r, g, b values. + + Rarely used for translating outputs of |nvim_get_hl()|. + + Parameters: ~ + + • {num} Number to seperate. + + Result: ~ + + • {table} Table containing r, g, b values. + + *markview.nvim-h-hex_to_rgb* +colors.hex_to_rgb({str}: string) -> { r: number, g: number, b: number } + + Seperates hex color codes to r, g, b colors. + + Supports codes with or without `#` in front of them. Also supports + `3-digit` & `6-digit` hex color codes. + + Parameters: ~ + + • {str} Hexadecimal string to seperate. + + Result: ~ + + • {table} Table containing r, g, b values. + + *markview.nvim-h-rgb_to_hex* +colors.rgb_to_hex({ {r}: number, {g}: number, {b}: number }) -> string + + Turns table containing r, g, b values into valid hex color codes. + + Used internally for transforming color values. + + Parameters: ~ + + • {tbl} A table containing r, g, b values. + + Result: ~ + + • {table} 6-digit hex color code. + + *markview.nvim-h-get_hl_value* +colors.get_hl_value({ns_id}: number, {hl_group}: string, {value}: string) + -> any + + A wrapper function for |nvim_get_hl()|. + + Gets {value} of {hl_group} in the provided {ns_id}. If {value} is `fg`, + `bg` or `sp` the returned value will be a table containing the r, g, b + values. Otherwise the value is directly returned. + + Parameters: ~ + + • {ns_id} Namespace ID. See |namespace| for more information. + • {hl_group} Highlight group name. + • {value} The value to return. + + Result: ~ + + • {any} Any of the value returned by |nvim_get_hl()|. + + *markview.nvim-h-create_gradient* +colors.create_gradient( + {name_prefix}: string, + + {from}: color, + {to}: color, + + {steps}: number, + {mode}: string +) -> { {group_name}: string, {value}: table } + + Creates a list of `highlight groups` for the {highlight_groups} option. + + A 2-stop gradient is generated between {from} & {to}. The value of + {from} & {to} can either be a number, string or a table with r, g, b + values. + + The {mode} can be used to make the gradient into the background color or + the foreground color or both. + + Parameters: ~ + + • {name_prefix} The prefix to add before each of the {group_name}. + + E.g. setting the {name_prefix} to "Gradient" will + result in group names being "Gradient" where + "" is the step number. + + • {from} The start color of the gradient. Can be a number, + a string or a table. It will be converted to a + table containing r, g, b values. + • {to} The stop color of the gradient. Works like {from}. + + • {steps} Number of steps in the gradient(including the start + and stop colors). + • {mode} The color mode of the gradient. Possible values are, + • bg: Applies the color to the background. + • fg: Applies the color to the foreground. + • both: Does all of the above. + + Result: ~ + + • {table} A list of tables containing a {group_name} and a + {value}. Mainly for use in {highlight_groups}. + + *markview.nvim-h-mix* +colors.mix( + {color_1}: color, {color_2}: color, + {per_1}: number, {per_2}: number +) -> string + + Mixes {color_1}, {color_2} to create a new color. + + The value of {color_1} & {color_2} can either be a number, string + or a table with r, g, b values. + + The {per_1} & {per_2} are floats between 0 & 1. They are used as % values + of the r, g, b values of the corresponding color. They are then added + together to make the new color. + + Parameters: ~ + + • {color_1} The first color to mix. Can be a number, + a string or a table. It will be converted to a + table containing r, g, b values. + • {color_2} The stop color of the gradient. Works like + {color_1}. + + • {per_1} The % of {color_1} to mix. + • {per_2} The % of {color_2} to mix. + + Result: ~ + + • {string} The hex color code of the resulting color. + + *markview.nvim-h-get_brightness* +colors.get_brightness({color}: color) -> number + + Gets the `luminosity` value of the color. Supports hexadecimal numbers, + color names, tables containing r, g, b values. + + Parameters: ~ + + • {color} The first color to mix. Can be a number, + a string or a table. It will be converted to a + table containing r, g, b values. + + Result: ~ + + • {number} Luminosity value between 0 & 1. + + *markview.nvim-h-brightest* +colors.brightest({list}: color[]) -> string + + Gets the brightest color from the provided list of colors. + + Parameters: ~ + • {list} A list of colors. Can contain hexadecimal numbers, numbers, + color names & tables with r, g, b values. + + Result: ~ + + • {string} The brightest color's hex color code. + + *markview.nvim-h-get* +colors.get({list}: any[]) -> any + + Gets the first `non-nil` value from a list(with empty holes) of values. + +vim:ft=help:bt=help:textwidth=78:ts=4:spell: diff --git a/doc/tags b/doc/tags new file mode 100644 index 0000000..039040e --- /dev/null +++ b/doc/tags @@ -0,0 +1,37 @@ +markview.nvim markview.txt /*markview.nvim* +markview.nvim-c-block_quotes markview.txt /*markview.nvim-c-block_quotes* +markview.nvim-c-checkboxes markview.txt /*markview.nvim-c-checkboxes* +markview.nvim-c-code_blocks markview.txt /*markview.nvim-c-code_blocks* +markview.nvim-c-headings markview.txt /*markview.nvim-c-headings* +markview.nvim-c-hrs markview.txt /*markview.nvim-c-hrs* +markview.nvim-c-inline_codes markview.txt /*markview.nvim-c-inline_codes* +markview.nvim-c-links markview.txt /*markview.nvim-c-links* +markview.nvim-c-list_items markview.txt /*markview.nvim-c-list_items* +markview.nvim-c-tables markview.txt /*markview.nvim-c-tables* +markview.nvim-commands markview.txt /*markview.nvim-commands* +markview.nvim-config markview.txt /*markview.nvim-config* +markview.nvim-features markview.txt /*markview.nvim-features* +markview.nvim-h-brightest markview.txt /*markview.nvim-h-brightest* +markview.nvim-h-clamp markview.txt /*markview.nvim-h-clamp* +markview.nvim-h-create_gradient markview.txt /*markview.nvim-h-create_gradient* +markview.nvim-h-get markview.txt /*markview.nvim-h-get* +markview.nvim-h-get_brightness markview.txt /*markview.nvim-h-get_brightness* +markview.nvim-h-get_hl_value markview.txt /*markview.nvim-h-get_hl_value* +markview.nvim-h-hex_to_rgb markview.txt /*markview.nvim-h-hex_to_rgb* +markview.nvim-h-lerp markview.txt /*markview.nvim-h-lerp* +markview.nvim-h-mix markview.txt /*markview.nvim-h-mix* +markview.nvim-h-name_to_hex markview.txt /*markview.nvim-h-name_to_hex* +markview.nvim-h-name_to_rgb markview.txt /*markview.nvim-h-name_to_rgb* +markview.nvim-h-num_to_hex markview.txt /*markview.nvim-h-num_to_hex* +markview.nvim-h-num_to_rgb markview.txt /*markview.nvim-h-num_to_rgb* +markview.nvim-h-rgb_to_hex markview.txt /*markview.nvim-h-rgb_to_hex* +markview.nvim-helpers markview.txt /*markview.nvim-helpers* +markview.nvim-hls markview.txt /*markview.nvim-hls* +markview.nvim-hr-repeating markview.txt /*markview.nvim-hr-repeating* +markview.nvim-hr-text markview.txt /*markview.nvim-hr-text* +markview.nvim-i-lazy markview.txt /*markview.nvim-i-lazy* +markview.nvim-i-minideps markview.txt /*markview.nvim-i-minideps* +markview.nvim-i-rocks markview.txt /*markview.nvim-i-rocks* +markview.nvim-installation markview.txt /*markview.nvim-installation* +markview.nvim-requirements markview.txt /*markview.nvim-requirements* +markview.nvim-toc markview.txt /*markview.nvim-toc* diff --git a/ftplugin/markdown.lua b/ftplugin/markdown.lua index abc2d98..a1de838 100644 --- a/ftplugin/markdown.lua +++ b/ftplugin/markdown.lua @@ -3,19 +3,21 @@ local utils = require("markview.utils"); local ts_available, treesitter_parsers = pcall(require, "nvim-treesitter.parsers"); local function parser_installed(parser) - return (ts_available and treesitter_parsers.has_parser(parser)) or - (vim.treesitter.query.get(parser, "highlights")) + return (ts_available and treesitter_parsers.has_parser(parser)) or pcall(vim.treesitter.query.get, parser, "highlights") end -- Check for requirements if vim.fn.has("nvim-0.10") == 0 then - vim.print("[ markview.nvim ] : Thie plugin is only available on version 0.10.0 and higher!"); + vim.notify("[ markview.nvim ] : Thie plugin is only available on version 0.10.0 and higher!", vim.log.levels.WARN); return; elseif not parser_installed("markdown") then - vim.print("[ markview.nvim ] : Treesitter parser for 'markdown' wasn't found!"); + vim.notify("[ markview.nvim ] : Treesitter parser for 'markdown' wasn't found!", vim.log.levels.WARN); return; elseif not parser_installed("markdown_inline") then - vim.print("[ markview.nvim ] : Treesitter parser for 'markdown_inline' wasn't found!"); + vim.notify("[ markview.nvim ] : Treesitter parser for 'markdown_inline' wasn't found!", vim.log.levels.WARN); + return; +elseif not parser_installed("html") then + vim.notify("[ markview.nvim ] : Treesitter parser for 'html' wasn't found! It is required for basic html tag support.", vim.log.levels.WARN); return; end @@ -23,12 +25,13 @@ if vim.islist(markview.configuration.buf_ignore) and vim.list_contains(markview. return end -if vim.islist(markview.configuration.highlight_groups) then +-- Don't add hls unless absolutely necessary +if not markview.added_hls and vim.islist(markview.configuration.highlight_groups) then markview.add_hls(markview.configuration.highlight_groups) + markview.added_hls = true; end local markview_augroup = vim.api.nvim_create_augroup("markview_buf_" .. vim.api.nvim_get_current_buf(), { clear = true }); -local options = markview.configuration.options; vim.api.nvim_create_autocmd({ "BufWinEnter" }, { buffer = vim.api.nvim_get_current_buf(), @@ -44,30 +47,43 @@ vim.api.nvim_create_autocmd({ "BufWinEnter" }, { end if markview.state.enable == false then + -- Call the on_disable callback before exiting + if not markview.configuration.callbacks or not markview.configuration.callbacks.on_disable then + return; + end + + for _, window in ipairs(windows) do + pcall(markview.configuration.callbacks.on_disable, buffer, window); + end + return; end if markview.state.buf_states[buffer] == false then + -- Call the on_disable callback before exiting + -- Even if only the buffer is disabled + if not markview.configuration.callbacks or not markview.configuration.callbacks.on_disable then + return; + end + + for _, window in ipairs(windows) do + pcall(markview.configuration.callbacks.on_disable, buffer, window); + end + return; end markview.state.buf_states[buffer] = true; - if vim.tbl_isempty(markview.global_options) then - markview.global_options = { - conceallevel = vim.o.conceallevel, - concealcursor = vim.o.concealcursor - } - end - - local parsed_content = markview.parser.init(buffer); + local parsed_content = markview.parser.init(buffer, markview.configuration); markview.renderer.clear(buffer); markview.renderer.render(buffer, parsed_content, markview.configuration) for _, window in ipairs(windows) do - vim.wo[window].conceallevel = type(options.on_enable) == "table" and options.on_enable.conceallevel or 2; - vim.wo[window].concealcursor = type(options.on_enable) == "table" and options.on_enable.concealcursor or "n"; + if markview.configuration.callbacks and markview.configuration.callbacks.on_enable then + pcall(markview.configuration.callbacks.on_enable, buffer, window); + end markview.keymaps.init(buffer, window, parsed_content, markview.configuration); end @@ -93,61 +109,112 @@ vim.api.nvim_create_autocmd({ "ModeChanged", "TextChanged" }, { return; end - if vim.islist(markview.configuration.modes) and vim.list_contains(markview.configuration.modes, mode) then - local parsed_content = markview.parser.init(buffer); - local cursor = vim.api.nvim_win_get_cursor(0) or {1, 0}; + -- Only on mode change + if event.event == "ModeChanged" then + -- Call the on_mode_change callback before exiting + if not markview.configuration.callbacks or not markview.configuration.callbacks.on_mode_change then + goto noCallbacks; + end - local draw_start, draw_stop = utils.get_cursor_range(buffer, windows[1], markview.configuration); + for _, window in ipairs(windows) do + pcall(markview.configuration.callbacks.on_mode_change, buffer, window, mode); + end + end + + ::noCallbacks:: + + if markview.configuration.modes and vim.list_contains(markview.configuration.modes, mode) then + local parsed_content = markview.parser.init(buffer, markview.configuration); + local parse_start, parse_stop = utils.get_cursor_range(buffer, windows[1]); markview.renderer.clear(buffer); - markview.renderer.render(buffer, parsed_content, markview.configuration, draw_start, draw_stop); - if vim.list_contains(markview.configuration.modes, "i") and mode == "i" then - local partial_contents = markview.parser.parse_range(buffer, draw_start, draw_stop); + local partial_contents = markview.parser.parse_range(event.buf, markview.configuration, parse_start, parse_stop); + local current_range = markview.renderer.get_content_range(partial_contents); - markview.renderer.clear_partial_range(buffer, partial_contents); - -- markview.renderer.render_deleted(event.buf, cursor, markview.configuration); - -- markview.renderer.clear_under_cursor(buffer, cursor); + if markview.configuration.hybrid_modes and vim.list_contains(markview.configuration.hybrid_modes, mode) then + markview.renderer.render(buffer, parsed_content, markview.configuration, parse_start, parse_stop); + markview.renderer.clear_content_range(event.buf, partial_contents) + else + markview.renderer.render(buffer, parsed_content, markview.configuration); end - for _, window in ipairs(windows) do - vim.wo[window].conceallevel = type(options.on_enable) == "table" and options.on_enable.conceallevel or 2; - vim.wo[window].concealcursor = type(options.on_enable) == "table" and options.on_enable.concealcursor or "n"; + -- Or else things won't render on first redraw from the other autocmd + markview.renderer.update_range(buffer, current_range); + for _, window in ipairs(windows) do markview.keymaps.init(buffer, window, parsed_content, markview.configuration); end else - for _, window in ipairs(windows) do - vim.wo[window].conceallevel = type(options.on_disable) == "table" and options.on_disable.conceallevel or markview.global_options.conceallevel; - vim.wo[window].concealcursor = type(options.on_disable) == "table" and options.on_disable.concealcursor or markview.global_options.concealcursor; - end - + -- Call an extra redraw to flush out screen updates markview.renderer.clear(buffer); + vim.cmd("redraw!"); end end }); -if not vim.list_contains(markview.configuration.modes, "i") then +if not markview.configuration.hybrid_modes then return; end +local events = {} local move_timer = vim.uv.new_timer(); -vim.api.nvim_create_autocmd({ "CursorMovedI" }, { +if vim.list_contains(markview.configuration.hybrid_modes, "n") or vim.list_contains(markview.configuration.hybrid_modes, "v") then + table.insert(events, "CursorMoved"); +end + +if vim.list_contains(markview.configuration.hybrid_modes, "i") then + table.insert(events, "CursorMovedI"); + table.insert(events, "TextChangedI"); -- For smoother experience when writing, potentially can cause bugs +end + +vim.api.nvim_create_autocmd(events, { buffer = vim.api.nvim_get_current_buf(), group = markview_augroup, callback = function (event) + if markview.state.enable == false then + move_timer:stop(); + return; + end + + if markview.state.buf_states[event.buf] == false then + move_timer:stop(); + return; + end + move_timer:stop(); move_timer:start(100, 0, vim.schedule_wrap(function () - local prev_contents = markview.parser.parse_range(event.buf); + if not _G.__markview_render_ranges then + _G.__markview_render_ranges = {}; + end + + if not _G.__markview_render_ranges[event.buf] then + _G.__markview_render_ranges[event.buf] = {}; + end + + local windows = utils.find_attached_wins(event.buf); + + local old_start, old_stop = _G.__markview_render_ranges[event.buf][1], _G.__markview_render_ranges[event.buf][2]; + local parse_start, parse_stop = utils.get_cursor_range(event.buf, windows[1]); + + local prev_contents = markview.parser.parse_range(event.buf, markview.configuration, old_start, old_stop); + local partial_contents = markview.parser.parse_range(event.buf, markview.configuration, parse_start, parse_stop); + + local current_range = markview.renderer.get_content_range(partial_contents); + + if _G.__markview_render_ranges[event.buf] and vim.deep_equal(_G.__markview_render_ranges[event.buf], current_range) then + markview.renderer.clear_content_range(event.buf, partial_contents) + return; + end - local draw_start, draw_stop = utils.get_cursor_range(event.buf, 0, markview.configuration); - local partial_contents = markview.parser.parse_range(event.buf, draw_start, draw_stop); + markview.renderer.clear_content_range(event.buf, partial_contents) + markview.renderer.clear_content_range(event.buf, prev_contents); + markview.renderer.clear(event.buf, parse_start, parse_stop); - markview.renderer.clear_partial_range(event.buf, prev_contents); - markview.renderer.render_partial(event.buf, prev_contents, markview.configuration, draw_start, draw_stop); - markview.renderer.clear_partial_range(event.buf, partial_contents); + markview.renderer.render_in_range(event.buf, prev_contents, markview.configuration); + markview.renderer.update_range(event.buf, current_range); end)); end }) diff --git a/images/headings.jpg b/images/headings.jpg deleted file mode 100644 index 4653213..0000000 Binary files a/images/headings.jpg and /dev/null differ diff --git a/images/lists.jpg b/images/lists.jpg deleted file mode 100644 index f05449c..0000000 Binary files a/images/lists.jpg and /dev/null differ diff --git a/images/preview_1.png b/images/preview_1.png deleted file mode 100644 index fb49d52..0000000 Binary files a/images/preview_1.png and /dev/null differ diff --git a/images/tables.jpg b/images/tables.jpg deleted file mode 100644 index cc135fb..0000000 Binary files a/images/tables.jpg and /dev/null differ diff --git a/lua/definitions.lua b/lua/definitions.lua index 4e57138..ff235f2 100644 --- a/lua/definitions.lua +++ b/lua/definitions.lua @@ -16,8 +16,11 @@ --- List of modes where the plugin will be active ---@field modes string[]? --- ---- Options for various plugins states ----@field options markview.config.options? +--- List of modes where both raw & preview is shown +---@field hybrid_modes string[]? +--- +--- Callbacks for plugin states +---@field callbacks markview.config.callbacks? --- --- Table for heading configuration ---@field headings markview.render_config.headings? @@ -59,8 +62,11 @@ --- List of modes where the plugin will be active ---@field modes string[] --- +--- List of modes where both raw & preview is shown +---@field hybrid_modes string[]? +--- --- Options for various plugins states ----@field options markview.config.options +---@field callbacks markview.config.callbacks --- --- Table for heading configuration ---@field headings markview.render_config.headings @@ -77,7 +83,7 @@ --- Table for hyperlink configuration ---@field links markview.render_config.links --- ---- Table for hyperlink configuration +--- Table for inline code configuration ---@field inline_codes markview.render_config.inline_codes --- --- Table for list item configuration @@ -90,20 +96,14 @@ ---@field tables markview.render_config.tables ---- Definition for the options ----@class markview.config.options +--- Definition for the plugin callbacks +---@class markview.config.callbacks --- ----@field on_enable markview.config.options.available +---@field on_enable function? --- ----@field on_disable markview.config.options.available - ---- Available options ----@class markview.config.options.available ---- ---- Conceal level ----@field conceallevel number +---@field on_disable function? --- ----@field concealcursor string? +---@field on_mode_change function? --------------------------------------------------------------- --- For rendering things @@ -137,7 +137,7 @@ --- Used for highlighting the line when the style is "simple" ---@field hl string? --- ---- Character added before the heading name to seperate heading levels +--- Character added before the heading name to separate heading levels ---@field shift_char string? --- --- Highlight group for shift_char @@ -258,10 +258,7 @@ ---@class markview.render_config.block_quotes.callouts --- --- String to match to detect the callout, this is not case-sensitive ----@field match_string string ---- ---- Aliases for the callout, this is not case-sensitive ----@field aliases string[]? +---@field match_string string|string[] --- --- The text to show for the callout ---@field callout_preview string @@ -319,7 +316,7 @@ --- Enable/Disable custom hyperlink ---@field enable boolean? --- ----@field inline_links markview.render_config.links.link +---@field hyperlinks markview.render_config.links.link --- ---@field images markview.render_config.links.link --- @@ -371,12 +368,6 @@ --- Default highlight group for the various parts ---@field hl string? --- ---- Custom text for the heading. The heading text is used when nil ----@field text string? ---- ---- Highlight group for the heading text, inherits from icon_hl ----@field text_hl string? ---- --- Used bu the "label" style to add text before the left padding ---@field corner_left string? --- diff --git a/lua/markview.lua b/lua/markview.lua index 3e31206..12008ce 100644 --- a/lua/markview.lua +++ b/lua/markview.lua @@ -1,11 +1,11 @@ local markview = {}; local utils = require("markview.utils"); -markview.parser = require("markview/parser"); -markview.renderer = require("markview/renderer"); -markview.keymaps = require("markview/keymaps"); +markview.parser = require("markview.parser"); +markview.renderer = require("markview.renderer"); +markview.keymaps = require("markview.keymaps"); -markview.colors = require("markview/colors"); +markview.colors = require("markview.colors"); markview.add_hls = function (obj) local use_hl = {}; @@ -43,264 +43,896 @@ markview.global_options = {}; ---@type markview.config markview.configuration = { - options = { - on_enable = { - conceallevel = 2, - concealcursor = "n" - }, - - on_disable = { - conceallevel = 0, - concealcursor = "" - } + callbacks = { + on_enable = function (buffer, window) + vim.wo[window].conceallevel = 2; + vim.wo[window].concealcursor = "nc"; + end, + on_disable = function (buffer, window) + vim.wo[window].conceallevel = 0; + vim.wo[window].concealcursor = ""; + end, + + on_mode_change = function (buffer, window, mode) + if vim.list_contains(markview.configuration.modes, mode) then + vim.wo[window].conceallevel = 2; + else + vim.wo[window].conceallevel = 0; + end + end }, highlight_groups = { + ---+ ##code## { + -- Heading level 1 output = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "markdownH1", "fg") or "#f38ba8"; - - return { - { - group_name = "Col1", - value = { - bg = markview.colors.mix(bg, fg, 0.7, 0.25), - fg = fg - } - }, - { - group_name = "Col1Fg", - value = { - fg = fg - } - }, - { - group_name = "Col1Inv", - value = { - bg = fg, - fg = bg - } - }, - } + if markview.colors.get_hl_value(0, "DiagnosticVirtualTextOk", "bg") and markview.colors.get_hl_value(0, "DiagnosticVirtualTextOk", "fg") then + local bg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextOk", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextOk", "fg"); + + return { + { + group_name = "Heading1", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading1Sign", + value = { + fg = fg, + + default = true + } + }, + } + elseif markview.colors.get_hl_value(0, "DiagnosticOk", "fg") and markview.colors.get_hl_value(0, "Normal", "bg") then + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticOk", "fg"); + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading1", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading1Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + else + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = vim.o.background == "dark" and "#a6e3a1" or "#40a02b"; + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading1", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading1Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + end end }, - { + -- Heading level 2 output = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "markdownH2", "fg") or "#fab387"; - - return { - { - group_name = "Col2", - value = { - bg = markview.colors.mix(bg, fg, 0.7, 0.25), - fg = fg - } - }, - { - group_name = "Col2Fg", - value = { - fg = fg - } - }, - { - group_name = "Col2Inv", - value = { - bg = fg, - fg = bg - } - }, - } + if markview.colors.get_hl_value(0, "DiagnosticVirtualTextHint", "bg") and markview.colors.get_hl_value(0, "DiagnosticVirtualTextHint", "fg") then + local bg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextHint", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextHint", "fg"); + + return { + { + group_name = "Heading2", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading2Sign", + value = { + fg = fg, + + default = true + } + }, + } + elseif markview.colors.get_hl_value(0, "DiagnosticHint", "fg") and markview.colors.get_hl_value(0, "Normal", "bg") then + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticHint", "fg"); + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading2", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading2Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + else + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = vim.o.background == "dark" and "#94e2d5" or "#179299"; + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading2", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading2Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + end end }, - { + -- Heading level 3 output = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "markdownH3", "fg") or "#f9e2af"; - - return { - { - group_name = "Col3", - value = { - bg = markview.colors.mix(bg, fg, 0.7, 0.25), - fg = fg - } - }, - { - group_name = "Col3Fg", - value = { - fg = fg - } - }, - { - group_name = "Col3Inv", - value = { - bg = fg, - fg = bg - } - }, - } + if markview.colors.get_hl_value(0, "DiagnosticVirtualTextInfo", "bg") and markview.colors.get_hl_value(0, "DiagnosticVirtualTextInfo", "fg") then + local bg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextInfo", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextInfo", "fg"); + + return { + { + group_name = "Heading3", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading3Sign", + value = { + fg = fg, + + default = true + } + }, + } + elseif markview.colors.get_hl_value(0, "DiagnosticInfo", "fg") and markview.colors.get_hl_value(0, "Normal", "bg") then + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticInfo", "fg"); + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading3", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading3Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + else + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = vim.o.background == "dark" and "#89dceb" or "#179299"; + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading3", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading3Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + end end }, - { + -- Heading level 4 output = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "markdownH4", "fg") or "#a6e3a1"; - - - return { - { - group_name = "Col4", - value = { - bg = markview.colors.mix(bg, fg, 0.7, 0.25), - fg = fg - } - }, - { - group_name = "Col4Fg", - value = { - fg = fg - } - }, - { - group_name = "Col4Inv", - value = { - bg = fg, - fg = bg - } - }, - } + if markview.colors.get_hl_value(0, "Special", "bg") and markview.colors.get_hl_value(0, "Special", "fg") then + local bg = markview.colors.get_hl_value(0, "Special", "bg"); + local fg = markview.colors.get_hl_value(0, "Special", "fg"); + + return { + { + group_name = "Heading4", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading4Sign", + value = { + fg = fg, + + default = true + } + }, + } + elseif markview.colors.get_hl_value(0, "Special", "fg") and markview.colors.get_hl_value(0, "Normal", "bg") then + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = markview.colors.get_hl_value(0, "Special", "fg"); + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading4", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading4Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + else + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = vim.o.background == "dark" and "#f5c2e7" or "#ea76cb"; + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading4", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading4Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + end end }, - { + -- Heading level 5 output = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "markdownH5", "fg") or "#74c7ec"; - - return { - { - group_name = "Col5", - value = { - bg = markview.colors.mix(bg, fg, 0.7, 0.25), - fg = fg - } - }, - { - group_name = "Col5Fg", - value = { - fg = fg - } - }, - { - group_name = "Col5Inv", - value = { - bg = fg, - fg = bg - } - }, - } + if markview.colors.get_hl_value(0, "DiagnosticVirtualTextWarn", "bg") and markview.colors.get_hl_value(0, "DiagnosticVirtualTextWarn", "fg") then + local bg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextWarn", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextWarn", "fg"); + + return { + { + group_name = "Heading5", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading5Sign", + value = { + fg = fg, + + default = true + } + }, + } + elseif markview.colors.get_hl_value(0, "DiagnosticWarn", "fg") and markview.colors.get_hl_value(0, "Normal", "bg") then + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticWarn", "fg"); + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading5", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading5Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + else + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = vim.o.background == "dark" and "#F9E3AF" or "#DF8E1D"; + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading5", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading5Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + end end }, - { + -- Heading level 6 output = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "markdownH6", "fg") or "#b4befe"; - - return { - { - group_name = "Col6", - value = { - bg = markview.colors.mix(bg, fg, 0.7, 0.25), - fg = fg - } - }, - { - group_name = "Col6Fg", - value = { - fg = fg - } - }, - { - group_name = "Col6Inv", - value = { - bg = fg, - fg = bg - } - }, - } + if markview.colors.get_hl_value(0, "DiagnosticVirtualTextError", "bg") and markview.colors.get_hl_value(0, "DiagnosticVirtualTextError", "fg") then + local bg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextError", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticVirtualTextError", "fg"); + + return { + { + group_name = "Heading6", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading6Sign", + value = { + fg = fg, + + default = true + } + }, + } + elseif markview.colors.get_hl_value(0, "DiagnosticError", "fg") and markview.colors.get_hl_value(0, "Normal", "bg") then + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = markview.colors.get_hl_value(0, "DiagnosticError", "fg"); + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading6", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading6Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + else + local bg = markview.colors.get_hl_value(0, "Normal", "bg"); + local fg = vim.o.background == "dark" and "#F38BA8" or "#D20F39"; + + local nr = markview.colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading6", + value = { + bg = vim.o.background == "dark" + and + markview.colors.mix(bg, fg, 0.5, 0.15) + or + markview.colors.mix(bg, fg, 0.85, 0.20), + fg = fg, + + default = true + } + }, + { + group_name = "Heading6Sign", + value = { + bg = nr, + fg = fg, + + default = true + } + }, + } + end end }, + { - output = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "Comment", "fg"); - - return { - { - group_name = "Col7", - value = { - bg = markview.colors.mix(bg, fg, 0.7, 0.25), - fg = fg - } - }, - { - group_name = "Col7Fg", - value = { - fg = fg - } - }, - { - group_name = "Col7Inv", - value = { - bg = fg, - fg = bg - } - }, - } + group_name = "BlockQuoteDefault", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "Comment", "fg"), + + vim.o.background == "dark" and "#6c7086" or "#9ca0b0"; + }); + + return { fg = fg, default = true }; end }, + { + group_name = "BlockQuoteError", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "DiagnosticError", "fg"), + + vim.o.background == "dark" and "#F38BA8" or "#D20F39"; + }); + return { fg = fg, default = true }; + end + }, { - group_name = "Layer", + group_name = "BlockQuoteWarn", value = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "Comment", "fg"); + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "DiagnosticWarn", "fg"), - local txt = markview.colors.get_hl_value(0, "FloatTitle", "fg") + vim.o.background == "dark" and "#F9E3AF" or "#DF8E1D"; + }); - return { - bg = markview.colors.mix(bg, fg, 1, 0.20), - fg = txt - } + return { fg = fg, default = true }; end }, { - group_name = "Layer2", + group_name = "BlockQuoteOk", value = function () - local bg = markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"); - local fg = markview.colors.get_hl_value(0, "Comment", "fg"); + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "DiagnosticOk", "fg"), - return { - bg = markview.colors.mix(bg, fg, 0.85, 0.13), - } + vim.o.background == "dark" and "#a6e3a1" or "#40a02b"; + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "BlockQuoteNote", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "@comment.note", "bg"), + markview.colors.get_hl_value(0, "@comment.note", "fg"), + + markview.colors.get_hl_value(0, "Title", "fg"), + vim.o.background == "dark" and "#89b4fa" or "#1e66f5" + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "BlockQuoteSpecial", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "Conditional", "fg"), + markview.colors.get_hl_value(0, "Keyword", "fg"), + + vim.o.background == "dark" and "#cba6f7" or "#8839ef" + }); + + return { fg = fg, default = true }; + end + }, + + + + { + group_name = "Code", + value = function () + local bg = markview.colors.get({ + markview.colors.get_hl_value(0, "Normal", "bg"), + markview.colors.get_hl_value(0, "Cursor", "fg"), + + vim.o.background == "dark" and "#1e1e2e" or "#cdd6f4" + }); + + local luminosity = markview.colors.get_brightness(bg); + + if luminosity < 0.5 then + return { + bg = markview.colors.mix(bg, bg, 1, math.max(luminosity, 0.25)), + default = true + }; + else + return { + bg = markview.colors.mix(bg, bg, 1, math.min(luminosity, 0.25) * -1), + default = true + }; + end end }, + { + group_name = "InlineCode", + value = function () + local bg = markview.colors.get({ + markview.colors.get_hl_value(0, "Normal", "bg"), + markview.colors.get_hl_value(0, "Cursor", "fg"), + + vim.o.background == "dark" and "#1e1e2e" or "#cdd6f4" + }); + + local luminosity = markview.colors.get_brightness(bg); + + if luminosity < 0.5 then + return { + bg = markview.colors.mix(bg, bg, 1, math.max(luminosity, 0.5)), + default = true + }; + else + return { + bg = markview.colors.mix(bg, bg, 1, math.min(luminosity, 0.5) * -1), + default = true + }; + end + end + }, + + + { + group_name = "CheckboxChecked", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "DiagnosticOk", "fg"), + + vim.o.background == "dark" and "#a6e3a1" or "#40a02b"; + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "CheckboxUnchecked", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "DiagnosticError", "fg"), + + vim.o.background == "dark" and "#F38BA8" or "#D20F39"; + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "CheckboxPending", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "DiagnosticWarn", "fg"), + + vim.o.background == "dark" and "#F9E3AF" or "#DF8E1D"; + }); + + return { fg = fg, default = true }; + end + }, + + + { + group_name = "TableBorder", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "@comment.note", "bg"), + markview.colors.get_hl_value(0, "@comment.note", "fg"), + + markview.colors.get_hl_value(0, "Title", "fg"), + vim.o.background == "dark" and "#89b4fa" or "#1e66f5" + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "TableAlignLeft", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "@comment.note", "bg"), + markview.colors.get_hl_value(0, "@comment.note", "fg"), + + markview.colors.get_hl_value(0, "Title", "fg"), + vim.o.background == "dark" and "#89b4fa" or "#1e66f5" + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "TableAlignRight", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "@comment.note", "bg"), + markview.colors.get_hl_value(0, "@comment.note", "fg"), + + markview.colors.get_hl_value(0, "Title", "fg"), + vim.o.background == "dark" and "#89b4fa" or "#1e66f5" + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "TableAlignCenter", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "@comment.note", "bg"), + markview.colors.get_hl_value(0, "@comment.note", "fg"), + + markview.colors.get_hl_value(0, "Title", "fg"), + vim.o.background == "dark" and "#89b4fa" or "#1e66f5" + }); + + return { fg = fg, default = true }; + end + }, + + + { + group_name = "ListItemMinus", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "DiagnosticWarn", "fg"), + + vim.o.background == "dark" and "#F9E3AF" or "#DF8E1D"; + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "ListItemPlus", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "DiagnosticOk", "fg"), + + vim.o.background == "dark" and "#a6e3a1" or "#40a02b"; + }); + + return { fg = fg, default = true }; + end + }, + { + group_name = "ListItemStar", + value = function () + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "@comment.note", "bg"), + markview.colors.get_hl_value(0, "@comment.note", "fg"), + + markview.colors.get_hl_value(0, "Title", "fg"), + vim.o.background == "dark" and "#89b4fa" or "#1e66f5" + }); + + return { fg = fg, default = true }; + end + }, + + + { + group_name = "Hyperlink", + value = function () + if markview.colors.get_hl_value(0, "markdownLinkText", "fg") then + return { link = "markdownLinkText", default = true }; + elseif markview.colors.get_hl_value(0, "@markup.link.label.markdown_inline", "fg") then + return { link = "@markup.link.label.markdown_inline", default = true }; + end + + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "Label", "fg"), + + vim.o.background == "dark" and "#74c7ec" or "#209fb5" + }); + + return { fg = fg, underline = true, default = true }; + end + }, + { + group_name = "ImageLink", + value = function () + if markview.colors.get_hl_value(0, "markdownLinkText", "fg") then + return { link = "markdownLinkText", default = true }; + elseif markview.colors.get_hl_value(0, "@markup.link.label.markdown_inline", "fg") then + return { link = "@markup.link.label.markdown_inline", default = true }; + end + + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "Label", "fg"), + + vim.o.background == "dark" and "#74c7ec" or "#209fb5" + }); + + return { fg = fg, underline = true, default = true }; + end + }, + { + group_name = "Email", + value = function () + if markview.colors.get_hl_value(0, "@markup.link.url.markdown_inline", "fg") then + return { link = "@markup.link.url.markdown_inline", default = true }; + elseif markview.colors.get_hl_value(0, "@markup.link.url", "fg") then + return { link = "@markup.link.url", default = true }; + end + + local fg = markview.colors.get({ + markview.colors.get_hl_value(0, "Label", "fg"), + + vim.o.background == "dark" and "#f5e0dc" or "#dc8a78" + }); + + return { fg = fg, underline = true, default = true }; + end + }, + + { output = function () return markview.colors.create_gradient("Gradient", markview.colors.get_hl_value(0, "Normal", "bg") or markview.colors.get_hl_value(0, "Cursor", "fg"), markview.colors.get_hl_value(0, "Title", "fg"), 10, "fg"); end } + ---_ }, buf_ignore = { "nofile" }, modes = { "n", "no" }, + special_modes = nil, headings = { enable = true, @@ -308,48 +940,48 @@ markview.configuration = { heading_1 = { style = "icon", - sign = "󰌕 ", sign_hl = "MarkviewCol1Fg", + sign = "󰌕 ", sign_hl = "MarkviewHeading1Sign", - icon = "󰼏 ", hl = "MarkviewCol1", + icon = "󰼏 ", hl = "MarkviewHeading1", }, heading_2 = { style = "icon", - sign = "󰌖 ", sign_hl = "MarkviewCol2Fg", + sign = "󰌖 ", sign_hl = "MarkviewHeading2Sign", - icon = "󰎨 ", hl = "MarkviewCol2", + icon = "󰎨 ", hl = "MarkviewHeading2", }, heading_3 = { style = "icon", - icon = "󰼑 ", hl = "MarkviewCol3", + icon = "󰼑 ", hl = "MarkviewHeading3", }, heading_4 = { style = "icon", - icon = "󰎲 ", hl = "MarkviewCol4", + icon = "󰎲 ", hl = "MarkviewHeading4", }, heading_5 = { style = "icon", - icon = "󰼓 ", hl = "MarkviewCol5", + icon = "󰼓 ", hl = "MarkviewHeading5", }, heading_6 = { style = "icon", - icon = "󰎴 ", hl = "MarkviewCol6", + icon = "󰎴 ", hl = "MarkviewHeading6", }, setext_1 = { style = "github", - icon = "  ", hl = "MarkviewCol1", + icon = "  ", hl = "MarkviewHeading1", underline = "━" }, setext_2 = { style = "github", - icon = "  ", hl = "MarkviewCol2", + icon = "  ", hl = "MarkviewHeading2", underline = "─" } }, @@ -358,7 +990,7 @@ markview.configuration = { enable = true, style = "language", - hl = "Layer2", + hl = "MarkviewCode", min_width = 60, pad_amount = 3, @@ -376,7 +1008,7 @@ markview.configuration = { enable = true, default = { - border = "▋", border_hl = "MarkviewCol7Fg" + border = "▋", border_hl = "MarkviewBlockQuoteDefault" }, callouts = { @@ -384,139 +1016,139 @@ markview.configuration = { { match_string = "ABSTRACT", callout_preview = "󱉫 Abstract", - callout_preview_hl = "MarkviewCol5Fg", + callout_preview_hl = "MarkviewBlockQuoteNote", custom_title = true, custom_icon = "󱉫 ", - border = "▋", border_hl = "MarkviewCol5Fg" + border = "▋", border_hl = "MarkviewBlockQuoteNote" }, { match_string = "TODO", callout_preview = " Todo", - callout_preview_hl = "MarkviewCol5Fg", + callout_preview_hl = "MarkviewBlockQuoteNote", custom_title = true, custom_icon = " ", - border = "▋", border_hl = "MarkviewCol5Fg" + border = "▋", border_hl = "MarkviewBlockQuoteNote" }, { match_string = "SUCCESS", callout_preview = "󰗠 Success", - callout_preview_hl = "MarkviewCol4Fg", + callout_preview_hl = "MarkviewBlockQuoteOk", custom_title = true, custom_icon = "󰗠 ", - border = "▋", border_hl = "MarkviewCol4Fg" + border = "▋", border_hl = "MarkviewBlockQuoteOk" }, { match_string = "QUESTION", callout_preview = "󰋗 Question", - callout_preview_hl = "MarkviewCol2Fg", + callout_preview_hl = "MarkviewBlockQuoteWarn", custom_title = true, custom_icon = "󰋗 ", - border = "▋", border_hl = "MarkviewCol2Fg" + border = "▋", border_hl = "MarkviewBlockQuoteWarn" }, { match_string = "FAILURE", callout_preview = "󰅙 Failure", - callout_preview_hl = "MarkviewCol1Fg", + callout_preview_hl = "MarkviewBlockQuoteError", custom_title = true, custom_icon = "󰅙 ", - border = "▋", border_hl = "MarkviewCol1Fg" + border = "▋", border_hl = "MarkviewBlockQuoteError" }, { match_string = "DANGER", callout_preview = " Danger", - callout_preview_hl = "MarkviewCol1Fg", + callout_preview_hl = "MarkviewBlockQuoteError", custom_title = true, custom_icon = "  ", - border = "▋", border_hl = "MarkviewCol1Fg" + border = "▋", border_hl = "MarkviewBlockQuoteError" }, { match_string = "BUG", callout_preview = " Bug", - callout_preview_hl = "MarkviewCol1Fg", + callout_preview_hl = "MarkviewBlockQuoteError", custom_title = true, custom_icon = "  ", - border = "▋", border_hl = "MarkviewCol1Fg" + border = "▋", border_hl = "MarkviewBlockQuoteError" }, { match_string = "EXAMPLE", callout_preview = "󱖫 Example", - callout_preview_hl = "MarkviewCol6Fg", + callout_preview_hl = "MarkviewBlockQuoteSpecial", custom_title = true, custom_icon = " 󱖫 ", - border = "▋", border_hl = "MarkviewCol6Fg" + border = "▋", border_hl = "MarkviewBlockQuoteSpecial" }, { match_string = "QUOTE", callout_preview = " Quote", - callout_preview_hl = "MarkviewCol7Fg", + callout_preview_hl = "MarkviewBlockQuoteDefault", custom_title = true, custom_icon = "  ", - border = "▋", border_hl = "MarkviewCol7Fg" + border = "▋", border_hl = "MarkviewBlockQuoteDefault" }, { match_string = "NOTE", callout_preview = "󰋽 Note", - callout_preview_hl = "MarkviewCol5Fg", + callout_preview_hl = "MarkviewBlockQuoteNote", - border = "▋", border_hl = "MarkviewCol5Fg" + border = "▋", border_hl = "MarkviewBlockQuoteNote" }, { match_string = "TIP", callout_preview = " Tip", - callout_preview_hl = "MarkviewCol4Fg", + callout_preview_hl = "MarkviewBlockQuoteOk", - border = "▋", border_hl = "MarkviewCol4Fg" + border = "▋", border_hl = "MarkviewBlockQuoteOk" }, { match_string = "IMPORTANT", callout_preview = " Important", - callout_preview_hl = "MarkviewCol3Fg", + callout_preview_hl = "MarkviewBlockQuoteSpecial", - border = "▋", border_hl = "MarkviewCol3Fg" + border = "▋", border_hl = "MarkviewBlockQuoteSpecial" }, { match_string = "WARNING", callout_preview = " Warning", - callout_preview_hl = "MarkviewCol2Fg", + callout_preview_hl = "MarkviewBlockQuoteWarn", - border = "▋", border_hl = "MarkviewCol2Fg" + border = "▋", border_hl = "MarkviewBlockQuoteWarn" }, { match_string = "CAUTION", callout_preview = "󰳦 Caution", - callout_preview_hl = "MarkviewCol1Fg", + callout_preview_hl = "MarkviewBlockQuoteError", - border = "▋", border_hl = "MarkviewCol1Fg" + border = "▋", border_hl = "MarkviewBlockQuoteError" }, { match_string = "CUSTOM", callout_preview = "󰠳 Custom", - callout_preview_hl = "MarkviewCol3Fg", + callout_preview_hl = "MarkviewBlockQuoteWarn", custom_title = true, custom_icon = " 󰠳 ", - border = "▋", border_hl = "MarkviewCol3Fg" + border = "▋", border_hl = "MarkviewBlockQuoteWarn" } } }, @@ -557,21 +1189,46 @@ markview.configuration = { } } }, + html = { + tags = { + enable = true, + + default = { + conceal = false + }, + + configs = { + b = { conceal = true, hl = "Bold" }, + strong = { conceal = true, hl = "Bold" }, + + u = { conceal = true, hl = "Underlined" }, + + i = { conceal = true, hl = "Italic" }, + emphasize = { conceal = true, hl = "Italic" }, + + marked = { conceal = true, hl = "Special" }, + } + }, + + entites = { + enable = true + } + }, links = { enable = true, - inline_links = { - icon = "󰌷 ", icon_hl = "markdownLinkText", - hl = "markdownLinkText", + hyperlinks = { + icon = "󰌷 ", + hl = "MarkviewHyperlink", }, images = { - icon = "󰥶 ", icon_hl = "markdownLinkText", - hl = "markdownLinkText", + icon = "󰥶 ", + hl = "MarkviewImageLink", }, emails = { - icon = " ", icon_hl = "@markup.link.url", - hl = "@markup.link.url", + icon = " ", + hl = "MarkviewEmail", } }, @@ -580,7 +1237,7 @@ markview.configuration = { corner_left = " ", corner_right = " ", - hl = "Layer" + hl = "MarkviewInlineCode" }, list_items = { @@ -588,19 +1245,19 @@ markview.configuration = { add_padding = true, text = "", - hl = "markviewCol2Fg" + hl = "MarkviewListItemMinus" }, marker_plus = { add_padding = true, text = "", - hl = "markviewCol4Fg" + hl = "MarkviewListItemPlus" }, marker_star = { add_padding = true, text = "", - text_hl = "markviewCol6Fg" + text_hl = "MarkviewListItemStar" }, marker_dot = { add_padding = true @@ -611,13 +1268,13 @@ markview.configuration = { enable = true, checked = { - text = "✔", hl = "markviewCol4Fg" + text = "✔", hl = "MarkviewCheckboxChecked" }, pending = { - text = "◯", hl = "MarkviewCol2Fg" + text = "◯", hl = "MarkviewCheckboxPending" }, unchecked = { - text = "✘", hl = "MarkviewCol1Fg" + text = "✘", hl = "MarkviewCheckboxUnchecked" } }, @@ -631,14 +1288,14 @@ markview.configuration = { "╼", "╾", "╴", "╶" }, hl = { - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg" + "MarkviewTableAlignLeft", "MarkviewTableAlignRight", "MarkviewTableAlignCenter", "MarkviewTableAlignCenter" }, - use_virt_lines = false + use_virt_lines = true }, }; @@ -661,13 +1318,15 @@ markview.commands = { for _, buf in ipairs(markview.attached_buffers) do local parsed_content = markview.parser.init(buf); local windows = utils.find_attached_wins(buffer); - local options = markview.configuration.options or {}; - for _, window in ipairs(windows) do - vim.wo[window].conceallevel = type(options.on_enable) == "table" and options.on_enable.conceallevel or 2; - vim.wo[window].concealcursor = type(options.on_enable) == "table" and options.on_enable.concealcursor or "n"; + if markview.configuration.callbacks and markview.configuration.callbacks.on_enable then + for _, window in ipairs(windows) do + pcall(markview.configuration.callbacks.on_enable, buf, window); + end end + markview.state.buf_states[buf] = true; + markview.renderer.clear(buf); markview.renderer.render(buf, parsed_content, markview.configuration) end @@ -675,13 +1334,15 @@ markview.commands = { disableAll = function () for _, buf in ipairs(markview.attached_buffers) do local windows = utils.find_attached_wins(buffer); - local options = markview.configuration.options or {}; - for _, window in ipairs(windows) do - vim.wo[window].conceallevel = type(options.on_disable) == "table" and options.on_disable.conceallevel or markview.global_options.conceallevel; - vim.wo[window].concealcursor = type(options.on_disable) == "table" and options.on_disable.concealcursor or markview.global_options.concealcursor; + if markview.configuration.callbacks and markview.configuration.callbacks.on_disable then + for _, window in ipairs(windows) do + pcall(markview.configuration.callbacks.on_disable, buf, window); + end end + markview.state.buf_states[buf] = false; + markview.renderer.clear(buf); end @@ -707,7 +1368,6 @@ markview.commands = { end, enable = function (buf) local buffer = tonumber(buf) or vim.api.nvim_get_current_buf(); - local options = markview.configuration.options or {}; if not vim.list_contains(markview.attached_buffers, buffer) or not vim.api.nvim_buf_is_valid(buffer) then return; @@ -720,8 +1380,7 @@ markview.commands = { markview.state.buf_states[buffer] = true; for _, window in ipairs(windows) do - vim.wo[window].conceallevel = type(options.on_enable) == "table" and options.on_enable.conceallevel or 2; - vim.wo[window].concealcursor = type(options.on_enable) == "table" and options.on_enable.concealcursor or "n"; + pcall(markview.configuration.callbacks.on_enable, buf, window); end markview.renderer.clear(buffer); @@ -730,7 +1389,6 @@ markview.commands = { disable = function (buf) local buffer = tonumber(buf) or vim.api.nvim_get_current_buf(); - local options = markview.configuration.options or {}; if not vim.list_contains(markview.attached_buffers, buffer) or not vim.api.nvim_buf_is_valid(buffer) then return; @@ -739,8 +1397,7 @@ markview.commands = { local windows = utils.find_attached_wins(buffer); for _, window in ipairs(windows) do - vim.wo[window].conceallevel = type(options.on_disable) == "table" and options.on_disable.conceallevel or markview.global_options.conceallevel; - vim.wo[window].concealcursor = type(options.on_disable) == "table" and options.on_disable.concealcursor or markview.global_options.concealcursor; + pcall(markview.configuration.callbacks.on_disable, buf, window); end markview.renderer.clear(buffer); @@ -817,7 +1474,6 @@ end, { end }) - markview.setup = function (user_config) ---@type markview.config -- Merged configuration tables diff --git a/lua/markview/colors.lua b/lua/markview/colors.lua index fd77497..26552a8 100644 --- a/lua/markview/colors.lua +++ b/lua/markview/colors.lua @@ -8,7 +8,55 @@ colors.lerp = function (x, y, t) return x + ((y - x) * t); end +colors.name_to_hex = function (name) + local lookup = { + ["red"] = "#FF0000", ["lightred"] = "#FFBBBB", ["darkred"] = "#8B0000", + ["green"] = "#00FF00", ["lightgreen"] = "#90EE90", ["darkgreen"] = "#006400", ["seagreen"] = "#2E8B57", + ["blue"] = "#0000FF", ["lightblue"] = "#ADD8E6", ["darkblue"] = "#00008B", ["slateblue"] = "#6A5ACD", + ["cyan"] = "#00FFFF", ["lightcyan"] = "#E0FFFF", ["darkcyan"] = "#008B8B", + ["magenta"] = "#FF00FF", ["lightmagenta"] = "#FFBBFF", ["darkmagenta"] = "#8B008B", + ["yellow"] = "#FFFF00", ["lightyellow"] = "#FFFFE0", ["darkyellow"] = "#BBBB00", ["brown"] = "#A52A2A", + ["grey"] = "#808080", ["lightgrey"] = "#D3D3D3", ["darkgrey"] = "#A9A9A9", + ["gray"] = "#808080", ["lightgray"] = "#D3D3D3", ["darkgray"] = "#A9A9A9", + ["black"] = "#000000", ["white"] = "#FFFFFF", + ["orange"] = "#FFA500", ["purple"] = "#800080", ["violet"] = "#EE82EE" + }; + + local lookup_nvim = { + ["nvimdarkblue"] = "#004C73", ["nvimlightblue"] = "#A6DBFF", + ["nvimdarkcyan"] = "#007373", ["nvimlightcyan"] = "#8CF8F7", + ["nvimdarkgray1"] = "#07080D", ["nvimlightgray1"] = "#EEF1F8", + ["nvimdarkgray2"] = "#14161B", ["nvimlightgray2"] = "#E0E2EA", + ["nvimdarkgray3"] = "#2C2E33", ["nvimlightgray3"] = "#C4C6CD", + ["nvimdarkgray4"] = "#4F5258", ["nvimlightgray4"] = "#9B9EA4", + ["nvimdarkgrey1"] = "#07080D", ["nvimlightgrey1"] = "#EEF1F8", + ["nvimdarkgrey2"] = "#14161B", ["nvimlightgrey2"] = "#E0E2EA", + ["nvimdarkgrey3"] = "#2C2E33", ["nvimlightgrey3"] = "#C4C6CD", + ["nvimdarkgrey4"] = "#4F5258", ["nvimlightgrey4"] = "#9B9EA4", + ["nvimdarkgreen"] = "#005523", ["nvimlightgreen"] = "#B3F6C0", + ["nvimdarkmagenta"] = "#470045", ["nvimlightmagenta"] = "#FFCAFF", + ["nvimdarkred"] = "#590008", ["nvimlightred"] = "#FFC0B9", + ["nvimdarkyellow"] = "#6B5300", ["nvimlightyellow"] = "#FCE094", + }; + + return lookup[string.lower(name)] or lookup_nvim[string.lower(name)]; +end + +colors.name_to_rgb = function (name) + local hex = colors.name_to_hex(name); + + if not hex then + return; + end + + return colors.hex_to_rgb(hex); +end + colors.num_to_hex = function (num) + if not num then + return; + end + if num == 0 then return "#000000"; elseif num ~= nil then @@ -17,6 +65,10 @@ colors.num_to_hex = function (num) end colors.num_to_rgb = function (num) + if not num then + return; + end + local hex = string.format("%x", num); return { @@ -49,14 +101,30 @@ colors.rgb_to_hex = function (tbl) end colors.get_hl_value = function (ns_id, hl_group, value) - local hl = vim.api.nvim_get_hl(ns_id, { name = hl_group, link = false }); + if vim.fn.hlexists(hl_group) == 0 then + return; + end + + local hl = vim.api.nvim_get_hl(ns_id, { name = hl_group, link = false, create = false }); if value == "fg" then - return colors.num_to_hex(hl.fg) + if type(hl.fg) == "string" and hl.fg:match("^[#]?(%x+)$") then + return colors.name_to_hex(hl.fg) + else + return colors.num_to_hex(hl.fg) + end elseif value == "bg" then - return colors.num_to_hex(hl.bg) + if type(hl.bg) == "string" and hl.bg:match("^[#]?(%x+)$") then + return colors.name_to_hex(hl.bg) + else + return colors.num_to_hex(hl.bg) + end elseif value == "sp" then - return colors.num_to_hex(hl.sp) + if type(hl.sp) == "string" and hl.sp:match("^[#]?(%x+)$") then + return colors.name_to_hex(hl.sp) + else + return colors.num_to_hex(hl.sp) + end else return hl[value]; end @@ -109,14 +177,18 @@ colors.mix = function (color_1, color_2, per_1, per_2) if type(color_1) == "table" then c_1 = color_1; - elseif type(color_1) == "string" then + elseif type(color_1) == "string" and color_1:match("^[#]?(%x+)$") then c_1 = colors.hex_to_rgb(color_1); + elseif type(color_1) == "string" then + c_1 = colors.name_to_rgb(color_1); end if type(color_2) == "table" then c_2 = color_2; - elseif type(color_2) == "string" then + elseif type(color_2) == "string" and color_2:match("^[#]?(%x+)$") then c_2 = colors.hex_to_rgb(color_2); + elseif type(color_2) == "string" then + c_1 = colors.name_to_rgb(color_2); end if not c_1 or not c_2 then @@ -130,4 +202,85 @@ colors.mix = function (color_1, color_2, per_1, per_2) return colors.rgb_to_hex({ r = _r, g = _g, b = _b }); end +colors.get_brightness = function (color) + if type(color) == "string" and color:match("^[#]?(%x+)$") then + color = colors.hex_to_rgb(color); + elseif type(color_1) == "string" then + color = colors.name_to_rgb(color); + elseif type(color) == "number" then + color = colors.num_to_rgb(color); + end + + for key, value in pairs(color) do + if value > 1 then + color[key] = value / 255; + end + end + + return (color.r * 0.2126) + (color.g * 0.7152) + (color.b * 0.0722); +end + +colors.brightest = function (col_list, debug) + if not col_list then + return; + elseif not vim.islist(col_list) then + local tmp = {}; + + for _, item in pairs(col_list) do + table.insert(tmp,item); + end + + col_list = tmp; + end + + local _c = {}; + + for _, col in ipairs(col_list) do + if type(col) == "string" and col:match("^[#]?(%x+)$") then + table.insert(_c, colors.hex_to_rgb(col)); + elseif type(col) == "string" then + table.insert(_c, colors.name_to_rgb(col)); + elseif type(col) == "number" then + table.insert(_c, colors.num_to_rgb(col)); + elseif type(col) == "table" then + table.insert(_c, col); + end + end + + + local _b = 0; + local brightest; + + for _, c in ipairs(_c) do + local brightness = colors.get_brightness(c) or 0; + + if brightness >= _b then + _b = brightness; + brightest = c; + end + end + + -- if debug then + -- vim.print(colors.rgb_to_hex(brightest) == nil); + -- end + + return colors.rgb_to_hex(brightest); +end + +colors.get = function (col_list) + if not col_list then + return; + elseif not vim.islist(col_list) then + local tmp = {}; + + for _, item in pairs(col_list) do + table.insert(tmp,item); + end + + col_list = tmp; + end + + return col_list[1]; +end + return colors; diff --git a/lua/markview/entites.lua b/lua/markview/entites.lua new file mode 100644 index 0000000..c0beec5 --- /dev/null +++ b/lua/markview/entites.lua @@ -0,0 +1,256 @@ +local entites = {}; + +entites.lookup = { + Aacute = "Á", + aacute = "á", + Acirc = "Â", + acirc = "â", + acute = "´", + AElig = "Æ", + aelig = "æ", + Agrave = "À", + agrave = "à", + alefsym = "ℵ", + Alpha = "Α", + alpha = "α", + amp = "&", + ["and"] = "∧", + ang = "∠", + Aring = "Å", + aring = "å", + asymp = "≈", + Atilde = "Ã", + atilde = "ã", + Auml = "Ä", + auml = "ä", + bdquo = "„", + Beta = "Β", + beta = "β", + brvbar = "¦", + bull = "•", + cap = "∩", + Ccedil = "Ç", + ccedil = "ç", + cedil = "¸", + cent = "¢", + Chi = "Χ", + chi = "χ", + circ = "ˆ", + clubs = "♣", + congc = "≅", + copy = "©", + crarr = "↵", + cup = "∪", + curren = "¤", + Dagger = "‡", + dagger = "†", + dArr = "⇓", + darr = "↓", + deg = "°", + Delta = "Δ", + delta = "δ", + diams = "♦", + divide = "÷", + Eacute = "É", + eacute = "é", + Ecirc = "Ê", + ecirc = "ê", + Egrave = "È", + egrave = "è", + empty = "∅", + Epsilon = "Ε", + epsilon = "ε", + equiv = "≡", + Eta = "Η", + eta = "η", + ETH = "Ð", + eth = "ð", + Euml = "Ë", + euml = "ë", + euro = "€", + exists = "∃", + fnof = "ƒ", + forall = "∀", + frac12 = "½", + frac14 = "¼", + frac34 = "¾", + frasl = "⁄", + Gamma = "Γ", + gamma = "γ", + ge = "≥", + gt = ">", + harr = "↔", + hArr = "⇔", + hearts = "♥", + hellip = "…", + Iacute = "Í", + iacute = "í", + Icirc = "Î", + icirc = "î", + iexcl = "¡", + Igrave = "Ì", + igrave = "ì", + image = "ℑ", + infin = "∞", + int = "∫", + Iota = "Ι", + iota = "ι", + iquest = "¿", + isin = "∈", + Iuml = "Ï", + iuml = "ï", + Kappa = "Κ", + kappa = "κ", + Lambda = "Λ", + lambda = "λ", + lang = "⟨", + laquo = "«", + lArr = "⇐", + larr = "←", + lceil = "⌈", + ldquo = "“", + le = "≤", + lfloor = "⌊", + lowast = "∗", + loz = "◊", + -- lrm = "‎", + lsaquo = "‹", + lsquo = "‘", + lt = "<", + macr = "¯", + mdash = "—", + micro = "µ", + middot = "·", + minus = "−", + Mu = "Μ", + mu = "μ", + nabla = "∇", + nbsp = " ", + ndash = "–", + ne = "≠", + ni = "∋", + ["not"] = "¬", + notin = "∉", + nsub = "⊄", + Ntilde = "Ñ", + ntilde = "ñ", + Nu = "Ν", + nu = "ν", + Oacute = "Ó", + oacute = "ó", + Ocirc = "Ô", + ocirc = "ô", + OElig = "Œ", + oelig = "œ", + Ograve = "Ò", + ograve = "ò", + Omeg = "Ω", + omega = "ω", + Omicron = "Ο", + omicron = "ο", + oline = "‾", + ["or"] = "∨", + Oslash = "Ø", + oslash = "ø", + Otilde = "Õ", + otilde = "õ", + Ouml = "Ö", + ouml = "ö", + para = "¶", + part = "∂", + permil = "‰", + perp = "⊥", + Phi = "Φ", + phi = "φ", + Pi = "Π", + pi = "π", + piv = "ϖ", + plusmn = "±", + pound = "£", + Prime = "″", + prime = "′", + prod = "∏", + prop = "∝", + Psi = "Ψ", + psi = "ψ", + quot = "\"", + radic = "√", + rang = "⟩", + raquo = "»", + rArr = "⇒", + rarr = "→", + rceil = "⌉", + rdquo = "”", + real = "ℜ", + reg = "®", + rflo = "⌋", + Rho = "Ρ", + rho = "ρ", + -- rlm = "‏", + rsaquo = "›", + rsquo = "’", + sbquo = "‚", + Scaron = "Š", + scaron = "š", + sdot = "⋅", + sect = "§", + shy = "­", + Sigma = "Σ", + sigma = "σ", + sigmaf = "ς", + sim = "∼", + spades = "♠", + sub = "⊂", + sube = "⊆", + sum = "∑", + sup = "⊃", + sup1 = "¹", + sup2 = "²", + sup3 = "³", + supe = "⊇", + szlig = "ß", + Tau = "Τ", + tau = "τ", + there4 = "∴", + Theta = "Θ", + theta = "θ", + thetasym = "ϑ", + thinsp = " ", + THORN = "Þ", + thorn = "þ", + tilde = "˜", + times = "×", + trade = "™", + Uacute = "Ú", + uacute = "ú", + uArr = "⇑", + uarr = "↑", + Ucirc = "Û", + ucirc = "û", + Ugrave = "Ù", + ugrave = "ù", + uml = "¨", + upsih = "ϒ", + Upsilon = "Υ", + upsilon = "υ", + Uuml = "Ü", + uuml = "ü", + weierp = "℘", + Xi = "Ξ", + xi = "ξ", + Yacute = "Ý", + yacute = "ý", + yen = "¥", + yuml = "ÿ", + Yuml = "Ÿ", + Zeta = "Ζ", + zeta = "ζ", + -- zwj = "‍", + -- zwnj = "‌" +} + +entites.get = function (string) + return entites.lookup[string], vim.fn.strdisplaywidth(entites.lookup[string]); +end + +return entites; diff --git a/lua/markview/extras.lua b/lua/markview/extras.lua index c4a1bf9..8654bba 100644 --- a/lua/markview/extras.lua +++ b/lua/markview/extras.lua @@ -1,3 +1,5 @@ +-- For testing purposes + local extras = {}; extras.show_headings = { diff --git a/lua/markview/languages.lua b/lua/markview/languages.lua new file mode 100644 index 0000000..64607ca --- /dev/null +++ b/lua/markview/languages.lua @@ -0,0 +1,221 @@ +local languages = {}; + +languages.patterns = { + { ".*%.feature", "Cucumber" }, + + { ".*%.abap", "Abap" }, + + { ".*%.ada", "Ada" }, + { "adb", "Ada" }, + { "ads$", "Ada" }, + + { "htaccess", "Apacheconf" }, + { "apache.conf", "Apacheconf" }, + { "apache2.conf", "Apacheconf" }, + + { ".*%.as", "As" }, + { ".%*%.asy", "Asy" }, + + { "ahkl", "Ahk" }, + + { "sh", "Bash" }, + { "ksh", "Bash" }, + { "ksh", "Bash" }, + { ".*%.ebuild", "Bash" }, + { ".*%.eclass", "Bash" }, + + { ".*%.befunge", "Befunge" }, + { ".*%.bmx", "Blitzmax" }, + { ".*%.boo", "Boo" }, + + { "bf", "Brainfuck" }, + { "b", "Brainfuck" }, + + { "cmd", "Bat" }, + + { ".*%.cfc", "Cfm" }, + { "cfml", "Cfm" }, + + { "cl", "Cl" }, + { "lisp", "Cl" }, + { ".*%.el", "Cl" }, + + { "clj", "Clojure" }, + { "cljs", "Clojure" }, + + { "h", "C" }, + { "c", "C" }, + { ".*.cmake", "Cmake" }, + + { "coffee", "Cofeescript" }, + { ".*%.sh%-session", "Console" }, + + { "cpp", "C++" }, + { "hpp", "C++" }, + { "cc", "C++" }, + { "hh", "C++" }, + { "cxx", "C++" }, + { "hxx", "C++" }, + { ".*%.pde", "C++" }, + + { "csharp", "C#" }, + { "cs", "C#" }, + { ".*.%cs", "C#" }, + + { "css", "CSS" }, + + { "pyx", "Cython" }, + { "pxd", "Cython" }, + { ".*%.pxi", "Cython" }, + + { "d", "D" }, + { "di", "D" }, + + { ".*%.pas", "Delphi" }, + + { "patch", "Diff" }, + + { "darcspatch", "Dpatch" }, + + { "jbst", "Duel" }, + + { "dyl", "Dylan" }, + + { ".*%.erb", "Erb" }, + + { ".*%.erl%-sh", "Erl" }, + + { "erl", "Erlang" }, + { "hrl", "Erlang" }, + + { "flx", "Felix" }, + { "flxh", "Felix" }, + + { "f", "Fortran" }, + { "f90", "Fortran" }, + + { "s", "Gas" }, + { "S", "Gas" }, + + { ".*%.kid", "Genshi" }, + + { "gitignore", "Gitignore" }, + + { "vert", "GLSL" }, + { "frag", "GLSL" }, + { ".*%.geo", "GLSL" }, + + { "plot", "Gnuplot" }, + { "plt", "Gnuplot" }, + + { ".*%.go", "Go" }, + + { "hs", "Haskell" }, + { ".*%.hs", "Haskell" }, + + { "htm", "Html" }, + { "xhtml", "Html" }, + { "xslt", "Html" }, + + { ".*%.hx", "Hx" }, + + { "hy", "Hybris" }, + { "hyb", "Hybris" }, + + { "ini", "INI" }, + { "cfg", "INI" }, + + { ".*%.io", "Io" }, + { "ik", "Ioke" }, + + { ".*%.jade", "Jade" }, + + { ".*%.Java", "Java" }, + + { "ll", "LLVM" }, + + { "wlua", "Lua" }, + + { "mak", "Make" }, + { "makefile", "Make" }, + { "Makefile", "Make" }, + { "GNUmakefile", "Make" }, + + { ".*%.mao", "Make" }, + + { "mhtml", "Mason" }, + { "mc", "Mason" }, + { ".*%.mi", "Mason" }, + { "autohandler", "Mason" }, + { "dhandler", "Mason" }, + + { "md", "Markdown" }, + + { "m", "Objective C" }, + { ".*%.m", "Objective C" }, + { ".*%.j", "Objective J" }, + + { "ml", "Ocaml" }, + { "mli", "Ocaml" }, + { "mll", "Ocaml" }, + { "mly", "Ocaml" }, + + { "pm", "Perl" }, + { "pl", "Perl" }, + + { "php", "PHP" }, + + { "ps", "Postscript" }, + { "eps", "Postscript" }, + + { "pro", "Prolog" }, + { ".*%.pl", "Prolog" }, + + { ".*%.properties", "Properties" }, + + { ".*%.py3tb", "Py3tb" }, + { ".*%.pytb", "Pytb" }, + { "py", "Python" }, + { "pyw", "Python" }, + { "sc", "Python" }, + { "SConstruct", "Python" }, + { "SConscript", "Python" }, + { "tac", "Python" }, + + { ".*%.R", "R" }, + + { "rb", "Ruby" }, + { "rbw", "Ruby" }, + { "RakeFile", "Ruby" }, + { "rake", "Ruby" }, + { "gemspec", "Ruby" }, + { "rbx", "Ruby" }, + { "duby", "Ruby" }, + + { "rs", "rust" }, + + { "sql", "SQL" }, + { ".*%.sql", "SQL" }, + + { "txt", "Text" }, + + { "ts", "Typescript" }, + + { "yml", "Yaml" }, +}; + +languages.get_name = function (name) + if not name or name == "" then + return "Unknown"; + end + + for _, pattern in ipairs(languages.patterns) do + if name:match("^" .. pattern[1] .. "$") then + return pattern[2]; + end + end + + return string.gsub(name, "^%l", string.upper); +end + +return languages; diff --git a/lua/markview/parser.lua b/lua/markview/parser.lua index 4bf9eb6..405f128 100644 --- a/lua/markview/parser.lua +++ b/lua/markview/parser.lua @@ -1,30 +1,55 @@ local parser = {}; -- local renderer = require("markview/renderer"); -parser.fiter_lines = function (buffer, from, to, marker) +parser.fiter_lines = function (buffer, from, to) local captured_lines = vim.api.nvim_buf_get_lines(buffer, from, to, false); local filtered_lines = {}; local indexes = {}; local spaces = {}; + local withinCodeBlock; + local parent_marker; + local tolarence = 3; local found = 0; for l, line in ipairs(captured_lines) do - if l ~= 1 and line:match(marker) then - break; + if l ~= 1 then + if withinCodeBlock ~= true and line:match("^%s*([+%-*])") then + break; + elseif withinCodeBlock ~= true and line:match("^%s*(%d+%.)") then + break; + end end if found >= tolarence then break; end - local spaces_before = vim.fn.strchars(line:match("(%s*)")); + local spaces_before = vim.fn.strchars(line:match("^(%s*)")); + + if line:match("(```)") and withinCodeBlock ~= true then + withinCodeBlock = true; + goto withinElement; + elseif line:match("(```)") and withinCodeBlock == true then + withinCodeBlock = false; + goto withinElement; + elseif withinCodeBlock == true then + goto withinElement; + end + + if line:match("^%s*([+%-*])") then + parent_marker = line:match("^%s*([+%-*])"); + elseif line:match("^%s*(%d+%.)") then + parent_marker = line:match("^%s*(%d+%.)"); + end - if not line:match(marker) then - spaces_before = math.max(0, spaces_before - vim.fn.strchars(marker .. " ")); + if not line:match("^%s*([+%-*])") and not line:match("^%s*(%d+%.)") and parent_marker then + spaces_before = math.max(0, spaces_before - vim.fn.strchars((parent_marker or "") .. " ")); end + ::withinElement:: + table.insert(filtered_lines, line); table.insert(indexes, l); table.insert(spaces, spaces_before) @@ -75,6 +100,16 @@ parser.parsed_content = {}; ---@param buffer number ---@param TStree any parser.md = function (buffer, TStree, from, to) + if not parser.cached_conf or not parser.cached_conf.on_injected or parser.cached_conf.on_injected == false then + local root = TStree:root(); + local root_r_start, _, root_r_end, _ = root:range(); + local buf_lines = vim.api.nvim_buf_line_count(buffer); + + if root_r_start ~= 0 or root_r_end ~= buf_lines then + return; + end + end + local scanned_queies = vim.treesitter.query.parse("markdown", [[ ((setext_heading) @setext_heading) @@ -129,23 +164,21 @@ parser.md = function (buffer, TStree, from, to) col_end = col_end }) elseif capture_name == "heading" then + local parent = capture_node:parent(); + local heading_txt = capture_node:next_sibling(); - local title = heading_txt ~= nil and vim.treesitter.get_node_text(heading_txt, buffer) or ""; + local title = heading_txt ~= nil and vim.treesitter.get_node_text(heading_txt, buffer) or nil; local h_txt_r_start, h_txt_c_start, h_txt_r_end, h_txt_c_end; - if heading_txt ~= nil then - h_txt_r_start, h_txt_c_start, h_txt_r_end, h_txt_c_end = heading_txt:range(); - end - table.insert(parser.parsed_content, { node = capture_node, type = "heading", level = vim.fn.strchars(capture_text), + line = vim.treesitter.get_node_text(parent, buffer), marker = capture_text, title = title, - title_pos = { h_txt_r_start, h_txt_c_start, h_txt_r_end, h_txt_c_end }, row_start = row_start, row_end = row_end, @@ -158,6 +191,8 @@ parser.md = function (buffer, TStree, from, to) local lines = {}; local highest_len = 0; + local block_start = vim.api.nvim_buf_get_lines(buffer, row_start, row_start + 1, false)[1]; + for i = 1,(row_end - row_start) - 2 do local this_code = vim.api.nvim_buf_get_lines(buffer, row_start + i, row_start + i + 1, false)[1]; local len = vim.fn.strchars(this_code) or 0; @@ -173,7 +208,7 @@ parser.md = function (buffer, TStree, from, to) table.insert(parser.parsed_content, { node = capture_node, type = "code_block", - language = not capture_node:named_child(1) and "" or vim.treesitter.get_node_text(capture_node:named_child(1), buffer), + language = block_start:match("%s*```(%S*)$") or "", line_lengths = line_lens, largest_line = highest_len, @@ -237,9 +272,23 @@ parser.md = function (buffer, TStree, from, to) local table_structure = {}; local alignments = {}; + local line_positions = {}; + for row in capture_node:iter_children() do local tmp = {}; + local row_text = vim.treesitter.get_node_text(row, buffer) + local r_row_start, r_col_start, r_row_end, r_col_end = row:range(); + + --- Separator gets counted from the start of the line + --- So, we will instead count the number of spaces at the start + table.insert(line_positions, { + row_start = r_row_start, + col_start = r_col_start == 0 and vim.fn.strchars(row_text:match("^(%s*)")) or r_col_start, + row_end = r_row_end, + col_end = r_col_end + }) + if row:type() == "pipe_table_header" then table.insert(table_structure, "header"); elseif row:type() == "pipe_table_delimiter_row" then @@ -262,7 +311,7 @@ parser.md = function (buffer, TStree, from, to) end end - table.insert(table_structure, "seperator"); + table.insert(table_structure, "separator"); elseif row:type() == "pipe_table_row" then table.insert(table_structure, "content"); else @@ -281,6 +330,25 @@ parser.md = function (buffer, TStree, from, to) table.insert(rows, tmp) end + local s_start, s_end; + + -- This is a workaround for hybrid-mode + -- + -- When ,`use_virt_lines` is true the table will take the + -- line above it and the line below it. + -- + -- So we must adjust the ranges to match the render. + -- + -- Don't worry, the renderer will use the __r ones in that + -- case + if parser.cached_conf and parser.cached_conf.tables and parser.cached_conf.tables.use_virt_lines == false then + s_start = row_start; + s_end = row_end; + + row_start = row_start - 1; + row_end = row_end + 1; + end + table.insert(parser.parsed_content, { node = capture_node, type = "table", @@ -289,22 +357,26 @@ parser.md = function (buffer, TStree, from, to) rows = rows, content_alignments = alignments, + content_positions = line_positions, + + __r_start = s_start, + __r_end = s_end, row_start = row_start, row_end = row_end, col_start = col_start, - col_end = col_end + col_end = col_end, }) elseif capture_name == "list_item" then local marker = capture_node:named_child(0); local marker_text = vim.treesitter.get_node_text(marker, buffer); local symbol = marker_text:gsub("%s", ""); - local list_lines, lines, spaces = parser.fiter_lines(buffer, row_start, row_end, symbol); + local list_lines, lines, spaces = parser.fiter_lines(buffer, row_start, row_end); local spaces_before_marker = list_lines[1]:match("^(%s*)" .. symbol .. "%s*"); - local c_end, r_end = parser.get_list_end_range(buffer, row_start, row_end, symbol) + local c_end, _ = parser.get_list_end_range(buffer, row_start, row_end, symbol) table.insert(parser.parsed_content, { node = capture_node, @@ -366,6 +438,8 @@ parser.md_inline = function (buffer, TStree, from, to) ] @link) ((code_span) @code) + + ((entity_reference) @entity) ]]); -- The last 2 _ represent the metadata & query @@ -379,25 +453,42 @@ parser.md_inline = function (buffer, TStree, from, to) local title = string.match(line ~= nil and line[1] or "", "%b[]%s*(.*)$") if capture_text == "[-]" then - table.insert(parser.parsed_content, { - node = capture_node, - type = "checkbox", - state = "pending", + for _, extmark in ipairs(parser.parsed_content) do + if extmark.type == "list_item" and extmark.row_start == row_start then + local start_line = extmark.list_lines[1] or ""; + local atStart = start_line:match("%-%s+(%[%-%])%s+"); - row_start = row_start, - row_end = row_end, + local chk_start, _ = start_line:find("%[%-%]"); - col_start = col_start, - col_end = col_end - }) + if not atStart or not chk_start or chk_start - 1 ~= col_start then + goto invalid; + end + + table.insert(parser.parsed_content, { + node = capture_node, + type = "checkbox", + state = "pending", + + row_start = row_start, + row_end = row_end, + + col_start = col_start, + col_end = col_end + }); + + break; + end + ::invalid:: + end else for _, extmark in ipairs(parser.parsed_content) do if extmark.type == "block_quote" and extmark.row_start == row_start then - extmark.callout = string.match(capture_text, "%[!([^%]]+)%]"); extmark.title = title; - extmark.line_width = vim.fn.strchars(line[1]) + extmark.line_width = vim.fn.strchars(line[1]); + + break; end end end @@ -450,6 +541,74 @@ parser.md_inline = function (buffer, TStree, from, to) col_start = col_start, col_end = col_end }) + elseif capture_name == "entity" then + table.insert(parser.parsed_content, { + node = capture_node, + type = "html_entity", + + text = capture_text, + + row_start = row_start, + row_end = row_end, + + col_start = col_start, + col_end = col_end + }) + end + end +end + +parser.html = function (buffer, TStree, from, to) + if not parser.cached_conf or not parser.cached_conf.on_injected or parser.cached_conf.on_injected == false then + local root = TStree:root(); + local root_r_start, _, _, _ = root:range(); + + local start_line = vim.api.nvim_buf_get_lines(buffer, root_r_start - 1, root_r_start, false)[1] or ""; + + if start_line:match("```") then + return; + end + end + + local scanned_queies = vim.treesitter.query.parse("html", [[ + ((element) @elem) + ]]); + + for capture_id, capture_node, _, _ in scanned_queies:iter_captures(TStree:root(), buffer, from, to) do + local capture_name = scanned_queies.captures[capture_id]; + local capture_text = vim.treesitter.get_node_text(capture_node, buffer); + local row_start, col_start, row_end, col_end = capture_node:range(); + + if capture_name == "elem" then + local node_childs = capture_node:named_child_count(); + + local start_tag = capture_node:named_child(0); + local end_tag = capture_node:named_child(node_childs - 1); + + if start_tag:type() == "start_tag" and end_tag:type() == "end_tag" and row_start == row_end then + local _, ts_col_start, _, ts_col_end = start_tag:range(); + local _, te_col_start, _, te_col_end = end_tag:range(); + + table.insert(parser.parsed_content, { + node = capture_node, + type = "html_inline", + + tag = vim.treesitter.get_node_text(start_tag, buffer):gsub("[]", ""):match("%a+"), + text = capture_text, + + start_tag_col_start = ts_col_start, + start_tag_col_end = ts_col_end, + + end_tag_col_start = te_col_start, + end_tag_col_end = te_col_end, + + row_start = row_start, + row_end = row_end, + + col_start = col_start, + col_end = col_end + }) + end end end end @@ -458,13 +617,16 @@ end --- Parsed data is stored as a "view" in renderer.lua --- ---@param buffer number -parser.init = function (buffer) +parser.init = function (buffer, config_table) local root_parser = vim.treesitter.get_parser(buffer); root_parser:parse(true); + if config_table then + parser.cached_conf = config_table; + end + -- Clear the previous contents parser.parsed_content = {}; - local main_tree_parsed = false; root_parser:for_each_tree(function (TStree, language_tree) local tree_language = language_tree:lang(); @@ -473,32 +635,34 @@ parser.init = function (buffer) parser.md(buffer, TStree) elseif tree_language == "markdown_inline" then parser.md_inline(buffer, TStree); + elseif tree_language == "html" then + parser.html(buffer, TStree); end end) return parser.parsed_content; end -parser.parse_range = function (buffer, from, to) +parser.parse_range = function (buffer, config_table, from, to) + if not from or not to then + return {}; + end + local root_parser = vim.treesitter.get_parser(buffer); root_parser:parse(true); - if (not from or not to) and _G.__markview_render_ranges and _G.__markview_render_ranges[buffer] then - from = _G.__markview_render_ranges[buffer][1]; - to = _G.__markview_render_ranges[buffer][2]; - end - -- -- Clear the previous contents parser.parsed_content = {}; - local main_tree_parsed = false; root_parser:for_each_tree(function (TStree, language_tree) local tree_language = language_tree:lang(); if tree_language == "markdown" then - parser.md(buffer, TStree, from, to) + parser.md(buffer, TStree, from, to); elseif tree_language == "markdown_inline" then parser.md_inline(buffer, TStree, from, to); + elseif tree_language == "html" then + parser.html(buffer, TStree, from, to); end end) diff --git a/lua/markview/presets.lua b/lua/markview/presets.lua index 1c0f2a2..b8774bd 100644 --- a/lua/markview/presets.lua +++ b/lua/markview/presets.lua @@ -1,4 +1,360 @@ local presets = {}; +local colors = require("markview.colors"); + +presets.highlight_groups = { + colorful_heading_bg = { + ---+ ##code## + { + -- Heading level 1 + output = function () + if colors.get_hl_value(0, "DiagnosticOk", "fg") and colors.get_hl_value(0, "Normal", "bg") then + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = colors.get_hl_value(0, "DiagnosticOk", "fg"); + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading1", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading1Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + else + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = vim.o.background == "dark" and "#a6e3a1" or "#40a02b"; + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading1", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading1Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + end + end + }, + { + -- Heading level 2 + output = function () + if colors.get_hl_value(0, "DiagnosticHint", "fg") and colors.get_hl_value(0, "Normal", "bg") then + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = colors.get_hl_value(0, "DiagnosticHint", "fg"); + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading2", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading2Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + else + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = vim.o.background == "dark" and "#94e2d5" or "#179299"; + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading2", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading2Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + end + end + }, + { + -- Heading level 3 + output = function () + if colors.get_hl_value(0, "DiagnosticInfo", "fg") and colors.get_hl_value(0, "Normal", "bg") then + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = colors.get_hl_value(0, "DiagnosticInfo", "fg"); + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading3", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading3Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + else + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = vim.o.background == "dark" and "#89dceb" or "#179299"; + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading3", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading3Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + end + end + }, + { + -- Heading level 4 + output = function () + if colors.get_hl_value(0, "Special", "fg") and colors.get_hl_value(0, "Normal", "bg") then + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = colors.get_hl_value(0, "Special", "fg"); + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading4", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading4Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + else + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = vim.o.background == "dark" and "#f5c2e7" or "#ea76cb"; + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading4", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading4Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + end + end + }, + { + -- Heading level 5 + output = function () + if colors.get_hl_value(0, "DiagnosticWarn", "fg") and colors.get_hl_value(0, "Normal", "bg") then + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = colors.get_hl_value(0, "DiagnosticWarn", "fg"); + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading5", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading5Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + else + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = vim.o.background == "dark" and "#F9E3AF" or "#DF8E1D"; + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading5", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading5Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + end + end + }, + { + -- Heading level 6 + output = function () + if colors.get_hl_value(0, "DiagnosticError", "fg") and colors.get_hl_value(0, "Normal", "bg") then + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = colors.get_hl_value(0, "DiagnosticError", "fg"); + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading6", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading6Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + else + local fg = colors.get_hl_value(0, "Normal", "bg"); + local bg = vim.o.background == "dark" and "#F38BA8" or "#D20F39"; + + local nr = colors.get_hl_value(0, "LineNr", "bg"); + + return { + { + group_name = "Heading6", + value = { + bg = bg, + fg = fg, + + default = true + } + }, + { + group_name = "Heading6Sign", + value = { + bg = nr, + fg = bg, + + default = true + } + }, + } + end + end + }, + ---_ + } +}; presets.headings = { glow = { @@ -10,7 +366,7 @@ presets.headings = { heading_1 = { style = "label", - hl = "MarkviewCol1Inv", + hl = "MarkviewHeading1", padding_left = " ", padding_right = " " @@ -21,13 +377,26 @@ presets.headings = { enable = true, shift_width = 0, + setext_1 = { + style = "github", + + icon = "  ", hl = "MarkviewHeading1", + underline = "━" + }, + setext_2 = { + style = "github", + + icon = "  ", hl = "MarkviewHeading2", + underline = "─" + }, + heading_1 = { style = "label", padding_left = " ", padding_right = " ", - hl = "MarkviewCol1Inv" + hl = "MarkviewHeading1" }, heading_2 = { style = "label", @@ -35,7 +404,7 @@ presets.headings = { padding_left = " ", padding_right = " ", - hl = "MarkviewCol2Inv" + hl = "MarkviewHeading2" }, heading_3 = { style = "label", @@ -43,7 +412,7 @@ presets.headings = { padding_left = " ", padding_right = " ", - hl = "MarkviewCol3Inv" + hl = "MarkviewHeading3" }, heading_4 = { style = "label", @@ -51,7 +420,7 @@ presets.headings = { padding_left = " ", padding_right = " ", - hl = "MarkviewCol4Inv" + hl = "MarkviewHeading4" }, heading_5 = { style = "label", @@ -59,7 +428,7 @@ presets.headings = { padding_left = " ", padding_right = " ", - hl = "MarkviewCol5Inv" + hl = "MarkviewHeading5" }, heading_6 = { style = "label", @@ -67,7 +436,7 @@ presets.headings = { padding_left = " ", padding_right = " ", - hl = "MarkviewCol6Inv" + hl = "MarkviewHeading6" }, }, decorated_labels = { @@ -82,9 +451,9 @@ presets.headings = { padding_right = " ", corner_right = "", - corner_right_hl = "MarkviewCol1Fg", + corner_right_hl = "MarkviewHeading1Sign", - hl = "MarkviewCol1Inv" + hl = "MarkviewHeading1" }, heading_2 = { style = "label", @@ -93,9 +462,9 @@ presets.headings = { padding_right = " ", corner_right = "", - corner_right_hl = "MarkviewCol2Fg", + corner_right_hl = "MarkviewHeading2", - hl = "MarkviewCol2Inv" + hl = "MarkviewHeading2Sign" }, heading_3 = { style = "label", @@ -104,9 +473,9 @@ presets.headings = { padding_right = " ", corner_right = "", - corner_right_hl = "MarkviewCol3Fg", + corner_right_hl = "MarkviewHeading3", - hl = "MarkviewCol3Inv" + hl = "MarkviewHeading3Sign" }, heading_4 = { style = "label", @@ -115,9 +484,9 @@ presets.headings = { padding_right = " ", corner_right = "", - corner_right_hl = "MarkviewCol4Fg", + corner_right_hl = "MarkviewHeading4", - hl = "MarkviewCol4Inv" + hl = "MarkviewHeading4Sign" }, heading_5 = { style = "label", @@ -126,9 +495,9 @@ presets.headings = { padding_right = " ", corner_right = "", - corner_right_hl = "MarkviewCol5Fg", + corner_right_hl = "MarkviewHeading5", - hl = "MarkviewCol5Inv" + hl = "MarkviewHeading5Sign" }, heading_6 = { style = "label", @@ -137,9 +506,9 @@ presets.headings = { padding_right = " ", corner_right = "", - corner_right_hl = "MarkviewCol6Fg", + corner_right_hl = "MarkviewHeading6", - hl = "MarkviewCol6Inv" + hl = "MarkviewHeading6Sign" }, }, @@ -151,32 +520,32 @@ presets.headings = { heading_1 = { style = "simple", - hl = "MarkviewCol1" + hl = "MarkviewHeading1" }, heading_2 = { style = "simple", - hl = "MarkviewCol2" + hl = "MarkviewHeading2" }, heading_3 = { style = "simple", - hl = "MarkviewCol3" + hl = "MarkviewHeading3" }, heading_4 = { style = "simple", - hl = "MarkviewCol4" + hl = "MarkviewHeading4" }, heading_5 = { style = "simple", - hl = "MarkviewCol5" + hl = "MarkviewHeading5" }, heading_6 = { style = "simple", - hl = "MarkviewCol6" + hl = "MarkviewHeading6" }, }, simple_no_marker = { @@ -191,37 +560,37 @@ presets.headings = { style = "icon", icon = " ", - hl = "MarkviewCol1" + hl = "MarkviewHeading1" }, heading_2 = { style = "icon", icon = " ", - hl = "MarkviewCol2" + hl = "MarkviewHeading2" }, heading_3 = { style = "icon", icon = " ", - hl = "MarkviewCol3" + hl = "MarkviewHeading3" }, heading_4 = { style = "icon", icon = " ", - hl = "MarkviewCol4" + hl = "MarkviewHeading4" }, heading_5 = { style = "icon", icon = " ", - hl = "MarkviewCol5" + hl = "MarkviewHeading5" }, heading_6 = { style = "icon", icon = " ", - hl = "MarkviewCol6" + hl = "MarkviewHeading6" }, }, }; @@ -260,11 +629,11 @@ presets.tables = { }, -- This is a required property hl = { - nil, "MarkviewCol1Fg", nil, nil, + nil, "MarkviewTableBorder", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", }, use_virt_lines = false @@ -282,11 +651,11 @@ presets.tables = { "╼", "╾", "╴", "╶" }, hl = { - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg" + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder" }, use_virt_lines = false @@ -304,11 +673,11 @@ presets.tables = { "╼", "╾", "╴", "╶" }, hl = { - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg" + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder" }, use_virt_lines = false @@ -327,11 +696,11 @@ presets.tables = { "━", "━", "━", "━" }, hl = { - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", - "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", "MarkviewCol1Fg", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", + "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", "MarkviewTableBorder", - "MarkviewCol3Fg", "MarkviewCol4Fg", "MarkviewCol6Fg", "MarkviewCol6Fg" + "MarkviewTableAlignLeft", "MarkviewTableAlignRight", "MarkviewTableAlignCenter", "MarkviewTableAlignCenter" }, use_virt_lines = false diff --git a/lua/markview/renderer.lua b/lua/markview/renderer.lua index a963c41..8a77231 100644 --- a/lua/markview/renderer.lua +++ b/lua/markview/renderer.lua @@ -1,7 +1,8 @@ local renderer = {}; local devicons = require("nvim-web-devicons"); -local utils = require("markview.utils"); +local entites = require("markview.entites"); +local languages = require("markview.languages"); _G.__markview_views = {}; @@ -66,7 +67,9 @@ local display_width = function (text, config) local d_width = vim.fn.strchars(text); local inl_conf = config.inline_codes; - for inline_code in text:gmatch("`([^`]+)`") do + local final_string = text; + + for inline_code in final_string:gmatch("`([^`]+)`") do d_width = d_width - (vim.fn.strchars("`" .. inline_code .. "`")); if inl_conf ~= nil and inl_conf.enable ~= false then @@ -79,13 +82,24 @@ local display_width = function (text, config) inl_conf.padding_right or "", inl_conf.corner_right or "" })); + + final_string = final_string:gsub("`" .. inline_code .. "`", table.concat({ + inl_conf.corner_left or "", + inl_conf.padding_left or "", + + inline_code or "", + + inl_conf.padding_right or "", + inl_conf.corner_right or "" + })); end end - local lnk_conf = config.links ~= nil and config.links.inline_links or nil; + local lnk_conf = config.links ~= nil and config.links.hyperlinks or nil; local img_conf = config.links ~= nil and config.links.images or nil; + local email_conf = config.links ~= nil and config.links.emails or nil; - for img_identifier, link, address in text:gmatch("(!?)%[([^%]]+)%]%(([^%)]+)%)") do + for img_identifier, link, address in final_string:gmatch("(!?)%[([^%]]+)%]%(([^%)]+)%)") do if img_identifier ~= "" then d_width = d_width - vim.fn.strchars("![" .. "](" .. address .. ")"); @@ -97,6 +111,15 @@ local display_width = function (text, config) img_conf.padding_right or "", img_conf.corner_right or "" })); + + final_string = final_string:gsub("!%[" .. link .. "%]%(" .. address .. "%)", table.concat({ + img_conf.corner_left or "", + img_conf.padding_left or "", + img_conf.icon or "", + link, + img_conf.padding_right or "", + img_conf.corner_right or "" + })); end else d_width = d_width - vim.fn.strchars("[" .. "](" .. address .. ")"); @@ -109,16 +132,25 @@ local display_width = function (text, config) lnk_conf.padding_right or "", lnk_conf.corner_right or "" })); + + final_string = final_string:gsub("%[" .. link .. "%]%(" .. address .. "%)", table.concat({ + lnk_conf.corner_left or "", + lnk_conf.padding_left or "", + lnk_conf.icon or "", + link, + lnk_conf.padding_right or "", + lnk_conf.corner_right or "" + })); end end end - for str_a, str_b in text:gmatch("([*]+)[^*]+([*]+)") do + for str_a, internal, str_b in final_string:gmatch("([*]+)([^*]+)([*]+)") do local min_signs = vim.fn.strchars(str_a) > vim.fn.strchars(str_b) and vim.fn.strchars(str_a) or vim.fn.strchars(str_b); - local start_pos, _ = text:find("([*]+)[^*]+([*]+)"); + local start_pos, _ = final_string:find("([*]+)[^*]+([*]+)"); - local c_before = text:sub(start_pos - 1, start_pos - 1); + local c_before = final_string:sub(start_pos - 1, start_pos - 1); -- local c_after = text:sub(end_pos + 1, end_pos + 1); -- Needs more flexibility @@ -132,14 +164,123 @@ local display_width = function (text, config) if a == b then d_width = d_width - 2; + + final_string = final_string:gsub(a .. internal .. b, internal); end end ::invalid:: end + for username, domain, tdl in final_string:gmatch("<([%w._%+-]+)@([%w.-]+)%.([%w.-]+)>") do + d_width = d_width - vim.fn.strchars("<" .. ">"); + + if email_conf ~= nil and email_conf.enable ~= false then + d_width = d_width + vim.fn.strchars(table.concat({ + email_conf.corner_left or "", + email_conf.padding_left or "", + email_conf.icon or "", + email_conf.padding_right or "", + email_conf.corner_right or "" + })); + + final_string = final_string:gsub("<" .. username .. "@" .. domain .. "." .. tdl .. ">", table.concat({ + email_conf.corner_left or "", + email_conf.padding_left or "", + email_conf.icon or "", + + username, "@", domain, ".", tdl, + + email_conf.padding_right or "", + email_conf.corner_right or "" + })); + end + end + + local tmp_string = final_string; + local iterations = 1; + + local html_conf = config.html; + + while tmp_string:match("<([^>]+)>") do + -- This shouldn't run so many times + if not html_conf or html_conf.enable == false then + break; + elseif not html_conf.tags or html_conf.tags.enable == false then + break; + elseif iterations > 10 then + break; + else + iterations = iterations + 1; + end + + local start_tag = tmp_string:match("<([^>]+)>"); + local s_tag_start, _ = tmp_string:find("<([^>]+)>"); + + local filtered_tag = start_tag:match("%a+"); + + -- No close tag + if not tmp_string:match("") then + goto invalid; + end + + local end_tag = tmp_string:match(""); + local e_tag_start, _ = tmp_string:find(""); + + -- Close tag before opening tag + if e_tag_start < s_tag_start then + goto invalid; + end + + local tag_conf = html_conf.tags; + local conf = tag_conf.default or {}; + + if tag_conf.configs and tag_conf.configs[string.lower(filtered_tag)] then + conf = tag_conf.configs[string.lower(filtered_tag)] + end + + local internal_text = tmp_string:match("<" .. start_tag .. ">(.-)") or ""; + + -- Tag isn't concealed + if conf.conceal ~= false then + final_string = final_string:gsub("<" .. start_tag .. ">" .. internal_text .. "", internal_text) + d_width = d_width - vim.fn.strchars("<" .. start_tag .. ">" .. "", internal_text); + end + + tmp_string = tmp_string:gsub("<" .. start_tag .. ">" .. internal_text .. "", internal_text) + + ::invalid:: + end + + for entity_name, semicolon in final_string:gmatch("&([%a%d]+)(;?)") do + if not html_conf or html_conf.enable == false then + break; + elseif not html_conf.entites or html_conf.entites.enable == false then + break; + end + + local entity = entites.get(entity_name); + + if not entity then + goto invalid; + end - return d_width, vim.fn.strchars(text); + if semicolon then + final_string = final_string:gsub("&" .. entity_name .. ";", entity); + + d_width = d_width - vim.fn.strchars("&" .. entity_name .. ";"); + d_width = d_width + vim.fn.strdisplaywidth(entity); + else + final_string = final_string:gsub("&" .. entity_name, entity); + + d_width = d_width - vim.fn.strchars("&" .. entity_name); + d_width = d_width + vim.fn.strdisplaywidth(entity); + end + + ::invalid:: + end + + return d_width, vim.fn.strchars(text), final_string; end @@ -150,47 +291,58 @@ end local table_header = function (buffer, content, config_table) local tbl_conf = config_table.tables; + local row_start = content.__r_start or content.row_start; + local col_start = content.col_start; + local curr_col = 0; local curr_tbl_col = 1; local virt_txt = {}; + if content.content_positions and content.content_positions[1] then + table.insert(virt_txt, { string.rep(" ", content.content_positions[1].col_start) }) + col_start = content.content_positions[1].col_start; + end + for index, col in ipairs(content.rows[1]) do if index == 1 then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + 1, + end_col = col_start + 1, conceal = "" }); table.insert(virt_txt, { tbl_conf.text[1], set_hl(tbl_conf.hl[1]) }) curr_col = curr_col + 1 elseif index == #content.rows[1] then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + curr_col + 1, + end_col = col_start + curr_col + 1, conceal = "" }); table.insert(virt_txt, { tbl_conf.text[3], set_hl(tbl_conf.hl[3]) }) if config_table.tables.use_virt_lines == true then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, 0, { virt_lines_above = true, virt_lines = { virt_txt } }); - elseif content.row_start > 0 then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start - 1, content.col_start, { + elseif row_start > 0 then + -- BUG: Nearby tables can cause text to overlap + vim.api.nvim_buf_clear_namespace(buffer, renderer.namespace, row_start - 1, row_start); + + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start - 1, 0, { virt_text_pos = "inline", virt_text = virt_txt }); @@ -198,13 +350,13 @@ local table_header = function (buffer, content, config_table) curr_col = curr_col + 1 elseif col == "|" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + curr_col + 1, + end_col = col_start + curr_col + 1, conceal = "" }); @@ -216,14 +368,14 @@ local table_header = function (buffer, content, config_table) if width < actual_width then if align == "left" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + curr_col + width + 1, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col + vim.fn.strchars(col), { virt_text_pos = "inline", virt_text = { { string.rep(" ", (actual_width - width)) } } }); elseif align == "right" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { string.rep(" ", (actual_width - width)) } @@ -232,14 +384,14 @@ local table_header = function (buffer, content, config_table) else local before, after = math.floor((actual_width - width) / 2), math.ceil((actual_width - width) / 2); - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + curr_col + width + 1, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col + vim.fn.strchars(col), { virt_text_pos = "inline", virt_text = { { string.rep(" ", after) } } }); - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { string.rep(" ", before) } @@ -255,7 +407,7 @@ local table_header = function (buffer, content, config_table) end end ---- Renderer for table seperator +--- Renderer for table separator ---@param buffer number ---@param content any ---@param user_config markview.config @@ -263,42 +415,49 @@ end local table_seperator = function (buffer, content, user_config, r_num) local tbl_conf = user_config.tables; + local row_start = content.__r_start or content.row_start; + local col_start = content.col_start; + local curr_col = 0; local curr_tbl_col = 1; + if content.content_positions and content.content_positions[r_num] then + col_start = content.content_positions[r_num].col_start; + end + for index, col in ipairs(content.rows[r_num]) do if index == 1 then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + (r_num - 1), content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[5], set_hl(tbl_conf.hl[5]) } }, - end_col = content.col_start + 1, + end_col = col_start + 1, conceal = "" }); curr_col = curr_col + 1; elseif index == #content.rows[1] then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + (r_num - 1), content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[7], set_hl(tbl_conf.hl[7]) } }, - end_col = content.col_start + curr_col + 1, + end_col = col_start + curr_col + 1, conceal = "" }); curr_col = curr_col + 1; elseif col == "|" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + (r_num - 1), content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[8], set_hl(tbl_conf.hl[8]) } }, - end_col = content.col_start + curr_col + 1, + end_col = col_start + curr_col + 1, conceal = "" }); @@ -308,29 +467,29 @@ local table_seperator = function (buffer, content, user_config, r_num) if col:match(":") then if align == "left" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + (r_num - 1), content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[13], set_hl(tbl_conf.hl[13]) }, { string.rep(tbl_conf.text[2], vim.fn.strchars(col) - 1), set_hl(tbl_conf.hl[2]) } }, - end_col = content.col_start + curr_col + vim.fn.strchars(col) + 1, + end_col = col_start + curr_col + vim.fn.strchars(col) + 1, conceal = "" }); elseif align == "right" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + (r_num - 1), content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, { virt_text_pos = "inline", virt_text = { { string.rep(tbl_conf.text[2], vim.fn.strchars(col) - 1), set_hl(tbl_conf.hl[2]) }, { tbl_conf.text[14], set_hl(tbl_conf.hl[14]) } }, - end_col = content.col_start + curr_col + vim.fn.strchars(col) + 1, + end_col = col_start + curr_col + vim.fn.strchars(col) + 1, conceal = "" }); elseif align == "center" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + (r_num - 1), content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[15], set_hl(tbl_conf.hl[15]) }, @@ -338,18 +497,18 @@ local table_seperator = function (buffer, content, user_config, r_num) { tbl_conf.text[16], set_hl(tbl_conf.hl[16]) } }, - end_col = content.col_start + curr_col + vim.fn.strchars(col) + 1, + end_col = col_start + curr_col + vim.fn.strchars(col) + 1, conceal = "" }); end else - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + (r_num - 1), content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, { virt_text_pos = "inline", virt_text = { { string.rep(tbl_conf.text[2], vim.fn.strchars(col)), set_hl(tbl_conf.hl[8]) } }, - end_col = content.col_start + curr_col + vim.fn.strchars(col) + 1, + end_col = col_start + curr_col + vim.fn.strchars(col) + 1, conceal = "" }); end @@ -367,47 +526,55 @@ end local table_footer = function (buffer, content, config_table) local tbl_conf = config_table.tables; + local row_end = content.__r_end or content.row_end; + local col_start = content.col_start; + local curr_col = 0; local curr_tbl_col = 1; local virt_txt = {}; + if content.content_positions and content.content_positions[#content.content_positions] then + table.insert(virt_txt, { string.rep(" ", content.content_positions[#content.content_positions].col_start) }) + col_start = content.content_positions[#content.content_positions].col_start; + end + for index, col in ipairs(content.rows[#content.rows]) do if index == 1 then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + 1, + end_col = col_start + 1, conceal = "" }); table.insert(virt_txt, { tbl_conf.text[9], set_hl(tbl_conf.hl[9]) }) curr_col = curr_col + 1 - elseif index == #content.rows[1] then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start + curr_col, { + elseif index == #content.rows[#content.rows] then + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + curr_col + 1, + end_col = col_start + curr_col + 1, conceal = "" }); table.insert(virt_txt, { tbl_conf.text[11], set_hl(tbl_conf.hl[11]) }) if config_table.tables.use_virt_lines == true then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, 0, { virt_lines_above = false, virt_lines = { virt_txt } }); - elseif content.row_start > 0 then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end, content.col_start, { + elseif content.row_start < vim.api.nvim_buf_line_count(buffer) then + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end, 0, { virt_text_pos = "inline", virt_text = virt_txt }); @@ -415,13 +582,13 @@ local table_footer = function (buffer, content, config_table) curr_col = curr_col + 1 elseif col == "|" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + curr_col + 1, + end_col = col_start + curr_col + 1, conceal = "" }); @@ -433,14 +600,14 @@ local table_footer = function (buffer, content, config_table) if width < actual_width then if align == "left" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start + curr_col + width + 1, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col + vim.fn.strchars(col), { virt_text_pos = "inline", virt_text = { { string.rep(" ", (actual_width - width)) } } }); elseif align == "right" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { string.rep(" ", (actual_width - width)) } @@ -449,14 +616,14 @@ local table_footer = function (buffer, content, config_table) else local before, after = math.floor((actual_width - width) / 2), math.ceil((actual_width - width) / 2); - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start + curr_col + width + 1, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col + vim.fn.strchars(col), { virt_text_pos = "inline", virt_text = { { string.rep(" ", after) } } }); - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { string.rep(" ", before) } @@ -480,42 +647,48 @@ end local table_content = function (buffer, content, config_table, r_num) local tbl_conf = config_table.tables; + local col_start = content.col_start; + local curr_col = 0; local curr_tbl_col = 1; + if content.content_positions and content.content_positions[r_num] then + col_start = content.content_positions[r_num].col_start; + end + for index, col in ipairs(content.rows[r_num]) do if index == 1 then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, col_start, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + 1, + end_col = col_start + 1, conceal = "" }); curr_col = curr_col + 1 elseif index == #content.rows[1] then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + curr_col + 1, + end_col = col_start + curr_col + 1, conceal = "" }); curr_col = curr_col + 1 elseif col == "|" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { tbl_conf.text[6], set_hl(tbl_conf.hl[6]) } }, - end_col = content.col_start + curr_col + 1, + end_col = col_start + curr_col + 1, conceal = "" }); @@ -526,14 +699,14 @@ local table_content = function (buffer, content, config_table, r_num) if width < actual_width then if align == "left" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, content.col_start + curr_col + width + 1, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, col_start + curr_col + vim.fn.strchars(col), { virt_text_pos = "inline", virt_text = { { string.rep(" ", (actual_width - width)) } } }); elseif align == "right" then - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, content.col_start, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { string.rep(" ", (actual_width - width)) } @@ -542,14 +715,14 @@ local table_content = function (buffer, content, config_table, r_num) else local before, after = math.floor((actual_width - width) / 2), math.ceil((actual_width - width) / 2); - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, content.col_start + curr_col + width + 1, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, col_start + curr_col + vim.fn.strchars(col), { virt_text_pos = "inline", virt_text = { { string.rep(" ", after) } } }); - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, content.col_start + curr_col, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + r_num - 1, col_start + curr_col, { virt_text_pos = "inline", virt_text = { { string.rep(" ", before) } @@ -573,7 +746,7 @@ renderer.views = {}; ---@param content any ---@param config markview.render_config.headings renderer.render_headings = function (buffer, content, config) - if config.enable == false then + if not config or config.enable == false then return; end @@ -581,6 +754,11 @@ renderer.render_headings = function (buffer, content, config) local conf = config["heading_" .. content.level] or {}; local shift = config.shift_width or vim.bo[buffer].shiftwidth; + -- Do not proceed if config doesn't exist for a heading + if not conf then + return; + end + if conf.style == "simple" then -- Adds a simple background vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { @@ -589,85 +767,76 @@ renderer.render_headings = function (buffer, content, config) hl_mode = "combine" }); elseif conf.style == "label" then - -- FIX: Make headings editable - local add_spaces = vim.fn.strchars(table.concat({ - string.rep(conf.shift_char or " ", shift * (content.level - 1)), - conf.corner_left or "", - conf.padding_left or "", - conf.icon or "", - })); - - -- Adds icons, seperators, paddings etc - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, 0, { - virt_text_pos = "overlay", + local conceal_start = string.match(content.line, "^[#]+(%s*)"); + local line_length = vim.fn.strchars(content.line); + + -- Heading rules + -- 1. Must start at the first column + -- 2. Must have 1 space between the marker and the title + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { + virt_text_pos = "inline", virt_text = { { string.rep(conf.shift_char or " ", shift * (content.level - 1)), conf.shift_hl }, { conf.corner_left or "", set_hl(conf.corner_left_hl) or set_hl(conf.hl) }, { conf.padding_left or "", set_hl(conf.padding_left_hl) or set_hl(conf.hl) }, - { conf.icon or "", set_hl(conf.icon_hl) or set_hl(conf.hl) }, - { conf.text or content.title or "", set_hl(conf.text_hl) or set_hl(conf.hl) }, - { conf.padding_right or "", set_hl(conf.padding_right_hl) or set_hl(conf.hl) }, - { conf.corner_right or "", set_hl(conf.corner_right_hl) or set_hl(conf.hl) }, + { conf.icon or "", set_hl(conf.icon_hl) or set_hl(conf.hl) } }, - sign_text = conf.sign, sign_hl_group = set_hl(conf.sign_hl) or set_hl(conf.hl), - + sign_text = conf.sign, sign_hl_group = set_hl(conf.sign_hl), hl_mode = "combine", - }) - -- Add extra spaces to match the virtual text - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, 0, { + end_col = content.level + vim.fn.strchars(conceal_start), + conceal = "" + }); + + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, line_length, { virt_text_pos = "inline", - virt_text = { { string.rep(" ", add_spaces) } }, + virt_text = { + { conf.padding_right or "", set_hl(conf.padding_right_hl) or set_hl(conf.hl) }, + { conf.corner_right or "", set_hl(conf.corner_right_hl) or set_hl(conf.hl) } + }, - end_col = content.title_pos[2] or content.col_end, - conceal = "" + hl_mode = "combine" }); + + vim.api.nvim_buf_add_highlight(buffer, renderer.namespace, set_hl(conf.hl), content.row_start, 0, line_length); elseif conf.style == "icon" then - -- FIX: Make headings editable - local add_spaces = vim.fn.strchars(table.concat({ - string.rep(conf.shift_char or " ", shift * (content.level - 1)), - conf.icon or "" - })); - - -- Adds simple icons with paddings - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, 0, { - virt_text_pos = "overlay", + local conceal_start = string.match(content.line, "^[#]+(%s*)"); + + -- Heading rules + -- 1. Must start at the first column + -- 2. Must have 1 space between the marker and the title + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { + virt_text_pos = "inline", virt_text = { { string.rep(conf.shift_char or " ", shift * (content.level - 1)), set_hl(conf.shift_hl) }, { conf.icon or "", set_hl(conf.icon_hl) or set_hl(conf.hl) }, - { conf.text or content.title or "", set_hl(conf.text_hl) or set_hl(conf.hl) }, }, + sign_text = conf.sign, sign_hl_group = set_hl(conf.sign_hl), + line_hl_group = set_hl(conf.hl), hl_mode = "combine", - }) - -- Add extra spaces to match the virtual text - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, 0, { - virt_text_pos = "inline", - virt_text = { { string.rep(" ", add_spaces) } }, - - end_col = content.title_pos[2] or content.col_end, + end_col = content.level + vim.fn.strchars(conceal_start), conceal = "" }); - - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, 0, { - line_hl_group = set_hl(conf.hl), - sign_text = conf.sign, sign_hl_group = set_hl(conf.sign_hl), - }); end end renderer.render_headings_s = function (buffer, content, config) - if config.enable == false then + if not config or config.enable == false then return; end ---@type markview.render_config.headings.h local conf = content.marker:match("=") and config["setext_1"] or config["setext_2"]; - local shift = config.shift_width or vim.bo[buffer].shiftwidth; + + -- Do not proceed if setext headings don't have configuraton + if not conf then + return; + end if conf.style == "simple" then -- Adds a simple background @@ -724,7 +893,7 @@ end ---@param content any ---@param config_table markview.render_config.code_blocks renderer.render_code_blocks = function (buffer, content, config_table) - if config_table == nil or config_table.enable == false then + if not config_table or config_table.enable == false then return; end @@ -790,27 +959,32 @@ renderer.render_code_blocks = function (buffer, content, config_table) local icon, hl = devicons.get_icon(nil, language, { default = true }); local block_length = content.largest_line; + local languageName; + if config_table.language_names ~= nil then for _, lang in ipairs(config_table.language_names) do if language == lang[1] then - language = lang[2]; - break; + languageName = lang[2]; + goto nameFound; end end end + languageName = languages.get_name(language) + ::nameFound:: + if type(config_table.min_width) == "number" and config_table.min_width > block_length then block_length = config_table.min_width end - local lang_width = vim.fn.strchars(icon .. " " .. language .. " "); + local lang_width = vim.fn.strchars(" " .. icon .. " " .. languageName .. " "); if config_table.language_direction == nil or config_table.language_direction == "left" then vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + 3 + vim.fn.strlen(content.language), { virt_text_pos = config_table.position or "inline", virt_text = { - { icon .. " ", set_hl(hl) }, - { language .. " ", set_hl(config_table.name_hl) or set_hl(hl) }, + { " " .. icon .. " ", set_hl(hl) }, + { languageName .. " ", set_hl(config_table.name_hl) or set_hl(hl) }, { string.rep(config_table.pad_char or " ", block_length - lang_width + ((config_table.pad_amount or 1) * 2)), set_hl(config_table.hl) }, }, @@ -824,8 +998,8 @@ renderer.render_code_blocks = function (buffer, content, config_table) virt_text_pos = config_table.position or "inline", virt_text = { { string.rep(config_table.pad_char or " ", block_length - lang_width + ((config_table.pad_amount or 1) * 2)), set_hl(config_table.hl) }, - { icon .. " ", set_hl(hl) }, - { language .. " ", set_hl(config_table.name_hl) or set_hl(hl) }, + { " " .. icon .. " ", set_hl(hl) }, + { languageName .. " ", set_hl(config_table.name_hl) or set_hl(hl) }, }, sign_text = config_table.sign == true and icon or nil, @@ -835,10 +1009,19 @@ renderer.render_code_blocks = function (buffer, content, config_table) }); end - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, content.col_start + 3, { + -- The text on the final line + -- We need to get the tail section to see if it contains ``` + local block_end_line = vim.api.nvim_buf_get_lines(buffer, content.row_end - 1, content.row_end, false)[1]; + local tail_section = vim.fn.strcharpart(block_end_line or "", content.col_start); + + if tail_section:match("```$") then + tail_section = tail_section:gsub("```$", ""); + end + + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, vim.fn.strchars(block_end_line or ""), { virt_text_pos = config_table.position or "inline", virt_text = { - { string.rep(config_table.pad_char or " ", block_length + ((config_table.pad_amount or 1) * 2)), set_hl(config_table.hl) }, + { string.rep(config_table.pad_char or " ", (block_length - vim.fn.strchars(tail_section)) + ((config_table.pad_amount or 1) * 2)), set_hl(config_table.hl) }, }, hl_mode = "combine", @@ -859,7 +1042,7 @@ renderer.render_code_blocks = function (buffer, content, config_table) } }) - local position, reduce_cols = get_str_width(text) + local position, reduce_cols = get_str_width(text); vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + line, position, { virt_text_pos = "inline", @@ -879,16 +1062,16 @@ end renderer.render_block_quotes = function (buffer, content, config_table) local qt_config; - if config_table.enable == false then + if not config_table or config_table.enable == false then return; end if content.callout ~= nil then for _, callout in ipairs(config_table.callouts) do - if type(callout.match_string) == "string" and callout.match_string:upper() == content.callout:upper() then + if type(callout.match_string) == "string" and string.upper(callout.match_string --[[@as string]]) == content.callout:upper() then qt_config = callout; - elseif vim.islist(callout.aliases) then - for _, alias in ipairs(callout.aliases) do + elseif vim.islist(callout.match_string) then + for _, alias in ipairs(callout.match_string --[[@as string[] ]]) do if type(alias) == "string" and alias:upper() == content.callout.upper() then qt_config = callout; end @@ -903,6 +1086,11 @@ renderer.render_block_quotes = function (buffer, content, config_table) qt_config = config_table.default; end + -- Config for a block quote is not available + if not qt_config then + return; + end + if qt_config.custom_title == true and content.title ~= "" then vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { virt_text_pos = "inline", @@ -971,7 +1159,7 @@ end renderer.render_horizontal_rules = function (buffer, content, config_table) local virt_text = {}; - if config_table.enable == false then + if not config_table or config_table.enable == false then return; end @@ -1025,18 +1213,23 @@ end renderer.render_links = function (buffer, content, config_table) local lnk_conf; - if config_table.enable == false then + if not config_table or config_table.enable == false then return; end if content.link_type == "inline_link" then - lnk_conf = config_table.inline_links; + lnk_conf = config_table.hyperlinks; elseif content.link_type == "image" then lnk_conf = config_table.images; elseif content.link_type == "email_autolink" then lnk_conf = config_table.emails; end + -- Do not render links with no config + if not lnk_conf then + return; + end + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.link_type == "email_autolink" and content.col_start or content.col_start + 1, { virt_text_pos = "inline", virt_text = { @@ -1068,7 +1261,7 @@ end ---@param content any ---@param config_table markview.render_config.inline_codes renderer.render_inline_codes = function (buffer, content, config_table) - if config_table.enable == false then + if not config_table or config_table.enable == false then return; end @@ -1083,7 +1276,7 @@ renderer.render_inline_codes = function (buffer, content, config_table) vim.api.nvim_buf_add_highlight(buffer, renderer.namespace, set_hl(config_table.hl), content.row_start, content.col_start, content.col_end); - vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_end - 1, { + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_end, { virt_text_pos = "inline", virt_text = { { config_table.padding_right or "", set_hl(config_table.padding_right_hl) or set_hl(config_table.hl) }, @@ -1097,7 +1290,7 @@ end ---@param content any ---@param config_table markview.render_config.list_items renderer.render_lists = function (buffer, content, config_table) - if config_table.enable == false then + if not config_table or config_table.enable == false then return; end @@ -1113,6 +1306,11 @@ renderer.render_lists = function (buffer, content, config_table) ls_conf = config_table.marker_dot or {}; end + -- Do not render list types with no configuraton + if not ls_conf then + return; + end + local use_text = ls_conf.text or content.marker_symbol; if ls_conf.add_padding == true then @@ -1162,7 +1360,7 @@ end ---@param content any ---@param config_table markview.render_config.checkboxes renderer.render_checkboxes = function (buffer, content, config_table) - if config_table.enable == false then + if not config_table or config_table.enable == false then return; end @@ -1176,7 +1374,7 @@ renderer.render_checkboxes = function (buffer, content, config_table) chk_config = config_table.pending; end - if type(chk_config.text) ~= "string" then + if not chk_config or type(chk_config.text) ~= "string" then return; end @@ -1198,14 +1396,14 @@ end ---@param content any ---@param user_config markview.config renderer.render_tables = function (buffer, content, user_config) - if user_config.tables == nil or user_config.tables.enable == false then + if not user_config.tables or user_config.tables.enable == false then return; end for row_number, _ in ipairs(content.rows) do if content.row_type[row_number] == "header" then table_header(buffer, content, user_config); - elseif content.row_type[row_number] == "seperator" then + elseif content.row_type[row_number] == "separator" then table_seperator(buffer, content, user_config, row_number) elseif content.row_type[row_number] == "content" and row_number == #content.rows then table_footer(buffer, content, user_config) @@ -1215,82 +1413,66 @@ renderer.render_tables = function (buffer, content, user_config) end end +renderer.render_html_inline = function (buffer, content, user_config) + if not user_config or user_config.enable == false then + return; + end - - ---- CursorMove listener -renderer.autocmd = nil; - -renderer.create_autocmd = function (config_table) - if renderer.autocmd then + if not user_config.tags or user_config.tags.enable == false then return; end - local events = { "CursorMovedI" }; + local html_conf = user_config.tags.default or {}; - -- if config_table.modes and vim.list_contains(config_table.modes, "i") then - -- table.insert(events, "CursorMovedI"); - -- end + if user_config.tags.configs[string.lower(content.tag)] then + html_conf = user_config.tags.configs[string.lower(content.tag)]; + end - renderer.autocmd = vim.api.nvim_create_autocmd(events, { - pattern = config_table.filetypes or "*.md", -- Currently only for markdown - callback = function (event) - local buffer = event.buf; - local mode = vim.api.nvim_get_mode().mode; + if html_conf.conceal ~= false then + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.start_tag_col_start, { + end_col = content.start_tag_col_end, + conceal = "" + }); + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.end_tag_col_start, { + end_col = content.end_tag_col_end, + conceal = "" + }); + end - if not vim.list_contains(config_table.modes or {}, mode) then - return; - end + if html_conf.hl then + vim.api.nvim_buf_add_highlight(buffer, renderer.namespace, html_conf.hl, content.row_start, content.start_tag_col_end, content.end_tag_col_start); + end +end - renderer.render_deleted_items(buffer, config_table); - renderer.removed_elements[buffer] = {}; +renderer.render_html_entities = function (buffer, content, user_config) + if not user_config or user_config.enable == false then + return; + end - if not vim.list_contains(config_table.special_modes or { "i" }, mode) then - return; - end + if not user_config.entites or user_config.entites.enable == false then + return; + end - -- This is for testing purposes - local cursor = vim.api.nvim_win_get_cursor(0); - local comps = {}; + local filtered_entity = content.text:gsub("[&;]", ""); + local entity = entites.get(filtered_entity); - for _, component in ipairs(_G.__markview_views[buffer] or {}) do - if (cursor[1] - 1) >= component.row_start and cursor[1] - 1 <= component.row_end then - table.insert(comps, component); - table.insert(renderer.removed_elements[buffer], component); - end - end + if not entity then + return; + end - renderer.destroy(buffer) - end - }) -end + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { + virt_text_pos = "inline", + virt_text = { + { entity, set_hl(user_config.entites.hl) } + }, -renderer.destroy = function (buffer) - -- if not renderer.removed_elements or not renderer.removed_elements[buffer] or vim.tbl_isempty(renderer.removed_elements[buffer]) then - -- return; - -- end - -- - -- local max_range = {}; - -- - -- for _, content in ipairs(renderer.removed_elements[buffer]) do - -- if not max_range[1] or content.row_start < max_range[1] then - -- max_range[1] = content.row_start; - -- end - -- - -- if not max_range[2] or content.row_end > max_range[2] then - -- max_range[2] = content.row_end; - -- end - -- end - -- - -- vim.api.nvim_buf_clear_namespace(buffer, renderer.namespace, max_range[1], max_range[2] + 1); + end_col = content.col_end, + conceal = "" + }); end -renderer.render_deleted_items = function (buffer, config_table) - if not renderer.removed_elements[buffer] then - return; - end - - for _, content in ipairs(renderer.removed_elements[buffer]) do +renderer.render_in_range = function (buffer, partial_contents, config_table) + for _, content in ipairs(partial_contents) do local type = content.type; local fold_closed = vim.fn.foldclosed(content.row_start + 1); @@ -1298,29 +1480,32 @@ renderer.render_deleted_items = function (buffer, config_table) goto extmark_skipped; end - if type == "heading_s" then - renderer.render_headings_s(buffer, content, config_table.headings); + pcall(renderer.render_headings_s, buffer, content, config_table.headings); elseif type == "heading" then - renderer.render_headings(buffer, content, config_table.headings) + pcall(renderer.render_headings, buffer, content, config_table.headings) elseif type == "code_block" then - renderer.render_code_blocks(buffer, content, config_table.code_blocks) + pcall(renderer.render_code_blocks, buffer, content, config_table.code_blocks) elseif type == "block_quote" then - renderer.render_block_quotes(buffer, content, config_table.block_quotes); + pcall(renderer.render_block_quotes, buffer, content, config_table.block_quotes); elseif type == "horizontal_rule" then - renderer.render_horizontal_rules(buffer, content, config_table.horizontal_rules); + pcall(renderer.render_horizontal_rules, buffer, content, config_table.horizontal_rules); elseif type == "link" then - renderer.render_links(buffer, content, config_table.links); + pcall(renderer.render_links, buffer, content, config_table.links); elseif type == "image" then - renderer.render_links(buffer, content, config_table.images); + pcall(renderer.render_links, buffer, content, config_table.images); elseif type == "inline_code" then - renderer.render_inline_codes(buffer, content, config_table.inline_codes) + pcall(renderer.render_inline_codes, buffer, content, config_table.inline_codes) elseif type == "list_item" then - renderer.render_lists(buffer, content, config_table.list_items) + pcall(renderer.render_lists, buffer, content, config_table.list_items) elseif type == "checkbox" then - renderer.render_checkboxes(buffer, content, config_table.checkboxes) + pcall(renderer.render_checkboxes, buffer, content, config_table.checkboxes) + elseif type == "html_inline" then + pcall(renderer.render_html_inline, buffer, content, config_table.html); + elseif type == "html_entity" then + pcall(renderer.render_html_entities, buffer, content, config_table.html); elseif type == "table" then - renderer.render_tables(buffer, content, config_table) + pcall(renderer.render_tables, buffer, content, config_table) end ::extmark_skipped:: @@ -1336,6 +1521,11 @@ renderer.render = function (buffer, parsed_content, config_table, conceal_start, _G.__markview_views[buffer] = parsed_content; end + -- Prevents errors caused by buffer ranges being nil + if _G.__markview_render_ranges and _G.__markview_render_ranges[buffer] then + _G.__markview_render_ranges[buffer] = {}; + end + for _, content in ipairs(_G.__markview_views[buffer]) do local type = content.type; local fold_closed = vim.fn.foldclosed(content.row_start + 1); @@ -1344,113 +1534,87 @@ renderer.render = function (buffer, parsed_content, config_table, conceal_start, goto extmark_skipped; end - -- if conceal_start and conceal_stop and content.row_start >= conceal_start and content.row_end <= conceal_stop then - -- goto extmark_skipped; - -- end + -- Unlike `conceal_start`, `conceal_stop` is 1-indexed + -- Do not render things inside the un-conceal range + if conceal_start and conceal_stop and content.row_start >= conceal_start and content.row_end <= (conceal_stop - 1) then + goto extmark_skipped; + end if type == "heading_s" then - renderer.render_headings_s(buffer, content, config_table.headings); + pcall(renderer.render_headings_s, buffer, content, config_table.headings); elseif type == "heading" then - renderer.render_headings(buffer, content, config_table.headings) + pcall(renderer.render_headings, buffer, content, config_table.headings) elseif type == "code_block" then - renderer.render_code_blocks(buffer, content, config_table.code_blocks) + pcall(renderer.render_code_blocks, buffer, content, config_table.code_blocks) elseif type == "block_quote" then - renderer.render_block_quotes(buffer, content, config_table.block_quotes); + pcall(renderer.render_block_quotes, buffer, content, config_table.block_quotes); elseif type == "horizontal_rule" then - renderer.render_horizontal_rules(buffer, content, config_table.horizontal_rules); + pcall(renderer.render_horizontal_rules, buffer, content, config_table.horizontal_rules); elseif type == "link" then - renderer.render_links(buffer, content, config_table.links); + pcall(renderer.render_links, buffer, content, config_table.links); elseif type == "image" then - renderer.render_links(buffer, content, config_table.images); + pcall(renderer.render_links, buffer, content, config_table.images); elseif type == "inline_code" then - renderer.render_inline_codes(buffer, content, config_table.inline_codes) + pcall(renderer.render_inline_codes, buffer, content, config_table.inline_codes) elseif type == "list_item" then - renderer.render_lists(buffer, content, config_table.list_items) + pcall(renderer.render_lists, buffer, content, config_table.list_items) elseif type == "checkbox" then - renderer.render_checkboxes(buffer, content, config_table.checkboxes) + pcall(renderer.render_checkboxes, buffer, content, config_table.checkboxes) + elseif type == "html_inline" then + pcall(renderer.render_html_inline, buffer, content, config_table.html); + elseif type == "html_entity" then + pcall(renderer.render_html_entities, buffer, content, config_table.html); elseif type == "table" then - renderer.render_tables(buffer, content, config_table) + pcall(renderer.render_tables, buffer, content, config_table); end ::extmark_skipped:: end end -renderer.clear = function (buffer) - vim.api.nvim_buf_clear_namespace(buffer, renderer.namespace, 0, -1) +renderer.clear = function (buffer, from, to) + vim.api.nvim_buf_clear_namespace(buffer, renderer.namespace, from or 0, to or -1) end -renderer.clear_under_cursor = function (buffer, cursor) - if not _G.__markview_views[buffer] then - return; - elseif not renderer.removed_elements then - renderer.removed_elements = {}; +renderer.update_range = function (buffer, new_range) + if not _G.__markview_render_ranges then + _G.__markview_render_ranges = {}; end - if not renderer.removed_elements[buffer] then - renderer.removed_elements[buffer] = {}; + if not _G.__markview_render_ranges[buffer] then + _G.__markview_render_ranges[buffer] = {}; end - renderer.clear_elements(buffer, cursor); + if new_range and not vim.deep_equal(_G.__markview_render_ranges[buffer], new_range) then + _G.__markview_render_ranges[buffer] = new_range; + end end -renderer.render_partial = function (buffer, partial_contents, config_table, conceal_start, conceal_stop) - -- if not renderer.removed_elements[buffer] then - -- return - -- end - - for _, content in ipairs(partial_contents) do - local type = content.type; - local fold_closed = vim.fn.foldclosed(content.row_start + 1); - - if fold_closed ~= -1 then - goto extmark_skipped; - end +renderer.clear_content_range = function (buffer, parsed_content) + local max_range = { nil, nil }; - if content.row_start >= conceal_start and content.row_end <= conceal_stop then - goto extmark_skipped; + for _, content in ipairs(parsed_content) do + if not max_range[1] or (content.row_start) < max_range[1] then + max_range[1] = content.row_start; end - - if type == "heading_s" then - renderer.render_headings_s(buffer, content, config_table.headings); - elseif type == "heading" then - renderer.render_headings(buffer, content, config_table.headings) - elseif type == "code_block" then - renderer.render_code_blocks(buffer, content, config_table.code_blocks) - elseif type == "block_quote" then - renderer.render_block_quotes(buffer, content, config_table.block_quotes); - elseif type == "horizontal_rule" then - renderer.render_horizontal_rules(buffer, content, config_table.horizontal_rules); - elseif type == "link" then - renderer.render_links(buffer, content, config_table.links); - elseif type == "image" then - renderer.render_links(buffer, content, config_table.images); - elseif type == "inline_code" then - renderer.render_inline_codes(buffer, content, config_table.inline_codes) - elseif type == "list_item" then - renderer.render_lists(buffer, content, config_table.list_items) - elseif type == "checkbox" then - renderer.render_checkboxes(buffer, content, config_table.checkboxes) - elseif type == "table" then - renderer.render_tables(buffer, content, config_table) + if not max_range[2] or (content.row_end) > max_range[2] then + max_range[2] = content.row_end; end - - ::extmark_skipped:: end -end -renderer.update = function (buffer, parsed_content) - if not _G.__markview_views then - _G.__markview_views = {}; + if not max_range[1] or not max_range[2] then + return; end - if parsed_content ~= nil then - _G.__markview_views[buffer] = parsed_content; + if max_range[1] == max_range[2] then + max_range[2] = max_range[2] + 1; end + + vim.api.nvim_buf_clear_namespace(buffer, renderer.namespace, max_range[1], max_range[2]); end -renderer.clear_partial_range = function (buffer, parsed_content) +renderer.get_content_range = function (parsed_content) local max_range = { nil, nil }; for _, content in ipairs(parsed_content) do @@ -1471,12 +1635,7 @@ renderer.clear_partial_range = function (buffer, parsed_content) max_range[2] = max_range[2] + 1; end - if not _G.__markview_render_ranges then - _G.__markview_render_ranges = {}; - end - - _G.__markview_render_ranges[buffer] = max_range; - vim.api.nvim_buf_clear_namespace(buffer, renderer.namespace, max_range[1], max_range[2]); + return max_range; end return renderer; diff --git a/lua/markview/utils.lua b/lua/markview/utils.lua index 888d6a3..92efda2 100644 --- a/lua/markview/utils.lua +++ b/lua/markview/utils.lua @@ -1,5 +1,9 @@ local utils = {}; +utils.clamp = function (val, min, max) + return math.min(math.max(val, min), max); +end + utils.find_attached_wins = function (buf) local attached_wins = {}; @@ -12,11 +16,11 @@ utils.find_attached_wins = function (buf) return attached_wins; end -utils.get_cursor_range = function (buffer, window, config_table) +utils.get_cursor_range = function (buffer, window) local cursor = vim.api.nvim_win_get_cursor(window or 0); local lines = vim.api.nvim_buf_line_count(buffer); - return math.max(0, (cursor[1] - 1) - (config_table.draw_range or 1)), math.min(lines, (cursor[1] - 1) + (config_table.draw_range or 1)); + return math.max(0, cursor[1] - 1), math.min(lines, cursor[1]); end return utils; diff --git a/markview.nvim.wiki b/markview.nvim.wiki new file mode 160000 index 0000000..873da3f --- /dev/null +++ b/markview.nvim.wiki @@ -0,0 +1 @@ +Subproject commit 873da3fa850e608a7c51023bbd54bae453757b66 diff --git a/showcases/demo.md b/showcases/demo.md new file mode 100644 index 0000000..6881174 --- /dev/null +++ b/showcases/demo.md @@ -0,0 +1,45 @@ +# Makrview.nvim + +An experimental markdown previewer for Neovim. + +```lua +vim.print(require("markview").state); +``` + +## Tasks + +- [X] Stability improvements +- [ ] Rocks.nvim workflow +- [-] Wiki updates + +## Links + +[Markview.nvim](https://www.github.com/markview.nvim) +![Showcase](../img/showcase.jpg) + + +## Notifications + +>[!Important] +> Old presets are about to be removed. + +>[!Tip] +> Don't forget to check the wiki! + +>[!Warning] +> Only for Neovim `0.10.0` and higher. + +## Github Insights + +| Entry name | Entry value | +|:------------------------|:-----------------------| +| Git clones | 1008 | +| Visitors | 3801 | +| Stars | 777 | +| Lines added | 8426 | +| Lines deleted | 3158 | + + + diff --git a/showcases/html.md b/showcases/html.md new file mode 100644 index 0000000..b29962f --- /dev/null +++ b/showcases/html.md @@ -0,0 +1,56 @@ +# Makrview.nvim + +An experimental markdown previewer for Neovim. + +## Basic html tag support + +Markview.nvim supports some simple `html`. + +For example, + +- Bold: Example text +- Strong: Example text +- Underline: Example text +- Italic: Example text +- Emphasize: Example text +- Marked: Example text + +These tags can also be used inside of your Normal text. + +## Html entity support + +Markview.nvim has basic support of `html entites`. + + ← ↓ ↑ → + + ∠ ≡ ∫ ≥ ≤ > < ∞ ∈ ∅ + ½ ¼ ¾ + +And a lot more symbols are also supported. + +## Supported in tables + +| Using tags in tables | Using entites in tables | +|:------------------------------:|---------------------------| +| Single tag usage | Single entity(←) | +| Multi tag usage | ∠ ¾ | +| =|= | +| You can also use both together: Underline & ⟩ | + +>[!Note] +> Html support is exclusive to tables! Other block elements +> will render them as raw text. + + + + + + + + + + + + diff --git a/showcases/hybrid_mode.md b/showcases/hybrid_mode.md new file mode 100644 index 0000000..162b5fa --- /dev/null +++ b/showcases/hybrid_mode.md @@ -0,0 +1,37 @@ +# Markview.nvim + +An experimental markdown previewer for Neovim. + +Hybrid mode: +A way to preview & edit at the same time +--- + +It is now possible to see previews as you type. + +It works for all kinds of elements such as `inline codes`, +*italic*, **bold** etc. + +It also works for block elements. + +```lua +vim.print("Hello world"); +``` + +>[!Tip] +> It can also work on nested elements. +> +> ```vim +> set scrolloff=0 +> ``` + +It even works on list items, +- Item 1 +- Item 2 + - Nested 1 + - Nested 2 + +--- + + diff --git a/test.md b/test.md deleted file mode 100644 index e201323..0000000 --- a/test.md +++ /dev/null @@ -1,24 +0,0 @@ -- Hello -- My name is -- MD - - Moinul - - Hossain - - Shawon -- I like to do -- programming - - - ->[!IMPORTANT] -> dudjdjd - -> heidjejd -> jdidjdjdjd - - - - - - -# Heklo - diff --git a/wiki b/wiki deleted file mode 160000 index 9d04479..0000000 --- a/wiki +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9d04479666463d12a2a406e1a2ca8e9cc5c6ef28