diff options
27 files changed, 3606 insertions, 1375 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 4cfa53e..0a63a01 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -3,7 +3,7 @@ name: Bug about: Create a bug report title: 'Bug:' labels: bug -assignees: norcalli +assignees: akianonymus --- diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..828d09f --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,42 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["master"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Pages + uses: actions/configure-pages@v2 + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + # Upload entire repository + path: 'doc' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v1 @@ -1,6 +1,6 @@ # colorizer.lua -[![luadoc](https://img.shields.io/badge/luadoc-0.1-blue)](https://norcalli.github.io/luadoc/nvim-colorizer.lua/modules/colorizer.html) +[![luadoc](https://img.shields.io/badge/luadoc-0.1-blue)](https://akianonymus.github.io/luadoc/nvim-colorizer.lua/modules/colorizer.html) A high-performance color highlighter for Neovim which has **no external dependencies**! Written in performant Luajit. @@ -10,14 +10,14 @@ A high-performance color highlighter for Neovim which has **no external dependen ## Installation and Usage -Requires Neovim >= 0.4.0 and `set termguicolors` (I'm looking into relaxing -these constraints). If you don't have true color for your terminal or are +Requires Neovim >= 0.6.0 and `set termguicolors`. +If you don't have true color for your terminal or are unsure, [read this excellent guide](https://github.com/termstandard/colors). Use your plugin manager or clone directly into your package. ```lua -use 'NvChad/nvim-colorizer.lua' +use 'Akianonymus/nvim-colorizer.lua' ``` As long as you have `malloc()` and `free()` on your system, this will work. @@ -25,13 +25,37 @@ Which includes Linux, OSX, and Windows. One line setup. This will create an `autocmd` for `FileType *` to highlight every filetype. + **NOTE**: You should add this line after/below where your plugins are setup. ```lua require'colorizer'.setup() ``` -### Why another highlighter? +### Use with commands + +| Command | Description | +|---|---| +| **ColorizerAttachToBuffer** | Attach to the current buffer with given or default settings | +| **ColorizerDetachFromBuffer** | Stop highlighting the current buffer | +| **ColorizerReloadAllBuffers** | Reload all buffers that are being highlighted currently | +| **ColorizerToggle** | Toggle highlighting of the current buffer | + +### Use from lua + +```lua + +-- All options that can be passed to `user_default_options` in setup() can be passed here +-- Similar for other functions + +-- Attach to buffer +require("colorizer").attach_to_buffer(0, { mode = "background", css = true}) + +-- Detach from buffer +require("colorizer").detach_from_buffer(0, { mode = "virtualtext", css = true}) + +``` +## Why another highlighter? Mostly, **RAW SPEED**. @@ -43,24 +67,40 @@ handwritten parser, updates can be done in real time. There are plugins such as performance, but it has some difficulty with becoming out of sync. The downside is that _this only works for Neovim_, and that will never change. +Apart from that, it only applies the highlights to the current visible contents, so +even if a big file is opened, the editor won't just choke on a blank screen. + +This idea was copied from + [brenoprata10/nvim-highlight-colors](https://github.com/brenoprata10/nvim-highlight-colors.) +Credits to [brenoprata10](https://github.com/brenoprata10) + Additionally, having a Lua API that's available means users can use this as a library to do custom highlighting themselves. -### Customization +## Customization + +**Note**: These are the default options ```lua - DEFAULT_OPTIONS = { - RGB = true; -- #RGB hex codes - RRGGBB = true; -- #RRGGBB hex codes - names = true; -- "Name" codes like Blue oe blue - RRGGBBAA = false; -- #RRGGBBAA hex codes - rgb_fn = false; -- CSS rgb() and rgba() functions - hsl_fn = false; -- CSS hsl() and hsla() functions - css = false; -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, RRGGBB - css_fn = false; -- Enable all CSS *functions*: rgb_fn, hsl_fn - -- Available modes: foreground, background, virtualtext - mode = 'background'; -- Set the display mode. - } + require("colorizer").setup { + filetypes = { "*" }, + user_default_options = { + RGB = true, -- #RGB hex codes + RRGGBB = true, -- #RRGGBB hex codes + names = true, -- "Name" codes like Blue or blue + RRGGBBAA = false, -- #RRGGBBAA hex codes + AARRGGBB = false, -- 0xAARRGGBB hex codes + rgb_fn = false, -- CSS rgb() and rgba() functions + hsl_fn = false, -- CSS hsl() and hsla() functions + css = false, -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, RRGGBB + css_fn = false, -- Enable all CSS *functions*: rgb_fn, hsl_fn + -- Available modes for `mode`: foreground, background, virtualtext + mode = "background", -- Set the display mode. + virtualtext = "■", + }, + -- all the sub-options of filetypes apply to buftypes + buftypes = {}, + } ``` MODES: @@ -78,78 +118,78 @@ require 'colorizer'.setup() -- Attach to certain Filetypes, add special configuration for `html` -- Use `background` for everything else. require 'colorizer'.setup { - 'css'; - 'javascript'; - html = { - mode = 'foreground'; - } + filetypes = { + 'css', + 'javascript', + html = { mode = 'foreground'; } + }, } -- Use the `default_options` as the second parameter, which uses -- `foreground` for every mode. This is the inverse of the previous -- setup configuration. -require 'colorizer'.setup({ - 'css'; - 'javascript'; - html = { mode = 'background' }; -}, { mode = 'foreground' }) +require 'colorizer'.setup { + filetypes = { + 'css', + 'javascript', + html = { mode = 'foreground'; } + }, + user_default_options = { mode = "background", }, +} -- Use the `default_options` as the second parameter, which uses -- `foreground` for every mode. This is the inverse of the previous -- setup configuration. require 'colorizer'.setup { - '*'; -- Highlight all files, but customize some others. - css = { rgb_fn = true; }; -- Enable parsing rgb(...) functions in css. - html = { names = false; } -- Disable parsing "names" like Blue or Gray + filetypes = { + '*'; -- Highlight all files, but customize some others. + css = { rgb_fn = true; }; -- Enable parsing rgb(...) functions in css. + html = { names = false; } -- Disable parsing "names" like Blue or Gray + }, } -- Exclude some filetypes from highlighting by using `!` require 'colorizer'.setup { - '*'; -- Highlight all files, but customize some others. - '!vim'; -- Exclude vim from highlighting. + filetypes = { + '*'; -- Highlight all files, but customize some others. + '!vim'; -- Exclude vim from highlighting. -- Exclusion Only makes sense if '*' is specified! + }, } -``` - -For lower level interface, see the [LuaDocs for API details](https://norcalli.github.io/luadoc/nvim-colorizer.lua/modules/colorizer.html) or use `:h colorizer.lua` once installed. - -## Commands - -```help -|:ColorizerAttachToBuffer| - -Attach to the current buffer and start highlighting with the settings as -specified in setup (or the defaults). - -If the buffer was already attached (i.e. being highlighted), the settings will -be reloaded with the ones from setup. This is useful for reloading settings -for just one buffer. -|:ColorizerDetachFromBuffer| - -Stop highlighting the current buffer (detach). - -|:ColorizerReloadAllBuffers| +``` -Reload all buffers that are being highlighted with new settings from the setup -settings (or the defaults). Shortcut for ColorizerAttachToBuffer on every -buffer. +All the above examples can also be apply to buftypes. Also no buftypes trigger colorizer by default -|:ColorizerToggle| +Buftype value is fetched by `vim.bo.buftype` -Toggle highlighting of the current buffer. +```lua +-- need to specify buftypes +require 'colorizer'.setup( + buftypes = { + "*", + -- exclude prompt and popup buftypes from highlight + "!prompt", + "!popup", + } +) ``` -## Caveats +For lower level interface, see the [LuaDocs for API details](https://akianonymus.github.io/luadoc/nvim-colorizer.lua/modules/colorizer.html) or use `:h colorizer` once installed. -If the file you are editing has no filetype, the plugin won't be attached, as -it relies on AutoCmd to do so. You can still make it work by running the -following command: `:ColorizerAttachToBuffer` +## Extras -See [this comment](https://github.com/norcalli/nvim-colorizer.lua/issues/9#issuecomment-543742619) for more information. +Documentaion is generated using ldoc. See +[scripts/gen_docs.sh](https://github.com/Akianonymus/nvim-colorizer.lua/blob/master/scripts/gen_docs.sh) ## TODO -- [ ] Add more display modes? +- [ ] Add more colour types ( var, advanced css functions ) +- [ ] Add more display modes. E.g - sign column - [ ] Use a more space efficient trie implementation. -- [ ] Create a COMMON_SETUP which does obvious things like enable `rgb_fn` for css + +## Similar projects + +[nvim-highlight-colors](https://github.com/brenoprata10/nvim-highlight-colors) + +[vim-hexokinase](https://github.com/RRethy/vim-hexokinase) diff --git a/doc/colorizer-lua.txt b/doc/colorizer-lua.txt deleted file mode 100644 index 84db37f..0000000 --- a/doc/colorizer-lua.txt +++ /dev/null @@ -1,162 +0,0 @@ -*colorizer.lua* Highlight color codes like #RRGGBB and others. - -Minimum version of neovim: 0.4.0 - -Author: Ashkan Kiani <from-nvim-colorizer.lua@kiani.io> - -============================================================================== -INTRODUCTION *colorizer-lua-introduction* - -============================================================================== -QUICK START *colorizer-lua-quickstart* - -Establish the an autocmd to highlight all filetypes. -> - lua require 'colorizer'.setup() - - " Highlight using all available possible highlight modes in every filetype - lua require 'colorizer'.setup(nil, { css = true; }) -< - -============================================================================== -COMMANDS *colorizer-commands* - -|:ColorizerAttachToBuffer| *:ColorizerAttachToBuffer* - -Attach to the current buffer and start highlighting with the settings as -specified in setup (or the defaults). - -If the buffer was already attached (i.e. being highlighted), the settings will -be reloaded with the ones from setup. This is useful for reloading settings -for just one buffer. - - -|:ColorizerDetachFromBuffer| *:ColorizerDetachFromBuffer* - -Stop highlighting the current buffer (detach). - -|:ColorizerReloadAllBuffers| *:ColorizerReloadAllBuffers* - -Reload all buffers that are being highlighted with new settings from the setup -settings (or the defaults). Shortcut for ColorizerAttachToBuffer on every -buffer. - -:ColorizerToggle :ColorizerToggle - -Toggle highlighting of the current buffer. - -============================================================================== -LUA API DEFINITION *colorizer-lua-api* - -Assumes the module is imported as `colorizer` - -|colorizer-options| *colorizer-options* - -> - DEFAULT_OPTIONS = { - RGB = true; -- #RGB hex codes - RRGGBB = true; -- #RRGGBB hex codes - names = true; -- "Name" codes like Blue - RRGGBBAA = false; -- #RRGGBBAA hex codes - rgb_fn = false; -- CSS rgb() and rgba() functions - hsl_fn = false; -- CSS hsl() and hsla() functions - css = false; -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, RRGGBB - css_fn = false; -- Enable all CSS *functions*: rgb_fn, hsl_fn - -- Available modes: foreground, background - mode = 'background'; -- Set the display mode. - virtualtext = '■'; -- the virtual text block - } -< - -MODES: -- 'foreground': sets the foreground text color. -- 'background': sets the background text color. -- 'virtualtext': indicate the color behind the virtualtext - - -|colorizer.setup| *colorizer.setup* - -Easy to use function if you want the full setup without fine grained control. -Establishes an autocmd for `FileType`s . - -PARAMETERS: - `filetypes` (optional) filetypes to enable. see examples below - `default_options` (optional) |colorizer-options| -> - colorizer.setup([filetypes=nil], [default_options={}]) - - " In your VIMRC - lua require'colorizer'.setup() - - -- From lua - -- Attaches to every FileType mode - require 'colorizer'.setup() - - -- Attach to certain Filetypes, add special configuration for `html` - -- Use `background` for everything else. - require 'colorizer'.setup { - 'css'; - 'javascript'; - html = { - mode = 'foreground'; - } - } - - -- Use the `default_options` as the second parameter, which uses - -- `foreground` for every mode. This is the inverse of the previous - -- setup configuration. - require 'colorizer'.setup({ - 'css'; - 'javascript'; - html = { mode = 'background' }; - }, { mode = 'foreground' }) - - -- Use the `default_options` as the second parameter, which uses - -- `foreground` for every mode. This is the inverse of the previous - -- setup configuration. - require 'colorizer'.setup { - '*'; -- Highlight all files, but customize some others. - css = { rgb_fn = true; }; -- Enable parsing rgb(...) functions in css. - html = { names = false; } -- Disable parsing "names" like Blue or Gray - } - - -- Exclude some filetypes from highlighting by using `!` - require 'colorizer'.setup { - '*'; -- Highlight all files, but customize some others. - '!vim'; -- Exclude vim from highlighting. - -- Exclusion Only makes sense if '*' is specified! - } -< - -|colorizer.highlight_buffer| *colorizer.highlight_buffer* - -Highlight starting from `line_start` (0-indexed) for each line described by `lines` in the -buffer `buf` and attach it to the namespace `ns`. - -PARAMETERS: - `buf` buffer id. - `ns` the namespace id. Create it with `vim.api.create_namespace` - `lines` the lines to highlight from the buffer. - `line_start` should be 0-indexed - `options` |colorizer-options| to set. REQUIRED! -> - colorizer.highlight_buffer(buf[, ns=DEFAULT_NAMESPACE], - lines, line_start, options) -< - -|colorizer.attach_to_buffer| *colorizer.attach_to_buffer* - -Attach to a buffer and continuously highlight changes. - -If you don't specify `options`, it will be set from the setup options if -specified or the default in |colorizer-options|. - -PARAMETERS: - `buf` A value of 0 implies the current buffer. - `options` (optional) |colorizer-options| to set. -> - colorizer.attach_to_buffer(buf[, options={}]) -< - - vim:tw=78:ts=8:noet:ft=help:norl: - diff --git a/doc/colorizer.txt b/doc/colorizer.txt new file mode 100644 index 0000000..1480756 --- /dev/null +++ b/doc/colorizer.txt @@ -0,0 +1,465 @@ +*colorizer* Requires Neovim >= 0.6.0 and `set termguicolors` + +Highlights terminal CSI ANSI color codes. + +Author: Ashkan Kiani <from-nvim-colorizer.lua@kiani.io> + +============================================================================== +USAGE *colorizer-usage* + + Establish the autocmd to highlight all filetypes. + + `lua require 'colorizer'.setup()` + + Highlight using all css highlight modes in every filetype + + `lua require 'colorizer'.setup(user_default_options = { css = true; })` + +============================================================================== +USE WITH COMMANDS *colorizer-commands* + + *:ColorizerAttachToBuffer* + + Attach to the current buffer and start highlighting with the settings as + specified in setup (or the defaults). + + If the buffer was already attached(i.e. being highlighted), the + settings will be reloaded with the ones from setup. + This is useful for reloading settings for just one buffer. + + *:ColorizerDetachFromBuffer* + + Stop highlighting the current buffer (detach). + + *:ColorizerReloadAllBuffers* + + Reload all buffers that are being highlighted currently. + Shortcut for ColorizerAttachToBuffer on every buffer. + + *:ColorizerToggle* + Toggle highlighting of the current buffer. + +USE WITH LUA + + All options that can be passed to user_default_options in `setup` + can be passed here. Can be empty too. + `0` is the buffer number here + + Attach to current buffer > + require("colorizer").attach_to_buffer(0, { + mode = "background", + css = false, + }) +< + Detach from buffer > + require("colorizer").detach_from_buffer(0, { + mode = "background", + css = false, + }) +< + + See:~ + |colorizer.setup| + |colorizer.attach_to_buffer| + |colorizer.detach_from_buffer| + +============================================================================== +LUA API *colorizer-lua-api* + +Functions: ~ + |highlight_buffer| - Highlight the buffer region + + |is_buffer_attached| - Check if attached to a buffer. + + |detach_from_buffer| - Stop highlighting the current buffer. + + |attach_to_buffer| - Attach to a buffer and continuously highlight changes. + + |setup| - Easy to use function if you want the full setup without fine + grained control. + + |get_buffer_options| - Return the currently active buffer options. + + |reload_all_buffers| - Reload all of the currently active highlighted + buffers. + + |clear_highlight_cache| - Clear the highlight cache and reload all buffers. + +Fields: ~ + |DEFAULT_NAMESPACE| - Default namespace used in + `colorizer.buffer_utils.highlight_buffer` and `attach_to_buffer`. + + +highlight_buffer() *colorizer.highlight_buffer* + Highlight the buffer region + + See also:~ + |colorizer.buffer_utils.highlight_buffer| + + + +is_buffer_attached({buf}) *colorizer.is_buffer_attached* + Check if attached to a buffer. + + Parameters: ~ + {buf} - number|nil: A value of 0 implies the current buffer. + + returns:~ + number|nil: if attached to the buffer, false otherwise. + + See also:~ + |highlight_buffer| + + + +detach_from_buffer({buf}, {ns}) *colorizer.detach_from_buffer* + Stop highlighting the current buffer. + + Parameters: ~ + {buf} - number|nil: buf A value of 0 or nil implies the current buffer. + {ns} - number|nil: ns the namespace id, if not given DEFAULT_NAMESPACE + is used + + + +attach_to_buffer({buf}, {options}, {typ}) *colorizer.attach_to_buffer* + Attach to a buffer and continuously highlight changes. + + Parameters: ~ + {buf} - integer: A value of 0 implies the current buffer. + {options} - table: Configuration options as described in `setup` + {typ} - string|nil: "buf" or "file" - The type of buffer option + + + +setup({config}) *colorizer.setup* + Easy to use function if you want the full setup without fine grained + control. + + Setup an autocmd which enables colorizing for the filetypes and options + specified. + + By default highlights all FileTypes. + + Example config:~ +> + { filetypes = { "css", "html" }, user_default_options = { names = true } } +< + Setup with all the default options:~ +> + require("colorizer").setup { + filetypes = { "*" }, + user_default_options = { + RGB = true, -- #RGB hex codes + RRGGBB = true, -- #RRGGBB hex codes + names = true, -- "Name" codes like Blue or blue + RRGGBBAA = false, -- #RRGGBBAA hex codes + AARRGGBB = false, -- 0xAARRGGBB hex codes + rgb_fn = false, -- CSS rgb() and rgba() functions + hsl_fn = false, -- CSS hsl() and hsla() functions + css = false, -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, + RRGGBB + css_fn = false, -- Enable all CSS *functions*: rgb_fn, hsl_fn + -- Available modes for `mode`: foreground, background, virtualtext + mode = "background", -- Set the display mode. + virtualtext = "■", + }, + -- all the sub-options of filetypes apply to buftypes + buftypes = {}, + } +< + + + Parameters: ~ + {config} - table: Config containing above parameters. + + Usage:~ + `require'colorizer'.setup()` + + + +get_buffer_options({buf}) *colorizer.get_buffer_options* + Return the currently active buffer options. + + Parameters: ~ + {buf} - number|nil: Buffer number + + + +reload_all_buffers() *colorizer.reload_all_buffers* + Reload all of the currently active highlighted buffers. + + + +clear_highlight_cache() *colorizer.clear_highlight_cache* + Clear the highlight cache and reload all buffers. + + + +DEFAULT_NAMESPACE *colorizer.DEFAULT_NAMESPACE* + Default namespace used in `colorizer.buffer_utils.highlight_buffer` and + `attach_to_buffer`. + + See also:~ + |colorizer.buffer_utils.highlight_buffer| + |attach_to_buffer| + + + +============================================================================== +BUFFER_UTILS *colorizer.buffer_utils-introduction* + +Helper functions to highlight buffer smartly + + +============================================================================== +LUA API *colorizer.buffer_utils-lua-api* + +Functions: ~ + |highlight_buffer| - Highlight the buffer region. + + |rehighlight_buffer| - Rehighlight the buffer if colorizer is active + +Tables: ~ + |HIGHLIGHT_MODE_NAMES| - Highlight mode which will be use to render the + colour + +Fields: ~ + |DEFAULT_NAMESPACE| - Default namespace used in `highlight_buffer` and + `colorizer.attach_to_buffer`. + + + + *colorizer.buffer_utils.highlight_buffer* +highlight_buffer({buf}, {ns}, {lines}, {line_start}, {options}) + Highlight the buffer region. + + Highlight starting from `line_start` (0-indexed) for each line described by + `lines` in the + buffer `buf` and attach it to the namespace `ns`. + + + Parameters: ~ + {buf} - number: buffer id + {ns} - number: The namespace id. Default is DEFAULT_NAMESPACE. Create + it with `vim.api.create_namespace` + {lines} - table: the lines to highlight from the buffer. + {line_start} - number: line_start should be 0-indexed + {options} - table: Configuration options as described in `setup` + + + +rehighlight_buffer({buf}, {options}) *colorizer.buffer_utils.rehighlight_buffer* + Rehighlight the buffer if colorizer is active + + Parameters: ~ + {buf} - number: Buffer number + {options} - table: Buffer options + + + +HIGHLIGHT_MODE_NAMES *colorizer.buffer_utils.HIGHLIGHT_MODE_NAMES* + Highlight mode which will be use to render the colour + + Fields: ~ + {background} - + {foreground} - + {virtualtext} - + + + +DEFAULT_NAMESPACE *colorizer.buffer_utils.DEFAULT_NAMESPACE* + Default namespace used in `highlight_buffer` and + `colorizer.attach_to_buffer`. + + See also:~ + |highlight_buffer| + |colorizer.attach_to_buffer| + + + +============================================================================== +COLOR_UTILS *colorizer.color_utils-introduction* + +Helper functions to parse different colour formats + + +============================================================================== +LUA API *colorizer.color_utils-lua-api* + +Functions: ~ + |color_is_bright| - Determine whether to use black or white text. + + |color_name_parser| - Grab all the colour values from + `vim.api.nvim_get_color_map` and create a lookup table. + + |rgb_function_parser| - Parse for rgb() css function and return rgb hex. + + |rgba_function_parser| - Parse for rgba() css function and return rgb hex. + + |hsl_function_parser| - Parse for hsl() css function and return rgb hex. + + |hsla_function_parser| - Parse for hsl() css function and return rgb hex. + + |argb_hex_parser| - parse for 0xaarrggbb and return rgb hex. + + |rgba_hex_parser| - parse for #rrggbbaa and return rgb hex. + + +color_is_bright({r}, {g}, {b}) *colorizer.color_utils.color_is_bright* + Determine whether to use black or white text. + + + ref: https://stackoverflow.com/a/1855903/837964 + https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color + + + Parameters: ~ + {r} - number: Red + {g} - number: Green + {b} - number: Blue + + + +color_name_parser({line}, {i}) *colorizer.color_utils.color_name_parser* + Grab all the colour values from `vim.api.nvim_get_color_map` and create a + lookup table. + + COLOR_MAP is used to store the colour values + + + Parameters: ~ + {line} - string: Line to parse + {i} - number: Index of line from where to start parsing + + + +rgb_function_parser({line}, {i}) *colorizer.color_utils.rgb_function_parser* + Parse for rgb() css function and return rgb hex. + + Parameters: ~ + {line} - string: Line to parse + {i} - number: Index of line from where to start parsing + + returns:~ + number|nil: Index of line where the rgb function ended + string|nil: rgb hex value + + + +rgba_function_parser({line}, {i}) *colorizer.color_utils.rgba_function_parser* + Parse for rgba() css function and return rgb hex. + + Todo consider removing the regexes here + Todo this might not be the best approach to alpha channel. + Things like pumblend might be useful here. + + + Parameters: ~ + {line} - string: Line to parse + {i} - number: Index of line from where to start parsing + + returns:~ + number|nil: Index of line where the rgba function ended + string|nil: rgb hex value + + + +hsl_function_parser({line}, {i}) *colorizer.color_utils.hsl_function_parser* + Parse for hsl() css function and return rgb hex. + + Parameters: ~ + {line} - string: Line to parse + {i} - number: Index of line from where to start parsing + + returns:~ + number|nil: Index of line where the hsl function ended + string|nil: rgb hex value + + + +hsla_function_parser({line}, {i}) *colorizer.color_utils.hsla_function_parser* + Parse for hsl() css function and return rgb hex. + + Parameters: ~ + {line} - string: Line to parse + {i} - number: Index of line from where to start parsing + + returns:~ + number|nil: Index of line where the hsla function ended + string|nil: rgb hex value + + + +argb_hex_parser({line}, {i}) *colorizer.color_utils.argb_hex_parser* + parse for 0xaarrggbb and return rgb hex. + + a format used in android apps + + + Parameters: ~ + {line} - string: line to parse + {i} - number: index of line from where to start parsing + + returns:~ + number|nil: index of line where the hex value ended + string|nil: rgb hex value + + + +rgba_hex_parser({line}, {i}, {opts}) *colorizer.color_utils.rgba_hex_parser* + parse for #rrggbbaa and return rgb hex. + + a format used in android apps + + + Parameters: ~ + {line} - string: line to parse + {i} - number: index of line from where to start parsing + {opts} - table: Containing minlen, maxlen, valid_lengths + + returns:~ + number|nil: index of line where the hex value ended + string|nil: rgb hex value + + + +============================================================================== +MATCHER_UTILS *colorizer.matcher_utils-introduction* + +Helper functions for colorizer to enable required parsers + + +============================================================================== +LUA API *colorizer.matcher_utils-lua-api* + +Functions: ~ + |make_matcher| - Parse the given options and return a function with enabled + parsers. + + +make_matcher({options}) *colorizer.matcher_utils.make_matcher* + Parse the given options and return a function with enabled parsers. + + if no parsers enabled then return false + Do not try make the function again if it is present in the cache + + + Parameters: ~ + {options} - table: options created in `colorizer.setup` + + returns:~ + function|boolean: function which will just parse the line for enabled + parsers + + + +============================================================================== +TRIE *colorizer.trie-introduction* + +Trie implementation in luajit. + +todo: write documentation + + +vim:tw=80:ts=8:noet:ft=help:norl: diff --git a/doc/index.html b/doc/index.html index fdeae17..ae0a8d2 100644 --- a/doc/index.html +++ b/doc/index.html @@ -3,7 +3,7 @@ <html> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <head> - <title>Reference</title> + <title>colorizer Docs</title> <link rel="stylesheet" href="ldoc.css" type="text/css" /> </head> <body> @@ -24,7 +24,7 @@ <div id="navigation"> <br/> -<h1>ldoc</h1> +<h1>colorizer</h1> @@ -32,8 +32,11 @@ <h2>Modules</h2> <ul class="nowrap"> <li><a href="modules/colorizer.html">colorizer</a></li> - <li><a href="modules/nvim.html">nvim</a></li> - <li><a href="modules/trie.html">trie</a></li> + <li><a href="modules/colorizer.buffer_utils.html">buffer_utils</a></li> + <li><a href="modules/colorizer.color_utils.html">color_utils</a></li> + <li><a href="modules/colorizer.matcher_utils.html">matcher_utils</a></li> + <li><a href="modules/colorizer.trie.html">trie</a></li> + <li><a href="modules/utils.html">utils</a></li> </ul> </div> @@ -46,16 +49,27 @@ <table class="module_list"> <tr> <td class="name" nowrap><a href="modules/colorizer.html">colorizer</a></td> - <td class="summary">Highlights terminal CSI ANSI color codes.</td> + <td class="summary">Requires Neovim >= 0.6.0 and <code>set termguicolors</code></td> </tr> <tr> - <td class="name" nowrap><a href="modules/nvim.html">nvim</a></td> - <td class="summary">Module of magic functions for nvim</td> + <td class="name" nowrap><a href="modules/colorizer.buffer_utils.html">colorizer.buffer_utils</a></td> + <td class="summary">Helper functions to highlight buffer smartly</td> </tr> <tr> - <td class="name" nowrap><a href="modules/trie.html">trie</a></td> - <td class="summary">Trie implementation in luajit - Copyright © 2019 Ashkan Kiani</td> + <td class="name" nowrap><a href="modules/colorizer.color_utils.html">colorizer.color_utils</a></td> + <td class="summary">Helper functions to parse different colour formats</td> + </tr> + <tr> + <td class="name" nowrap><a href="modules/colorizer.matcher_utils.html">colorizer.matcher_utils</a></td> + <td class="summary">Helper functions for colorizer to enable required parsers</td> + </tr> + <tr> + <td class="name" nowrap><a href="modules/colorizer.trie.html">colorizer.trie</a></td> + <td class="summary">Trie implementation in luajit.</td> + </tr> + <tr> + <td class="name" nowrap><a href="modules/utils.html">utils</a></td> + <td class="summary">Helper utils</td> </tr> </table> @@ -63,7 +77,7 @@ </div> <!-- id="main" --> <div id="about"> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> -<i style="float:right;">Last updated 2019-10-18 09:40:19 </i> +<i style="float:right;">Last updated 2022-09-03 17:24:13 </i> </div> <!-- id="about" --> </div> <!-- id="container" --> </body> diff --git a/doc/ldoc.css b/doc/ldoc.css index 52c4ad2..0863257 100644 --- a/doc/ldoc.css +++ b/doc/ldoc.css @@ -1,303 +1,328 @@ -/* BEGIN RESET +@import url(https://fonts.googleapis.com/css?family=Quicksand:300,700); +@import url(https://fonts.googleapis.com/css?family=Lato); -Copyright (c) 2010, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.com/yui/license.html -version: 2.8.2r1 -*/ -html { - color: #000; - background: #FFF; +body { + margin-left: 1em; + margin-right: 1em; + font-family: "Lato", arial, helvetica, geneva, sans-serif; + background-color: #ffffff; + margin: 0px; + color: #1c4e68; } -body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { - margin: 0; - padding: 0; + +code, +tt { + font-family: monospace; + font-size: 1.1em; } -table { - border-collapse: collapse; - border-spacing: 0; +span.parameter { + font-family: monospace; } -fieldset,img { - border: 0; +span.parameter:after { + content: ":"; } -address,caption,cite,code,dfn,em,strong,th,var,optgroup { - font-style: inherit; - font-weight: inherit; +span.types:before { + content: "("; } -del,ins { - text-decoration: none; +span.types:after { + content: ")"; } -li { - margin-left: 20px; +.type { + font-weight: bold; + font-style: italic; } -caption,th { - text-align: left; + +body, +p, +td, +th { + font-size: 1em; + line-height: 1.2em; } -h1,h2,h3,h4,h5,h6 { - font-size: 100%; - font-weight: bold; + +p, +ul { + margin: 10px 0 0 0px; } -q:before,q:after { - content: ''; + +strong { + font-weight: bold; } -abbr,acronym { - border: 0; - font-variant: normal; + +em { + font-style: italic; } -sup { - vertical-align: baseline; + +h1 { + font-family: "Quicksand", sans-serif; + font-weight: 700; + color: #ea316e; + font-size: 1.5em; + margin: 20px 0 20px 0; } -sub { - vertical-align: baseline; +h2, +h3, +h4 { + font-family: "Quicksand", sans-serif; + font-weight: 700; + margin: 15px 0 10px 0; } -legend { - color: #000; +h2 { + font-size: 1.25em; + color: #ea316e; } -input,button,textarea,select,optgroup,option { - font-family: inherit; - font-size: inherit; - font-style: inherit; - font-weight: inherit; +h3 { + font-size: 1.15em; } -input,button,textarea,select {*font-size:100%; +h4 { + font-size: 1.06em; } -/* END RESET */ -body { - margin-left: 1em; - margin-right: 1em; - font-family: arial, helvetica, geneva, sans-serif; - background-color: #ffffff; margin: 0px; +a:link { + font-weight: bold; + color: #1c4e68; + text-decoration: none; } - -code, tt { font-family: monospace; font-size: 1.1em; } -span.parameter { font-family:monospace; } -span.parameter:after { content:":"; } -span.types:before { content:"("; } -span.types:after { content:")"; } -.type { font-weight: bold; font-style:italic } - -body, p, td, th { font-size: .95em; line-height: 1.2em;} - -p, ul { margin: 10px 0 0 0px;} - -strong { font-weight: bold;} - -em { font-style: italic;} - -h1 { - font-size: 1.5em; - margin: 20px 0 20px 0; +a:visited { + font-weight: bold; + color: #1e86be; + text-decoration: none; +} +a:link:hover { + text-decoration: underline; } -h2, h3, h4 { margin: 15px 0 10px 0; } -h2 { font-size: 1.25em; } -h3 { font-size: 1.15em; } -h4 { font-size: 1.06em; } - -a:link { font-weight: bold; color: #004080; text-decoration: none; } -a:visited { font-weight: bold; color: #006699; text-decoration: none; } -a:link:hover { text-decoration: underline; } hr { - color:#cccccc; - background: #00007f; - height: 1px; + color: #b1e3fa; + background: #00007f; + height: 1px; } -blockquote { margin-left: 3em; } +blockquote { + margin-left: 3em; +} -ul { list-style-type: disc; } +ul { + list-style-type: disc; +} p.name { - font-family: "Andale Mono", monospace; - padding-top: 1em; + font-family: "Andale Mono", monospace; + padding-top: 1em; } pre { - background-color: rgb(245, 245, 245); - border: 1px solid #C0C0C0; /* silver */ - padding: 10px; - margin: 10px 0 10px 0; - overflow: auto; - font-family: "Andale Mono", monospace; + background-color: rgb(245, 245, 245); + border: 1px solid #c0c0c0; /* silver */ + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: "Andale Mono", monospace; } pre.example { - font-size: .85em; + font-size: 0.85em; } -table.index { border: 1px #00007f; } -table.index td { text-align: left; vertical-align: top; } +table.index { + border: 1px #b1e3fa; +} +table.index td { + text-align: left; + vertical-align: top; +} #container { - margin-left: 1em; - margin-right: 1em; - background-color: #f0f0f0; + margin-left: 1em; + margin-right: 1em; + background-color: #e0f4fc; } #product { - text-align: center; - border-bottom: 1px solid #cccccc; - background-color: #ffffff; + text-align: center; + border-bottom: 1px solid #b1e3fa; + background-color: #ffffff; } #product big { - font-size: 2em; + font-size: 2em; } #main { - background-color: #f0f0f0; - border-left: 2px solid #cccccc; + background-color: #e0f4fc; + border-left: 2px solid #b1e3fa; } #navigation { - float: left; - width: 14em; - vertical-align: top; - background-color: #f0f0f0; - overflow: visible; + float: left; + width: 14em; + vertical-align: top; + background-color: #e0f4fc; + overflow: visible; } #navigation h2 { - background-color:#e7e7e7; - font-size:1.1em; - color:#000000; - text-align: left; - padding:0.2em; - border-top:1px solid #dddddd; - border-bottom:1px solid #dddddd; + background-color: #aee7ff; + font-size: 1.1em; + color: #25aae1; + text-align: left; + padding: 0.2em; + border-top: 1px solid #b1e3fa; + border-bottom: 1px solid #b1e3fa; } -#navigation ul -{ - font-size:1em; - list-style-type: none; - margin: 1px 1px 10px 1px; +#navigation h1 { + font-family: "Quicksand", sans-serif; + font-weight: 300; + font-size: 32px; + padding-left: 20px; + padding-bottom: 20px; +} +#navigation ul { + font-size: 1em; + list-style-type: none; + margin: 1px 1px 10px 1px; + padding-left: 0px; } #navigation li { - text-indent: -1em; - display: block; - margin: 3px 0px 0px 22px; + font-size: 12px; + display: block; + margin: 3px 0px 0px 22px; + padding-left: 0px; } #navigation li li a { - margin: 0px 3px 0px -1em; + margin: 0px 3px 0px -1em; } #content { - margin-left: 14em; - padding: 1em; - width: 700px; - border-left: 2px solid #cccccc; - border-right: 2px solid #cccccc; - background-color: #ffffff; + margin-left: 14em; + padding: 1em; + border-left: 2px solid #b1e3fa; + border-right: 2px solid #b1e3fa; + background-color: #ffffff; } #about { - clear: both; - padding: 5px; - border-top: 2px solid #cccccc; - background-color: #ffffff; + clear: both; + padding: 5px; + border-top: 2px solid #b1e3fa; + background-color: #ffffff; + font-size: 10px; } @media print { - body { - font: 12pt "Times New Roman", "TimeNR", Times, serif; - } - a { font-weight: bold; color: #004080; text-decoration: underline; } - - #main { - background-color: #ffffff; - border-left: 0px; - } - - #container { - margin-left: 2%; - margin-right: 2%; - background-color: #ffffff; - } - - #content { - padding: 1em; - background-color: #ffffff; - } - - #navigation { - display: none; - } - pre.example { - font-family: "Andale Mono", monospace; - font-size: 10pt; - page-break-inside: avoid; - } + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { + font-weight: bold; + color: #1c4e68; + text-decoration: underline; + } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } } table.module_list { - border-width: 1px; - border-style: solid; - border-color: #cccccc; - border-collapse: collapse; + border-width: 1px; + border-style: solid; + border-color: #b1e3fa; + border-collapse: collapse; } table.module_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #cccccc; + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #b1e3fa; +} +table.module_list td.name { + background-color: #e0f4fc; + min-width: 200px; +} +table.module_list td.summary { + width: 100%; } -table.module_list td.name { background-color: #f0f0f0; min-width: 200px; } -table.module_list td.summary { width: 100%; } - table.function_list { - border-width: 1px; - border-style: solid; - border-color: #cccccc; - border-collapse: collapse; + border-width: 1px; + border-style: solid; + border-color: #b1e3fa; + border-collapse: collapse; } table.function_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #cccccc; + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #b1e3fa; +} +table.function_list td.name { + background-color: #e0f4fc; + min-width: 200px; +} +table.function_list td.summary { + width: 100%; } -table.function_list td.name { background-color: #f0f0f0; min-width: 200px; } -table.function_list td.summary { width: 100%; } ul.nowrap { - overflow:auto; - white-space:nowrap; + overflow: auto; + white-space: nowrap; } -dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} -dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} -dl.table h3, dl.function h3 {font-size: .95em;} +dl.table dt, +dl.function dt { + border-top: 1px solid #b1e3fa; + padding-top: 1em; +} +dl.table dd, +dl.function dd { + padding-bottom: 1em; + margin: 10px 0 0 20px; +} +dl.table h3, +dl.function h3 { + font-size: 0.95em; +} /* stop sublists from having initial vertical space */ -ul ul { margin-top: 0px; } -ol ul { margin-top: 0px; } -ol ol { margin-top: 0px; } -ul ol { margin-top: 0px; } +ul ul { + margin-top: 0px; +} +ol ul { + margin-top: 0px; +} +ol ol { + margin-top: 0px; +} +ul ol { + margin-top: 0px; +} /* make the target distinct; helps when we're navigating to a function */ a:target + * { - background-color: #FF9; -} - - -/* styles for prettification of source */ -pre .comment { color: #558817; } -pre .constant { color: #a8660d; } -pre .escape { color: #844631; } -pre .keyword { color: #aa5050; font-weight: bold; } -pre .library { color: #0e7c6b; } -pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; } -pre .string { color: #8080ff; } -pre .number { color: #f8660d; } -pre .operator { color: #2239a8; font-weight: bold; } -pre .preprocessor, pre .prepro { color: #a33243; } -pre .global { color: #800080; } -pre .user-keyword { color: #800080; } -pre .prompt { color: #558817; } -pre .url { color: #272fc2; text-decoration: underline; } - + background-color: #ff9; +} diff --git a/doc/ldoc_vim.ltp b/doc/ldoc_vim.ltp new file mode 100644 index 0000000..baf388e --- /dev/null +++ b/doc/ldoc_vim.ltp @@ -0,0 +1,230 @@ +# -- Yes this file is a huge mess but working with what we got +# local header = '==============================================================================' +# -- Most stuff copied from ldoc html tempelate +# local no_spaces = ldoc.no_spaces +# local use_li = ldoc.use_li +# local display_name = ldoc.display_name +# local iter = ldoc.modules.iter +# local function M(txt,item) return ldoc.markup(txt,item,ldoc.plain) end +# local nowrap = "" +# local width = #header +# local indentstr = "" +# for i = 1, 4 do indentstr = indentstr .. " " end +# local function new_header(start, e, noh, sep) +# local s = " " +# s = s:rep(width-(#e+ #start)) +# local w = #s + #start + #e +# if w > width then +# local s = " " +# return (noh and "" or header) .. "\n\n".. s:rep(width - #e) .. sep .. e .. sep .. "\n" .. start +# else +# return (noh and "" or header) .. "\n" .. start .. s .. sep .. e .. sep +# end +# end +# +#local function magiclines( str ) +# local pos = 1; +# return function() +# if not pos then return nil end +# local p1, p2 = str:find( "\r?\n", pos ) +# local line +# if p1 then +# line = str:sub( pos, p1 - 1 ) +# pos = p2 + 1 +# else +# line = str:sub( pos ) +# pos = nil +# end +# return line +# end +#end +# local function indent(s, n) +# n = n or 1 +# local a = "" +# local ss = indentstr:rep(n) +# s = s:gsub("^", ss):gsub("\r?\n", "\n" .. ss) +# -- to handle vim style comments +# s = s:gsub(ss .. "<" , "<") +# s = s:gsub(ss .. ">" , ">") +# return s +# end +# if module then -- module documentation +# local intro = module.name:gsub(".*%.", ""):upper() +# if module.name == ldoc.project then +*$(module.name)*$(indentstr)$(module.summary) + +$(module.description) + +# else +$(new_header(intro, module.name .. "-introduction", false, "*")) + +$(module.summary) +$(module.description) +# end +# if module.info then +# for tag, value in module.info:iter() do +$(tag): $(value) +# end +# end -- if module.info + +# if module.usage then +$(new_header("USAGE", module.name .. "-usage", false, "*")) + +# for usage in iter(module.usage) do +$(usage) +# end -- for +# end -- if usage +# if module.tags.include then + $(M(ldoc.include_file(module.tags.include))) +# end +# if module.see then +$(indent("See:"))~ +# for see in iter(module.see) do +$(indent("|" .. see.label, 2))| +# end -- for + +# end -- if see +# if not ldoc.no_summary then +# local function_present = true +# -- bang out the tables of item types for this module (e.g Functions, Tables, etc) +# for kind,items in module.kinds() do +# if function_present then +$(new_header("LUA API", module.name .. "-lua-api", false, "*")) + +# end +# function_present = false +$(kind): ~ +# for item in items() do +$(indentstr)|$(item.name)| - $(M(item.summary,item)) + +# end -- for items +#end -- for kinds +#end -- if not no_summary +# --- currently works for both Functions and Tables. The params field either contains +# --- function parameters or table fields. +# local show_return = not ldoc.no_return_or_parms +# local show_parms = show_return +# for kind, items in module.kinds() do +# for item in items() do +# local plist = "" +# for parm in iter(item.params) do +# local param,sublist = item:subparam(parm) +# for p in iter(param) do +# local name,tp,def = item:display_name_of(p), ldoc.typename(item:type_of_param(p)), item:default_of_param(p) +# if plist == "" then +# plist = "{" .. name .. "}" +# else +# plist = plist .. ", " .. "{" .. name .. "}" +# end +# end -- for +# end +# if item.type == "function" then +$(new_header(item.name .. "(" .. plist .. ")", module.name .. "." .. item.name, true, "*")) +# else +$(new_header(item.name,module.name .. "." .. item.name , true, "*")) +#end +$(indent(item.summary)) +# if item.description ~= "" then +$(indent(item.description)) + +# end +# if ldoc.custom_tags then +# for custom in iter(ldoc.custom_tags) do +# local tag = item.tags[custom[1]] +# if tag and not custom.hidden then +# local li,il = use_li(tag) +$(indentstr)$(indentstr)$(custom.title or custom[1]): +# for value in iter(tag) do +$(indentstr)$(indentstr)$(indentstr)$(custom.format and custom.format(value) or M(value)) +# end -- for +# end -- if tag +# end -- iter tags +# end +# if show_parms and item.params and #item.params > 0 then +# local subnames = module.kinds:type_of(item).subnames +# if subnames then + +$(indentstr)$(subnames): ~ +# end +# for parm in iter(item.params) do +# local param,sublist = item:subparam(parm) +# if sublist then + $(sublist) - $(M(item.params.map[sublist],item)) +# end +# for p in iter(param) do +# local name,tp,def = item:display_name_of(p), ldoc.typename(item:type_of_param(p)), item:default_of_param(p) +# if tp ~= '' then + $(tp) +# end +$(indent("", 2)){$(name)} - $(M(item.params.map[p],item)) +# if def == true then + (optional) +# elseif def then + (default $(def)) +# end +# if item:readonly(p) then + readonly +# end +# end +# if sublist then +# end +# end -- for +# end -- if params +# if show_return and item.retgroups then local groups = item.retgroups + +$(indentstr)returns:~ +# for i,group in ldoc.ipairs(groups) do local li,il = use_li(group) +# for r in group:iter() do local type, ctypes = item:return_type(r); local rt = ldoc.typename(type) +# if rt ~= '' then + $(rt) +# end +$(indent("", 2))$(r.text) +# if ctypes then +# for c in ctypes:iter() do + $(c.name) + $(ldoc.typename(c.type)) + $(M(c.comment,item)) +# end +# end -- if ctypes +# end -- for r +# if i < #groups then +Or +# end +# end -- for group +# end -- if returns +# if show_return and item.raise then + Raises: + $(M(item.raise,item)) +# end +# if item.see then +# local see_present = false +# for see in iter(item.see) do +# if not see_present then + +$(indentstr)See also:~ +# end +# see_present = true +$(indentstr)$(indentstr)|$(see.label)| +# end -- for +# end -- if see + +# if item.usage then +$(indentstr)Usage:~ +# for usage in iter(item.usage) do +$(indentstr)$(indentstr)$(usage) +# end -- for +# end -- if usage + +# end -- for items +# end -- for kinds + +# else -- if module; project-level contents +# for kind, mods in ldoc.kinds() do +$(kind) +# kind = kind:lower() +# for m in mods() do +$(nowrap) - "$(no_spaces(kind))/$(m.name).html" - $(m.name) + $(M(ldoc.strip_header(m.summary),m)) +# end -- for modules +# end -- for kinds +# end -- if module diff --git a/doc/modules/colorizer.buffer_utils.html b/doc/modules/colorizer.buffer_utils.html new file mode 100644 index 0000000..f2f75fe --- /dev/null +++ b/doc/modules/colorizer.buffer_utils.html @@ -0,0 +1,222 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> +<head> + <title>colorizer Docs</title> + <link rel="stylesheet" href="../ldoc.css" type="text/css" /> +</head> +<body> + +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + + +<div id="main"> + + +<!-- Menu --> + +<div id="navigation"> +<br/> +<h1>colorizer</h1> + +<ul> + <li><a href="../index.html">Index</a></li> +</ul> + +<h2>Contents</h2> +<ul> +<li><a href="#Functions">Functions</a></li> +<li><a href="#Tables">Tables</a></li> +<li><a href="#Fields">Fields</a></li> +</ul> + + +<h2>Modules</h2> +<ul class="nowrap"> + <li><a href="../modules/colorizer.html">colorizer</a></li> + <li><strong>buffer_utils</strong></li> + <li><a href="../modules/colorizer.color_utils.html">color_utils</a></li> + <li><a href="../modules/colorizer.matcher_utils.html">matcher_utils</a></li> + <li><a href="../modules/colorizer.trie.html">trie</a></li> + <li><a href="../modules/utils.html">utils</a></li> +</ul> + +</div> + +<div id="content"> + +<h1>Module <code>colorizer.buffer_utils</code></h1> +<p>Helper functions to highlight buffer smartly</p> +<p> + +</p> + + +<h2><a href="#Functions">Functions</a></h2> +<table class="function_list"> + <tr> + <td class="name" nowrap><a href="#highlight_buffer">highlight_buffer (buf, ns, lines, line_start, options)</a></td> + <td class="summary">Highlight the buffer region.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#rehighlight_buffer">rehighlight_buffer (buf, options)</a></td> + <td class="summary">Rehighlight the buffer if colorizer is active</td> + </tr> +</table> +<h2><a href="#Tables">Tables</a></h2> +<table class="function_list"> + <tr> + <td class="name" nowrap><a href="#HIGHLIGHT_MODE_NAMES">HIGHLIGHT_MODE_NAMES</a></td> + <td class="summary">Highlight mode which will be use to render the colour</td> + </tr> +</table> +<h2><a href="#Fields">Fields</a></h2> +<table class="function_list"> + <tr> + <td class="name" nowrap><a href="#DEFAULT_NAMESPACE">DEFAULT_NAMESPACE</a></td> + <td class="summary">Default namespace used in <a href="../modules/colorizer.buffer_utils.html#highlight_buffer">highlight_buffer</a> and <a href="../modules/colorizer.html#attach_to_buffer">colorizer.attach_to_buffer</a>.</td> + </tr> +</table> + +<br/> +<br/> + + + <h2 class="section-header "><a name="Functions"></a>Functions</h2> + + <dl class="function"> + <dt> + <a name = "highlight_buffer"></a> + <strong>highlight_buffer (buf, ns, lines, line_start, options)</strong> + </dt> + <dd> + Highlight the buffer region. + Highlight starting from <code>line_start</code> (0-indexed) for each line described by <code>lines</code> in the + buffer <code>buf</code> and attach it to the namespace <code>ns</code>. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">buf</span> + number: buffer id + </li> + <li><span class="parameter">ns</span> + number: The namespace id. Default is DEFAULT_NAMESPACE. Create it with <code>vim.api.create_namespace</code> + </li> + <li><span class="parameter">lines</span> + table: the lines to highlight from the buffer. + </li> + <li><span class="parameter">line_start</span> + number: line_start should be 0-indexed + </li> + <li><span class="parameter">options</span> + table: Configuration options as described in <code>setup</code> + </li> + </ul> + + + + + +</dd> + <dt> + <a name = "rehighlight_buffer"></a> + <strong>rehighlight_buffer (buf, options)</strong> + </dt> + <dd> + Rehighlight the buffer if colorizer is active + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">buf</span> + number: Buffer number + </li> + <li><span class="parameter">options</span> + table: Buffer options + </li> + </ul> + + + + + +</dd> +</dl> + <h2 class="section-header "><a name="Tables"></a>Tables</h2> + + <dl class="function"> + <dt> + <a name = "HIGHLIGHT_MODE_NAMES"></a> + <strong>HIGHLIGHT_MODE_NAMES</strong> + </dt> + <dd> + Highlight mode which will be use to render the colour + + + <h3>Fields:</h3> + <ul> + <li><span class="parameter">background</span> + + + + </li> + <li><span class="parameter">foreground</span> + + + + </li> + <li><span class="parameter">virtualtext</span> + + + + </li> + </ul> + + + + + +</dd> +</dl> + <h2 class="section-header "><a name="Fields"></a>Fields</h2> + + <dl class="function"> + <dt> + <a name = "DEFAULT_NAMESPACE"></a> + <strong>DEFAULT_NAMESPACE</strong> + </dt> + <dd> + Default namespace used in <a href="../modules/colorizer.buffer_utils.html#highlight_buffer">highlight_buffer</a> and <a href="../modules/colorizer.html#attach_to_buffer">colorizer.attach_to_buffer</a>. + + + + + + <h3>See also:</h3> + <ul> + <li><a href="../modules/colorizer.buffer_utils.html#highlight_buffer">highlight_buffer</a></li> + <li><a href="../modules/colorizer.html#attach_to_buffer">colorizer.attach_to_buffer</a></li> + </ul> + + +</dd> +</dl> + + +</div> <!-- id="content" --> +</div> <!-- id="main" --> +<div id="about"> +<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> +<i style="float:right;">Last updated 2022-09-03 17:24:13 </i> +</div> <!-- id="about" --> +</div> <!-- id="container" --> +</body> +</html> diff --git a/doc/modules/colorizer.color_utils.html b/doc/modules/colorizer.color_utils.html new file mode 100644 index 0000000..613185c --- /dev/null +++ b/doc/modules/colorizer.color_utils.html @@ -0,0 +1,355 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> +<head> + <title>colorizer Docs</title> + <link rel="stylesheet" href="../ldoc.css" type="text/css" /> +</head> +<body> + +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + + +<div id="main"> + + +<!-- Menu --> + +<div id="navigation"> +<br/> +<h1>colorizer</h1> + +<ul> + <li><a href="../index.html">Index</a></li> +</ul> + +<h2>Contents</h2> +<ul> +<li><a href="#Functions">Functions</a></li> +</ul> + + +<h2>Modules</h2> +<ul class="nowrap"> + <li><a href="../modules/colorizer.html">colorizer</a></li> + <li><a href="../modules/colorizer.buffer_utils.html">buffer_utils</a></li> + <li><strong>color_utils</strong></li> + <li><a href="../modules/colorizer.matcher_utils.html">matcher_utils</a></li> + <li><a href="../modules/colorizer.trie.html">trie</a></li> + <li><a href="../modules/utils.html">utils</a></li> +</ul> + +</div> + +<div id="content"> + +<h1>Module <code>colorizer.color_utils</code></h1> +<p>Helper functions to parse different colour formats</p> +<p> + +</p> + + +<h2><a href="#Functions">Functions</a></h2> +<table class="function_list"> + <tr> + <td class="name" nowrap><a href="#color_is_bright">color_is_bright (r, g, b)</a></td> + <td class="summary">Determine whether to use black or white text.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#color_name_parser">color_name_parser (line, i)</a></td> + <td class="summary">Grab all the colour values from <code>vim.api.nvim_get_color_map</code> and create a lookup table.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#rgb_function_parser">rgb_function_parser (line, i)</a></td> + <td class="summary">Parse for rgb() css function and return rgb hex.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#rgba_function_parser">rgba_function_parser (line, i)</a></td> + <td class="summary">Parse for rgba() css function and return rgb hex.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#hsl_function_parser">hsl_function_parser (line, i)</a></td> + <td class="summary">Parse for hsl() css function and return rgb hex.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#hsla_function_parser">hsla_function_parser (line, i)</a></td> + <td class="summary">Parse for hsl() css function and return rgb hex.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#argb_hex_parser">argb_hex_parser (line, i)</a></td> + <td class="summary">parse for 0xaarrggbb and return rgb hex.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#rgba_hex_parser">rgba_hex_parser (line, i, opts)</a></td> + <td class="summary">parse for #rrggbbaa and return rgb hex.</td> + </tr> +</table> + +<br/> +<br/> + + + <h2 class="section-header "><a name="Functions"></a>Functions</h2> + + <dl class="function"> + <dt> + <a name = "color_is_bright"></a> + <strong>color_is_bright (r, g, b)</strong> + </dt> + <dd> + Determine whether to use black or white text. </p> + +<p> ref: https://stackoverflow.com/a/1855903/837964 + https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">r</span> + number: Red + </li> + <li><span class="parameter">g</span> + number: Green + </li> + <li><span class="parameter">b</span> + number: Blue + </li> + </ul> + + + + + +</dd> + <dt> + <a name = "color_name_parser"></a> + <strong>color_name_parser (line, i)</strong> + </dt> + <dd> + Grab all the colour values from <code>vim.api.nvim_get_color_map</code> and create a lookup table. + COLOR_MAP is used to store the colour values + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">line</span> + string: Line to parse + </li> + <li><span class="parameter">i</span> + number: Index of line from where to start parsing + </li> + </ul> + + + + + +</dd> + <dt> + <a name = "rgb_function_parser"></a> + <strong>rgb_function_parser (line, i)</strong> + </dt> + <dd> + Parse for rgb() css function and return rgb hex. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">line</span> + string: Line to parse + </li> + <li><span class="parameter">i</span> + number: Index of line from where to start parsing + </li> + </ul> + + <h3>Returns:</h3> + <ol> + <li> + number|nil: Index of line where the rgb function ended</li> + <li> + string|nil: rgb hex value</li> + </ol> + + + + +</dd> + <dt> + <a name = "rgba_function_parser"></a> + <strong>rgba_function_parser (line, i)</strong> + </dt> + <dd> + Parse for rgba() css function and return rgb hex. + Todo consider removing the regexes here + Todo this might not be the best approach to alpha channel. + Things like pumblend might be useful here. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">line</span> + string: Line to parse + </li> + <li><span class="parameter">i</span> + number: Index of line from where to start parsing + </li> + </ul> + + <h3>Returns:</h3> + <ol> + <li> + number|nil: Index of line where the rgba function ended</li> + <li> + string|nil: rgb hex value</li> + </ol> + + + + +</dd> + <dt> + <a name = "hsl_function_parser"></a> + <strong>hsl_function_parser (line, i)</strong> + </dt> + <dd> + Parse for hsl() css function and return rgb hex. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">line</span> + string: Line to parse + </li> + <li><span class="parameter">i</span> + number: Index of line from where to start parsing + </li> + </ul> + + <h3>Returns:</h3> + <ol> + <li> + number|nil: Index of line where the hsl function ended</li> + <li> + string|nil: rgb hex value</li> + </ol> + + + + +</dd> + <dt> + <a name = "hsla_function_parser"></a> + <strong>hsla_function_parser (line, i)</strong> + </dt> + <dd> + Parse for hsl() css function and return rgb hex. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">line</span> + string: Line to parse + </li> + <li><span class="parameter">i</span> + number: Index of line from where to start parsing + </li> + </ul> + + <h3>Returns:</h3> + <ol> + <li> + number|nil: Index of line where the hsla function ended</li> + <li> + string|nil: rgb hex value</li> + </ol> + + + + +</dd> + <dt> + <a name = "argb_hex_parser"></a> + <strong>argb_hex_parser (line, i)</strong> + </dt> + <dd> + parse for 0xaarrggbb and return rgb hex. + a format used in android apps + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">line</span> + string: line to parse + </li> + <li><span class="parameter">i</span> + number: index of line from where to start parsing + </li> + </ul> + + <h3>Returns:</h3> + <ol> + <li> + number|nil: index of line where the hex value ended</li> + <li> + string|nil: rgb hex value</li> + </ol> + + + + +</dd> + <dt> + <a name = "rgba_hex_parser"></a> + <strong>rgba_hex_parser (line, i, opts)</strong> + </dt> + <dd> + parse for #rrggbbaa and return rgb hex. + a format used in android apps + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">line</span> + string: line to parse + </li> + <li><span class="parameter">i</span> + number: index of line from where to start parsing + </li> + <li><span class="parameter">opts</span> + table: Containing minlen, maxlen, valid_lengths + </li> + </ul> + + <h3>Returns:</h3> + <ol> + <li> + number|nil: index of line where the hex value ended</li> + <li> + string|nil: rgb hex value</li> + </ol> + + + + +</dd> +</dl> + + +</div> <!-- id="content" --> +</div> <!-- id="main" --> +<div id="about"> +<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> +<i style="float:right;">Last updated 2022-09-03 17:24:13 </i> +</div> <!-- id="about" --> +</div> <!-- id="container" --> +</body> +</html> diff --git a/doc/modules/colorizer.html b/doc/modules/colorizer.html index e02d18a..3db15a7 100644 --- a/doc/modules/colorizer.html +++ b/doc/modules/colorizer.html @@ -3,7 +3,7 @@ <html> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <head> - <title>Reference</title> + <title>colorizer Docs</title> <link rel="stylesheet" href="../ldoc.css" type="text/css" /> </head> <body> @@ -24,7 +24,7 @@ <div id="navigation"> <br/> -<h1>ldoc</h1> +<h1>colorizer</h1> <ul> <li><a href="../index.html">Index</a></li> @@ -40,8 +40,11 @@ <h2>Modules</h2> <ul class="nowrap"> <li><strong>colorizer</strong></li> - <li><a href="../modules/nvim.html">nvim</a></li> - <li><a href="../modules/trie.html">trie</a></li> + <li><a href="../modules/colorizer.buffer_utils.html">buffer_utils</a></li> + <li><a href="../modules/colorizer.color_utils.html">color_utils</a></li> + <li><a href="../modules/colorizer.matcher_utils.html">matcher_utils</a></li> + <li><a href="../modules/colorizer.trie.html">trie</a></li> + <li><a href="../modules/utils.html">utils</a></li> </ul> </div> @@ -49,42 +52,114 @@ <div id="content"> <h1>Module <code>colorizer</code></h1> +<p>Requires Neovim >= 0.6.0 and <code>set termguicolors</code></p> <p>Highlights terminal CSI ANSI color codes.</p> -<p></p> + <h3>See also:</h3> + <ul> + <li><a href="../modules/colorizer.html#setup">colorizer.setup</a></li> + <li><a href="../modules/colorizer.html#attach_to_buffer">colorizer.attach_to_buffer</a></li> + <li><a href="../modules/colorizer.html#detach_from_buffer">colorizer.detach_from_buffer</a></li> + </ul> + <h3>Usage:</h3> + <ul> + <pre class="example"> Establish the autocmd to highlight all filetypes. + + `lua require 'colorizer'.setup()` + + Highlight using all css highlight modes in every filetype + + `lua require 'colorizer'.setup(user_default_options = { css = true; })` + +============================================================================== +USE WITH COMMANDS *colorizer-commands* + + *:ColorizerAttachToBuffer* + + Attach to the current buffer and start highlighting with the settings as + specified in setup (or the defaults). + + If the buffer was already attached(i.e. being highlighted), the + settings will be reloaded with the ones from setup. + This is useful for reloading settings for just one buffer. + + *:ColorizerDetachFromBuffer* + + Stop highlighting the current buffer (detach). + + *:ColorizerReloadAllBuffers* + + Reload all buffers that are being highlighted currently. + Shortcut for ColorizerAttachToBuffer on every buffer. + + *:ColorizerToggle* + Toggle highlighting of the current buffer. + +USE WITH LUA + + All options that can be passed to user_default_options in `setup` + can be passed here. Can be empty too. + `0` is the buffer number here + + Attach to current buffer <pre> + require("colorizer").attach_to_buffer(0, { + mode = "background", + css = false, + }) +</pre> + Detach from buffer <pre> + require("colorizer").detach_from_buffer(0, { + mode = "background", + css = false, + }) +</pre> +</pre> + </ul> + <h3>Info:</h3> + <ul> + <li><strong>Author</strong>: Ashkan Kiani <a href="mailto:from-nvim-colorizer.lua@kiani.io">from-nvim-colorizer.lua@kiani.io</a></li> + </ul> <h2><a href="#Functions">Functions</a></h2> <table class="function_list"> <tr> - <td class="name" nowrap><a href="#highlight_buffer">highlight_buffer (buf[, ns=DEFAULT_NAMESPACE], lines, line_start, options)</a></td> - <td class="summary">Highlight the buffer region.</td> + <td class="name" nowrap><a href="#highlight_buffer">highlight_buffer ()</a></td> + <td class="summary">Highlight the buffer region</td> </tr> <tr> - <td class="name" nowrap><a href="#attach_to_buffer">attach_to_buffer ([buf=0|nil[, options]])</a></td> - <td class="summary">Attach to a buffer and continuously highlight changes.</td> + <td class="name" nowrap><a href="#is_buffer_attached">is_buffer_attached (buf)</a></td> + <td class="summary">Check if attached to a buffer.</td> </tr> <tr> - <td class="name" nowrap><a href="#detach_from_buffer">detach_from_buffer ([buf=0|nil[, ns=DEFAULT_NAMESPACE]])</a></td> + <td class="name" nowrap><a href="#detach_from_buffer">detach_from_buffer (buf, ns)</a></td> <td class="summary">Stop highlighting the current buffer.</td> </tr> <tr> - <td class="name" nowrap><a href="#setup">setup ([filetypes={'*'}[, default_options]])</a></td> + <td class="name" nowrap><a href="#attach_to_buffer">attach_to_buffer (buf, options, typ)</a></td> + <td class="summary">Attach to a buffer and continuously highlight changes.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#setup">setup (config)</a></td> <td class="summary">Easy to use function if you want the full setup without fine grained control.</td> </tr> <tr> + <td class="name" nowrap><a href="#get_buffer_options">get_buffer_options (buf)</a></td> + <td class="summary">Return the currently active buffer options.</td> + </tr> + <tr> <td class="name" nowrap><a href="#reload_all_buffers">reload_all_buffers ()</a></td> <td class="summary">Reload all of the currently active highlighted buffers.</td> </tr> <tr> - <td class="name" nowrap><a href="#get_buffer_options">get_buffer_options ([buf=0|nil])</a></td> - <td class="summary">Return the currently active buffer options.</td> + <td class="name" nowrap><a href="#clear_highlight_cache">clear_highlight_cache ()</a></td> + <td class="summary">Clear the highlight cache and reload all buffers.</td> </tr> </table> <h2><a href="#Fields">Fields</a></h2> <table class="function_list"> <tr> <td class="name" nowrap><a href="#DEFAULT_NAMESPACE">DEFAULT_NAMESPACE</a></td> - <td class="summary">Default namespace used in `highlight_buffer` and `attach_to_buffer`.</td> + <td class="summary">Default namespace used in <a href="../modules/colorizer.buffer_utils.html#highlight_buffer">colorizer.buffer_utils.highlight_buffer</a> and <a href="../modules/colorizer.html#attach_to_buffer">attach_to_buffer</a>.</td> </tr> </table> @@ -97,97 +172,92 @@ <dl class="function"> <dt> <a name = "highlight_buffer"></a> - <strong>highlight_buffer (buf[, ns=DEFAULT_NAMESPACE], lines, line_start, options)</strong> + <strong>highlight_buffer ()</strong> </dt> <dd> - Highlight the buffer region. -Highlight starting from `line_start` (0-indexed) for each line described by `lines` in the -buffer `buf` and attach it to the namespace `ns`. + Highlight the buffer region + + + <h3>See also:</h3> + <ul> + <a href="../modules/colorizer.buffer_utils.html#highlight_buffer">colorizer.buffer_utils.highlight_buffer</a> + </ul> + + +</dd> + <dt> + <a name = "is_buffer_attached"></a> + <strong>is_buffer_attached (buf)</strong> + </dt> + <dd> + Check if attached to a buffer. + + <h3>Parameters:</h3> <ul> <li><span class="parameter">buf</span> - <span class="types"><span class="type">integer</span></span> - buffer id. - </li> - <li><span class="parameter">ns</span> - <span class="types"><span class="type">integer</span></span> - the namespace id. Create it with `vim.api.create_namespace` - (<em>default</em> DEFAULT_NAMESPACE) - </li> - <li><span class="parameter">lines</span> - <span class="types"><a class="type" href="https://www.lua.org/manual/5.3/manual.html#6.4">{string,...}</a></span> - the lines to highlight from the buffer. - </li> - <li><span class="parameter">line_start</span> - <span class="types"><span class="type">integer</span></span> - should be 0-indexed - </li> - <li><span class="parameter">options</span> - Configuration options as described in `setup` + number|nil: A value of 0 implies the current buffer. </li> </ul> + <h3>Returns:</h3> + <ol> + + number|nil: if attached to the buffer, false otherwise. + </ol> <h3>See also:</h3> <ul> - <a href="../modules/colorizer.html#setup">setup</a> + <a href="../modules/colorizer.html#highlight_buffer">highlight_buffer</a> </ul> </dd> <dt> - <a name = "attach_to_buffer"></a> - <strong>attach_to_buffer ([buf=0|nil[, options]])</strong> + <a name = "detach_from_buffer"></a> + <strong>detach_from_buffer (buf, ns)</strong> </dt> <dd> - Attach to a buffer and continuously highlight changes. + Stop highlighting the current buffer. <h3>Parameters:</h3> <ul> <li><span class="parameter">buf</span> - <span class="types"><span class="type">integer</span></span> - A value of 0 implies the current buffer. - (<em>default</em> 0|nil) + number|nil: buf A value of 0 or nil implies the current buffer. </li> - <li><span class="parameter">options</span> - Configuration options as described in `setup` - (<em>optional</em>) + <li><span class="parameter">ns</span> + number|nil: ns the namespace id, if not given DEFAULT_NAMESPACE is used </li> </ul> - <h3>See also:</h3> - <ul> - <a href="../modules/colorizer.html#setup">setup</a> - </ul> </dd> <dt> - <a name = "detach_from_buffer"></a> - <strong>detach_from_buffer ([buf=0|nil[, ns=DEFAULT_NAMESPACE]])</strong> + <a name = "attach_to_buffer"></a> + <strong>attach_to_buffer (buf, options, typ)</strong> </dt> <dd> - Stop highlighting the current buffer. + Attach to a buffer and continuously highlight changes. <h3>Parameters:</h3> <ul> <li><span class="parameter">buf</span> - <span class="types"><span class="type">integer</span></span> - A value of 0 or nil implies the current buffer. - (<em>default</em> 0|nil) + integer: A value of 0 implies the current buffer. </li> - <li><span class="parameter">ns</span> - <span class="types"><span class="type">integer</span></span> - the namespace id. - (<em>default</em> DEFAULT_NAMESPACE) + <li><span class="parameter">options</span> + table: Configuration options as described in <a href="../modules/colorizer.html#setup">setup</a> + </li> + <li><span class="parameter">typ</span> + string|nil: "buf" or "file" - The type of buffer option </li> </ul> @@ -198,34 +268,52 @@ buffer `buf` and attach it to the namespace `ns`. </dd> <dt> <a name = "setup"></a> - <strong>setup ([filetypes={'*'}[, default_options]])</strong> + <strong>setup (config)</strong> </dt> <dd> - Easy to use function if you want the full setup without fine grained control. - Setup an autocmd which enables colorizing for the filetypes and options specified. -<p> By default highlights all FileTypes. -<p> Example config: - ``` - { 'scss', 'html', css = { rgb_fn = true; }, javascript = { no_names = true } } - ``` -<p> You can combine an array and more specific options. - Possible options: - - `no_names`: Don't highlight names like Blue - - `rgb_fn`: Highlight `rgb(...)` functions. - - `mode`: Highlight mode. Valid options: `foreground`,`background` + +<p>Easy to use function if you want the full setup without fine grained control. +Setup an autocmd which enables colorizing for the filetypes and options specified.</p> + +<p>By default highlights all FileTypes.</p> + +<p>Example config:~</p> + +<pre> + { filetypes = { "css", "html" }, user_default_options = { names = true } } +</pre> + +<p>Setup with all the default options:~</p> + +<pre> + require("colorizer").setup { + filetypes = { "*" }, + user_default_options = { + RGB = true, -- #RGB hex codes + RRGGBB = true, -- #RRGGBB hex codes + names = true, -- "Name" codes like Blue or blue + RRGGBBAA = false, -- #RRGGBBAA hex codes + AARRGGBB = false, -- 0xAARRGGBB hex codes + rgb_fn = false, -- CSS rgb() and rgba() functions + hsl_fn = false, -- CSS hsl() and hsla() functions + css = false, -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, RRGGBB + css_fn = false, -- Enable all CSS *functions*: rgb_fn, hsl_fn + -- Available modes for <code>mode</code>: foreground, background, virtualtext + mode = "background", -- Set the display mode. + virtualtext = "■", + }, + -- all the sub-options of filetypes apply to buftypes + buftypes = {}, + } +</pre> + <h3>Parameters:</h3> <ul> - <li><span class="parameter">filetypes</span> - A table/array of filetypes to selectively enable and/or customize. By default, enables all filetypes. - (<em>default</em> {'*'}) - </li> - <li><span class="parameter">default_options</span> - <span class="types"><a class="type" href="https://www.lua.org/manual/5.3/manual.html#6.4">{[string]=string}</a></span> - Default options to apply for the filetypes enable. - (<em>optional</em>) + <li><span class="parameter">config</span> + table: Config containing above parameters. </li> </ul> @@ -234,11 +322,31 @@ buffer `buf` and attach it to the namespace `ns`. <h3>Usage:</h3> <ul> - <pre class="example"><span class="global">require</span><span class="string">'colorizer'</span>.setup()</pre> + <pre class="example"><span class="backtick"><code>require'colorizer'.setup()</code></span></pre> </ul> </dd> <dt> + <a name = "get_buffer_options"></a> + <strong>get_buffer_options (buf)</strong> + </dt> + <dd> + Return the currently active buffer options. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">buf</span> + number|nil: Buffer number + </li> + </ul> + + + + + +</dd> + <dt> <a name = "reload_all_buffers"></a> <strong>reload_all_buffers ()</strong> </dt> @@ -253,21 +361,13 @@ buffer `buf` and attach it to the namespace `ns`. </dd> <dt> - <a name = "get_buffer_options"></a> - <strong>get_buffer_options ([buf=0|nil])</strong> + <a name = "clear_highlight_cache"></a> + <strong>clear_highlight_cache ()</strong> </dt> <dd> - Return the currently active buffer options. + Clear the highlight cache and reload all buffers. - <h3>Parameters:</h3> - <ul> - <li><span class="parameter">buf</span> - <span class="types"><span class="type">integer</span></span> - A value of 0 or nil implies the current buffer. - (<em>default</em> 0|nil) - </li> - </ul> @@ -283,8 +383,7 @@ buffer `buf` and attach it to the namespace `ns`. <strong>DEFAULT_NAMESPACE</strong> </dt> <dd> - Default namespace used in `highlight_buffer` and `attach_to_buffer`. - The name is "terminal_highlight" + Default namespace used in <a href="../modules/colorizer.buffer_utils.html#highlight_buffer">colorizer.buffer_utils.highlight_buffer</a> and <a href="../modules/colorizer.html#attach_to_buffer">attach_to_buffer</a>. @@ -292,7 +391,7 @@ buffer `buf` and attach it to the namespace `ns`. <h3>See also:</h3> <ul> - <li><a href="../modules/colorizer.html#highlight_buffer">highlight_buffer</a></li> + <li><a href="../modules/colorizer.buffer_utils.html#highlight_buffer">colorizer.buffer_utils.highlight_buffer</a></li> <li><a href="../modules/colorizer.html#attach_to_buffer">attach_to_buffer</a></li> </ul> @@ -305,7 +404,7 @@ buffer `buf` and attach it to the namespace `ns`. </div> <!-- id="main" --> <div id="about"> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> -<i style="float:right;">Last updated 2019-10-18 09:40:19 </i> +<i style="float:right;">Last updated 2022-09-03 17:24:13 </i> </div> <!-- id="about" --> </div> <!-- id="container" --> </body> diff --git a/doc/modules/colorizer.matcher_utils.html b/doc/modules/colorizer.matcher_utils.html new file mode 100644 index 0000000..e709932 --- /dev/null +++ b/doc/modules/colorizer.matcher_utils.html @@ -0,0 +1,113 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> +<head> + <title>colorizer Docs</title> + <link rel="stylesheet" href="../ldoc.css" type="text/css" /> +</head> +<body> + +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + + +<div id="main"> + + +<!-- Menu --> + +<div id="navigation"> +<br/> +<h1>colorizer</h1> + +<ul> + <li><a href="../index.html">Index</a></li> +</ul> + +<h2>Contents</h2> +<ul> +<li><a href="#Functions">Functions</a></li> +</ul> + + +<h2>Modules</h2> +<ul class="nowrap"> + <li><a href="../modules/colorizer.html">colorizer</a></li> + <li><a href="../modules/colorizer.buffer_utils.html">buffer_utils</a></li> + <li><a href="../modules/colorizer.color_utils.html">color_utils</a></li> + <li><strong>matcher_utils</strong></li> + <li><a href="../modules/colorizer.trie.html">trie</a></li> + <li><a href="../modules/utils.html">utils</a></li> +</ul> + +</div> + +<div id="content"> + +<h1>Module <code>colorizer.matcher_utils</code></h1> +<p>Helper functions for colorizer to enable required parsers</p> +<p> + +</p> + + +<h2><a href="#Functions">Functions</a></h2> +<table class="function_list"> + <tr> + <td class="name" nowrap><a href="#make_matcher">make_matcher (options)</a></td> + <td class="summary">Parse the given options and return a function with enabled parsers.</td> + </tr> +</table> + +<br/> +<br/> + + + <h2 class="section-header "><a name="Functions"></a>Functions</h2> + + <dl class="function"> + <dt> + <a name = "make_matcher"></a> + <strong>make_matcher (options)</strong> + </dt> + <dd> + Parse the given options and return a function with enabled parsers. +if no parsers enabled then return false +Do not try make the function again if it is present in the cache + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">options</span> + table: options created in <a href="../modules/colorizer.html#setup">colorizer.setup</a> + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + function|boolean: function which will just parse the line for enabled parsers + </ol> + + + + +</dd> +</dl> + + +</div> <!-- id="content" --> +</div> <!-- id="main" --> +<div id="about"> +<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> +<i style="float:right;">Last updated 2022-09-03 17:24:13 </i> +</div> <!-- id="about" --> +</div> <!-- id="container" --> +</body> +</html> diff --git a/doc/modules/nvim.html b/doc/modules/colorizer.trie.html index 8009822..0261786 100644 --- a/doc/modules/nvim.html +++ b/doc/modules/colorizer.trie.html @@ -3,7 +3,7 @@ <html> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <head> - <title>Reference</title> + <title>colorizer Docs</title> <link rel="stylesheet" href="../ldoc.css" type="text/css" /> </head> <body> @@ -24,7 +24,7 @@ <div id="navigation"> <br/> -<h1>ldoc</h1> +<h1>colorizer</h1> <ul> <li><a href="../index.html">Index</a></li> @@ -35,17 +35,20 @@ <h2>Modules</h2> <ul class="nowrap"> <li><a href="../modules/colorizer.html">colorizer</a></li> - <li><strong>nvim</strong></li> - <li><a href="../modules/trie.html">trie</a></li> + <li><a href="../modules/colorizer.buffer_utils.html">buffer_utils</a></li> + <li><a href="../modules/colorizer.color_utils.html">color_utils</a></li> + <li><a href="../modules/colorizer.matcher_utils.html">matcher_utils</a></li> + <li><strong>trie</strong></li> + <li><a href="../modules/utils.html">utils</a></li> </ul> </div> <div id="content"> -<h1>Module <code>nvim</code></h1> -<p>Module of magic functions for nvim</p> -<p></p> +<h1>Module <code>colorizer.trie</code></h1> +<p>Trie implementation in luajit.</p> +<p>todo: write documentation</p> @@ -59,7 +62,7 @@ </div> <!-- id="main" --> <div id="about"> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> -<i style="float:right;">Last updated 2019-10-18 09:40:19 </i> +<i style="float:right;">Last updated 2022-09-03 17:24:13 </i> </div> <!-- id="about" --> </div> <!-- id="container" --> </body> diff --git a/doc/modules/colorizer.utils.html b/doc/modules/colorizer.utils.html new file mode 100644 index 0000000..9bca259 --- /dev/null +++ b/doc/modules/colorizer.utils.html @@ -0,0 +1,87 @@ +============================================================================== +UTILS *colorizer.utils* + +Helper utils + + +============================================================================== +LUA API *colorizer.utils* + +Available Functions: + + |colorizer.utils.byte_is_alphanumeric| - Obvious + + |colorizer.utils.byte_is_hex| - Obvious + + |colorizer.utils.merge| - Merge two tables + TODO Remove this and use vim.tbl_deep_extend + + |colorizer.utils.parse_hex| - Obvious + + |colorizer.utils.percent_or_hex| - Obvious + + + +byte_is_alphanumeric({byte}) |colorizer.utils.byte_is_alphanumeric| + Obvious + + + Parameters: + {byte} - number + + Returns: + boolean + + + +byte_is_hex({byte}) |colorizer.utils.byte_is_hex| + Obvious + + + Parameters: + {byte} - number + + Returns: + boolean + + + +merge({...}) |colorizer.utils.merge| + Merge two tables + TODO Remove this and use vim.tbl_deep_extend + + + Parameters: + {...} - + + Returns: + table + + + +parse_hex({byte}) |colorizer.utils.parse_hex| + Obvious + + + Parameters: + {byte} - number + + Returns: + number + + + +percent_or_hex({v}) |colorizer.utils.percent_or_hex| + Obvious + + + Parameters: + {v} - string + + Returns: + number|nil + + + + + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/doc/modules/trie.html b/doc/modules/trie.html index 5496cfd..e353630 100644 --- a/doc/modules/trie.html +++ b/doc/modules/trie.html @@ -3,7 +3,7 @@ <html> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <head> - <title>Reference</title> + <title>colorizer Docs</title> <link rel="stylesheet" href="../ldoc.css" type="text/css" /> </head> <body> @@ -24,7 +24,7 @@ <div id="navigation"> <br/> -<h1>ldoc</h1> +<h1>colorizer</h1> <ul> <li><a href="../index.html">Index</a></li> @@ -35,8 +35,11 @@ <h2>Modules</h2> <ul class="nowrap"> <li><a href="../modules/colorizer.html">colorizer</a></li> - <li><a href="../modules/nvim.html">nvim</a></li> + <li><a href="../modules/colorizer.buffer_utils.html">buffer_utils</a></li> + <li><a href="../modules/colorizer.color_utils.html">color_utils</a></li> + <li><a href="../modules/colorizer.matcher_utils.html">matcher_utils</a></li> <li><strong>trie</strong></li> + <li><a href="../modules/utils.html">utils</a></li> </ul> </div> @@ -44,9 +47,19 @@ <div id="content"> <h1>Module <code>trie</code></h1> -<p>Trie implementation in luajit - Copyright © 2019 Ashkan Kiani</p> -<p></p> +<p>Trie implementation in luajit.</p> +<p> Copyright © 2019 Ashkan Kiani + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version.</p> + +<p> This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.</p> @@ -60,7 +73,7 @@ </div> <!-- id="main" --> <div id="about"> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> -<i style="float:right;">Last updated 2019-10-18 09:40:19 </i> +<i style="float:right;">Last updated 2022-09-02 21:37:16 </i> </div> <!-- id="about" --> </div> <!-- id="container" --> </body> diff --git a/doc/modules/utils.html b/doc/modules/utils.html new file mode 100644 index 0000000..3e3ff4d --- /dev/null +++ b/doc/modules/utils.html @@ -0,0 +1,231 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> +<head> + <title>colorizer Docs</title> + <link rel="stylesheet" href="../ldoc.css" type="text/css" /> +</head> +<body> + +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + + +<div id="main"> + + +<!-- Menu --> + +<div id="navigation"> +<br/> +<h1>colorizer</h1> + +<ul> + <li><a href="../index.html">Index</a></li> +</ul> + +<h2>Contents</h2> +<ul> +<li><a href="#Functions">Functions</a></li> +</ul> + + +<h2>Modules</h2> +<ul class="nowrap"> + <li><a href="../modules/colorizer.html">colorizer</a></li> + <li><a href="../modules/colorizer.buffer_utils.html">buffer_utils</a></li> + <li><a href="../modules/colorizer.color_utils.html">color_utils</a></li> + <li><a href="../modules/colorizer.matcher_utils.html">matcher_utils</a></li> + <li><a href="../modules/colorizer.trie.html">trie</a></li> + <li><strong>utils</strong></li> +</ul> + +</div> + +<div id="content"> + +<h1>Module <code>utils</code></h1> +<p>Helper utils</p> +<p> + +</p> + + +<h2><a href="#Functions">Functions</a></h2> +<table class="function_list"> + <tr> + <td class="name" nowrap><a href="#byte_is_alphanumeric">byte_is_alphanumeric (byte)</a></td> + <td class="summary">Obvious.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#byte_is_hex">byte_is_hex (byte)</a></td> + <td class="summary">Obvious.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#merge">merge (...)</a></td> + <td class="summary">Merge two tables.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#parse_hex">parse_hex (byte)</a></td> + <td class="summary">Obvious.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#percent_or_hex">percent_or_hex (v)</a></td> + <td class="summary">Obvious.</td> + </tr> +</table> + +<br/> +<br/> + + + <h2 class="section-header "><a name="Functions"></a>Functions</h2> + + <dl class="function"> + <dt> + <a name = "byte_is_alphanumeric"></a> + <strong>byte_is_alphanumeric (byte)</strong> + </dt> + <dd> + Obvious. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">byte</span> + number + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + boolean + </ol> + + + + +</dd> + <dt> + <a name = "byte_is_hex"></a> + <strong>byte_is_hex (byte)</strong> + </dt> + <dd> + Obvious. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">byte</span> + number + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + boolean + </ol> + + + + +</dd> + <dt> + <a name = "merge"></a> + <strong>merge (...)</strong> + </dt> + <dd> + Merge two tables. </p> + +<p> todo: Remove this and use <code>vim.tbl_deep_extend</code> + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + + + + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + table + </ol> + + + + +</dd> + <dt> + <a name = "parse_hex"></a> + <strong>parse_hex (byte)</strong> + </dt> + <dd> + Obvious. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">byte</span> + number + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + number + </ol> + + + + +</dd> + <dt> + <a name = "percent_or_hex"></a> + <strong>percent_or_hex (v)</strong> + </dt> + <dd> + Obvious. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">v</span> + string + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + number|nil + </ol> + + + + +</dd> +</dl> + + +</div> <!-- id="content" --> +</div> <!-- id="main" --> +<div id="about"> +<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> +<i style="float:right;">Last updated 2022-09-03 17:24:13 </i> +</div> <!-- id="about" --> +</div> <!-- id="container" --> +</body> +</html> diff --git a/doc/tags b/doc/tags new file mode 100644 index 0000000..bb5229d --- /dev/null +++ b/doc/tags @@ -0,0 +1,37 @@ +:ColorizerAttachToBuffer colorizer.txt /*:ColorizerAttachToBuffer* +:ColorizerDetachFromBuffer colorizer.txt /*:ColorizerDetachFromBuffer* +:ColorizerReloadAllBuffers colorizer.txt /*:ColorizerReloadAllBuffers* +:ColorizerToggle colorizer.txt /*:ColorizerToggle* +colorizer colorizer.txt /*colorizer* +colorizer-commands colorizer.txt /*colorizer-commands* +colorizer-lua-api colorizer.txt /*colorizer-lua-api* +colorizer-usage colorizer.txt /*colorizer-usage* +colorizer.DEFAULT_NAMESPACE colorizer.txt /*colorizer.DEFAULT_NAMESPACE* +colorizer.attach_to_buffer colorizer.txt /*colorizer.attach_to_buffer* +colorizer.buffer_utils-introduction colorizer.txt /*colorizer.buffer_utils-introduction* +colorizer.buffer_utils-lua-api colorizer.txt /*colorizer.buffer_utils-lua-api* +colorizer.buffer_utils.DEFAULT_NAMESPACE colorizer.txt /*colorizer.buffer_utils.DEFAULT_NAMESPACE* +colorizer.buffer_utils.HIGHLIGHT_MODE_NAMES colorizer.txt /*colorizer.buffer_utils.HIGHLIGHT_MODE_NAMES* +colorizer.buffer_utils.highlight_buffer colorizer.txt /*colorizer.buffer_utils.highlight_buffer* +colorizer.buffer_utils.rehighlight_buffer colorizer.txt /*colorizer.buffer_utils.rehighlight_buffer* +colorizer.clear_highlight_cache colorizer.txt /*colorizer.clear_highlight_cache* +colorizer.color_utils-introduction colorizer.txt /*colorizer.color_utils-introduction* +colorizer.color_utils-lua-api colorizer.txt /*colorizer.color_utils-lua-api* +colorizer.color_utils.argb_hex_parser colorizer.txt /*colorizer.color_utils.argb_hex_parser* +colorizer.color_utils.color_is_bright colorizer.txt /*colorizer.color_utils.color_is_bright* +colorizer.color_utils.color_name_parser colorizer.txt /*colorizer.color_utils.color_name_parser* +colorizer.color_utils.hsl_function_parser colorizer.txt /*colorizer.color_utils.hsl_function_parser* +colorizer.color_utils.hsla_function_parser colorizer.txt /*colorizer.color_utils.hsla_function_parser* +colorizer.color_utils.rgb_function_parser colorizer.txt /*colorizer.color_utils.rgb_function_parser* +colorizer.color_utils.rgba_function_parser colorizer.txt /*colorizer.color_utils.rgba_function_parser* +colorizer.color_utils.rgba_hex_parser colorizer.txt /*colorizer.color_utils.rgba_hex_parser* +colorizer.detach_from_buffer colorizer.txt /*colorizer.detach_from_buffer* +colorizer.get_buffer_options colorizer.txt /*colorizer.get_buffer_options* +colorizer.highlight_buffer colorizer.txt /*colorizer.highlight_buffer* +colorizer.is_buffer_attached colorizer.txt /*colorizer.is_buffer_attached* +colorizer.matcher_utils-introduction colorizer.txt /*colorizer.matcher_utils-introduction* +colorizer.matcher_utils-lua-api colorizer.txt /*colorizer.matcher_utils-lua-api* +colorizer.matcher_utils.make_matcher colorizer.txt /*colorizer.matcher_utils.make_matcher* +colorizer.reload_all_buffers colorizer.txt /*colorizer.reload_all_buffers* +colorizer.setup colorizer.txt /*colorizer.setup* +colorizer.trie-introduction colorizer.txt /*colorizer.trie-introduction* diff --git a/lua/colorizer.lua b/lua/colorizer.lua index 0f80e83..87acad3 100644 --- a/lua/colorizer.lua +++ b/lua/colorizer.lua @@ -1,67 +1,98 @@ ---- Highlights terminal CSI ANSI color codes. +--- Requires Neovim >= 0.6.0 and `set termguicolors` +-- +--Highlights terminal CSI ANSI color codes. -- @module colorizer -local Trie = require "colorizer/trie" -local bit = require "bit" -local ffi = require "ffi" -local api = vim.api +-- @author Ashkan Kiani <from-nvim-colorizer.lua@kiani.io> +-- @usage Establish the autocmd to highlight all filetypes. +-- +-- `lua require 'colorizer'.setup()` +-- +-- Highlight using all css highlight modes in every filetype +-- +-- `lua require 'colorizer'.setup(user_default_options = { css = true; })` +-- +--============================================================================== +--USE WITH COMMANDS *colorizer-commands* +-- +-- *:ColorizerAttachToBuffer* +-- +-- Attach to the current buffer and start highlighting with the settings as +-- specified in setup (or the defaults). +-- +-- If the buffer was already attached(i.e. being highlighted), the +-- settings will be reloaded with the ones from setup. +-- This is useful for reloading settings for just one buffer. +-- +-- *:ColorizerDetachFromBuffer* +-- +-- Stop highlighting the current buffer (detach). +-- +-- *:ColorizerReloadAllBuffers* +-- +-- Reload all buffers that are being highlighted currently. +-- Shortcut for ColorizerAttachToBuffer on every buffer. +-- +-- *:ColorizerToggle* +-- Toggle highlighting of the current buffer. +-- +--USE WITH LUA +-- +-- All options that can be passed to user_default_options in `setup` +-- can be passed here. Can be empty too. +-- `0` is the buffer number here +-- +-- Attach to current buffer <pre> +-- require("colorizer").attach_to_buffer(0, { +-- mode = "background", +-- css = false, +-- }) +--</pre> +-- Detach from buffer <pre> +-- require("colorizer").detach_from_buffer(0, { +-- mode = "background", +-- css = false, +-- }) +--</pre> +-- @see colorizer.setup +-- @see colorizer.attach_to_buffer +-- @see colorizer.detach_from_buffer + +local buffer_utils = require "colorizer.buffer_utils" + +---Default namespace used in `colorizer.buffer_utils.highlight_buffer` and `attach_to_buffer`. +-- @see colorizer.buffer_utils.highlight_buffer +-- @see attach_to_buffer +local DEFAULT_NAMESPACE = buffer_utils.DEFAULT_NAMESPACE +local HIGHLIGHT_MODE_NAMES = buffer_utils.HIGHLIGHT_MODE_NAMES +local rehighlight_buffer = buffer_utils.rehighlight_buffer + +---Highlight the buffer region +---@function highlight_buffer +-- @see colorizer.buffer_utils.highlight_buffer +local highlight_buffer = buffer_utils.highlight_buffer + +local utils = require "colorizer.utils" +local merge = utils.merge + +local api = vim.api local augroup = api.nvim_create_augroup local autocmd = api.nvim_create_autocmd -local set_highlight = api.nvim_set_hl - -local buf_add_highlight = api.nvim_buf_add_highlight -local buf_clear_namespace = api.nvim_buf_clear_namespace -local get_current_buf = api.nvim_get_current_buf local buf_get_option = api.nvim_buf_get_option -local buf_get_lines = api.nvim_buf_get_lines -local buf_set_virtual_text = api.nvim_buf_set_virtual_text - -local band, lshift, bor, tohex = bit.band, bit.lshift, bit.bor, bit.tohex -local rshift = bit.rshift -local floor, min, max = math.floor, math.min, math.max - -local COLOR_MAP -local COLOR_TRIE -local COLOR_NAME_MINLEN, COLOR_NAME_MAXLEN -local COLOR_NAME_SETTINGS = { - lowercase = true, - strip_digits = false, -} +local clear_namespace = api.nvim_buf_clear_namespace +local current_buf = api.nvim_get_current_buf ---- Setup the COLOR_MAP and COLOR_TRIE -local function initialize_trie() - if not COLOR_TRIE then - COLOR_MAP = {} - COLOR_TRIE = Trie() - for k, v in pairs(api.nvim_get_color_map()) do - if not (COLOR_NAME_SETTINGS.strip_digits and k:match "%d+$") then - COLOR_NAME_MINLEN = COLOR_NAME_MINLEN and min(#k, COLOR_NAME_MINLEN) or #k - COLOR_NAME_MAXLEN = COLOR_NAME_MAXLEN and max(#k, COLOR_NAME_MAXLEN) or #k - local rgb_hex = tohex(v, 6) - COLOR_MAP[k] = rgb_hex - COLOR_TRIE:insert(k) - if COLOR_NAME_SETTINGS.lowercase then - local lowercase = k:lower() - COLOR_MAP[lowercase] = rgb_hex - COLOR_TRIE:insert(lowercase) - end - end - end - end -end - -local function merge(...) - local res = {} - for i = 1, select("#", ...) do - local o = select(i, ...) - for k, v in pairs(o) do - res[k] = v - end - end - return res -end +-- USER FACING FUNCTIONALITY -- +local AUGROUP_ID +local AUGROUP_NAME = "ColorizerSetup" +-- buffer specific options given in setup +local BUFFER_OPTIONS = {} +-- store boolean for buffer if it is initialzed +local BUFFER_INIT = {} +-- store buffer local autocmd(s) id +local BUFFER_AUTOCMDS = {} -local DEFAULT_OPTIONS = { +local USER_DEFAULT_OPTIONS = { RGB = true, -- #RGB hex codes RRGGBB = true, -- #RRGGBB hex codes names = true, -- "Name" codes like Blue or blue @@ -71,789 +102,282 @@ local DEFAULT_OPTIONS = { hsl_fn = false, -- CSS hsl() and hsla() functions css = false, -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, RRGGBB css_fn = false, -- Enable all CSS *functions*: rgb_fn, hsl_fn - -- Available modes: foreground, background, sign, virtualtext + -- Available modes: foreground, background, virtualtext mode = "background", -- Set the display mode. virtualtext = "■", } --- -- TODO use rgb as the return value from the matcher functions --- -- instead of the rgb_hex. Can be the highlight key as well --- -- when you shift it left 8 bits. Use the lower 8 bits for --- -- indicating which highlight mode to use. --- ffi.cdef [[ --- typedef struct { uint8_t r, g, b; } colorizer_rgb; --- ]] --- local rgb_t = ffi.typeof 'colorizer_rgb' - --- Create a lookup table where the bottom 4 bits are used to indicate the --- category and the top 4 bits are the hex value of the ASCII byte. -local BYTE_CATEGORY = ffi.new "uint8_t[256]" -local CATEGORY_DIGIT = lshift(1, 0) -local CATEGORY_ALPHA = lshift(1, 1) -local CATEGORY_HEX = lshift(1, 2) -local CATEGORY_ALPHANUM = bor(CATEGORY_ALPHA, CATEGORY_DIGIT) -do - local b = string.byte - for i = 0, 255 do - local v = 0 - -- Digit is bit 1 - if i >= b "0" and i <= b "9" then - v = bor(v, lshift(1, 0)) - v = bor(v, lshift(1, 2)) - v = bor(v, lshift(i - b "0", 4)) - end - local lowercase = bor(i, 0x20) - -- Alpha is bit 2 - if lowercase >= b "a" and lowercase <= b "z" then - v = bor(v, lshift(1, 1)) - if lowercase <= b "f" then - v = bor(v, lshift(1, 2)) - v = bor(v, lshift(lowercase - b "a" + 10, 4)) - end - end - BYTE_CATEGORY[i] = v - end -end - -local function byte_is_hex(byte) - return band(BYTE_CATEGORY[byte], CATEGORY_HEX) ~= 0 -end - -local function byte_is_alphanumeric(byte) - local category = BYTE_CATEGORY[byte] - return band(category, CATEGORY_ALPHANUM) ~= 0 -end - -local function parse_hex(b) - return rshift(BYTE_CATEGORY[b], 4) -end - -local function percent_or_hex(v) - if v:sub(-1, -1) == "%" then - return tonumber(v:sub(1, -2)) / 100 * 255 - end - local x = tonumber(v) - if x > 255 then - return - end - return x -end - ---- Determine whether to use black or white text --- Ref: https://stackoverflow.com/a/1855903/837964 --- https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color -local function color_is_bright(r, g, b) - -- Counting the perceptive luminance - human eye favors green color - local luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255 - if luminance > 0.5 then - return true -- Bright colors, black font - else - return false -- Dark colors, white font - end -end - --- https://gist.github.com/mjackson/5311256 -local function hue_to_rgb(p, q, t) - if t < 0 then - t = t + 1 - end - if t > 1 then - t = t - 1 - end - if t < 1 / 6 then - return p + (q - p) * 6 * t - end - if t < 1 / 2 then - return q - end - if t < 2 / 3 then - return p + (q - p) * (2 / 3 - t) * 6 - end - return p -end +local OPTIONS = { buf = {}, file = {} } +local SETUP_SETTINGS = { + exclusions = { buf = {}, file = {} }, + all = { file = false, buf = false }, + default_options = USER_DEFAULT_OPTIONS, +} -local function hsl_to_rgb(h, s, l) - if h > 1 or s > 1 or l > 1 then - return - end - if s == 0 then - local r = l * 255 - return r, r, r - end - local q - if l < 0.5 then - q = l * (1 + s) +--- Make new buffer Configuration +---@param buf number: buffer number +---@param typ string|nil: "buf" or "file" - The type of buffer option +---@return table +local function new_buffer_options(buf, typ) + local value + if typ == "buf" then + value = buf_get_option(buf, "buftype") else - q = l + s - l * s + value = buf_get_option(buf, "filetype") end - local p = 2 * l - q - return 255 * hue_to_rgb(p, q, h + 1 / 3), 255 * hue_to_rgb(p, q, h), 255 * hue_to_rgb(p, q, h - 1 / 3) + return OPTIONS.file[value] or SETUP_SETTINGS.default_options end -local function color_name_parser(line, i) - if i > 1 and byte_is_alphanumeric(line:byte(i - 1)) then - return +--- Check if attached to a buffer. +---@param buf number|nil: A value of 0 implies the current buffer. +---@return number|nil: if attached to the buffer, false otherwise. +---@see highlight_buffer +local function is_buffer_attached(buf) + if buf == 0 or buf == nil then + buf = current_buf() end - if #line < i + COLOR_NAME_MINLEN - 1 then + local au = api.nvim_get_autocmds { + group = AUGROUP_ID, + event = { "WinScrolled", "TextChanged", "TextChangedI", "TextChangedP" }, + buffer = buf, + } + if not BUFFER_OPTIONS[buf] or vim.tbl_isempty(au) then return end - local prefix = COLOR_TRIE:longest_prefix(line, i) - if prefix then - -- Check if there is a letter here so as to disallow matching here. - -- Take the Blue out of Blueberry - -- Line end or non-letter. - local next_byte_index = i + #prefix - if #line >= next_byte_index and byte_is_alphanumeric(line:byte(next_byte_index)) then - return - end - return #prefix, COLOR_MAP[prefix] - end -end -local b_hash = ("#"):byte() -local function rgb_hex_parser(line, i, minlen, maxlen) - if i > 1 and byte_is_alphanumeric(line:byte(i - 1)) then - return - end - if line:byte(i) ~= b_hash then - return - end - local j = i + 1 - if #line < j + minlen - 1 then - return - end - local n = j + maxlen - local alpha - local v = 0 - while j <= min(n, #line) do - local b = line:byte(j) - if not byte_is_hex(b) then - break - end - if j - i >= 7 then - alpha = parse_hex(b) + lshift(alpha or 0, 4) - else - v = parse_hex(b) + lshift(v, 4) - end - j = j + 1 - end - if #line >= j and byte_is_alphanumeric(line:byte(j)) then - return - end - local length = j - i - if length ~= 4 and length ~= 7 and length ~= 9 then - return - end - if alpha then - alpha = tonumber(alpha) / 255 - local r = floor(band(rshift(v, 16), 0xFF) * alpha) - local g = floor(band(rshift(v, 8), 0xFF) * alpha) - local b = floor(band(v, 0xFF) * alpha) - v = bor(lshift(r, 16), lshift(g, 8), b) - return 9, tohex(v, 6) - end - return length, line:sub(i + 1, i + length - 1) + return buf end -local RGB_FUNCTION_TRIE = Trie { "0x" } -local function rgb_0x_parser(line, i) - local prefix = RGB_FUNCTION_TRIE:longest_prefix(line:sub(i)) - if not prefix then - return - end - - local j = i + 2 - if #line < 10 then - return - end - local n = j + 8 - local alpha - local v = 0 - while j <= min(n, #line) do - local b = line:byte(j) - if not byte_is_hex(b) then - break - end - if j - i <= 3 then - alpha = parse_hex(b) + lshift(alpha or 0, 4) - else - v = parse_hex(b) + lshift(v, 4) - end - j = j + 1 - end - if #line >= j and byte_is_alphanumeric(line:byte(j)) then - return - end - local length = j - i - if length ~= 10 then +--- Stop highlighting the current buffer. +---@param buf number|nil: buf A value of 0 or nil implies the current buffer. +---@param ns number|nil: ns the namespace id, if not given DEFAULT_NAMESPACE is used +local function detach_from_buffer(buf, ns) + buf = is_buffer_attached(buf) + if not buf then return end - alpha = tonumber(alpha) / 255 - local r = floor(band(rshift(v, 16), 0xFF) * alpha) - local g = floor(band(rshift(v, 8), 0xFF) * alpha) - local b = floor(band(v, 0xFF) * alpha) - v = bor(lshift(r, 16), lshift(g, 8), b) - return length, tohex(v, 6) -end --- TODO consider removing the regexes here --- TODO this might not be the best approach to alpha channel. --- Things like pumblend might be useful here. -local css_fn = {} -do - local CSS_RGB_FN_MINIMUM_LENGTH = #"rgb(0,0,0)" - 1 - local CSS_RGBA_FN_MINIMUM_LENGTH = #"rgba(0,0,0,0)" - 1 - local CSS_HSL_FN_MINIMUM_LENGTH = #"hsl(0,0%,0%)" - 1 - local CSS_HSLA_FN_MINIMUM_LENGTH = #"hsla(0,0%,0%,0)" - 1 - function css_fn.rgb(line, i) - if #line < i + CSS_RGB_FN_MINIMUM_LENGTH then - return - end - local r, g, b, match_end = line:sub(i):match "^rgb%(%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*(%d+%%?)%s*%)()" - if not match_end then - r, g, b, match_end = line:sub(i):match "^rgb%(%s*(%d+%%?)%s+(%d+%%?)%s+(%d+%%?)%s*%)()" - if not match_end then - return - end - end - r = percent_or_hex(r) - if not r then - return - end - g = percent_or_hex(g) - if not g then - return - end - b = percent_or_hex(b) - if not b then - return - end - local rgb_hex = string.format("%02x%02x%02x", r, g, b) - return match_end - 1, rgb_hex - end - - function css_fn.hsl(line, i) - if #line < i + CSS_HSL_FN_MINIMUM_LENGTH then - return - end - local h, s, l, match_end = line:sub(i):match "^hsl%(%s*(%d+)%s*,%s*(%d+)%%%s*,%s*(%d+)%%%s*%)()" - if not match_end then - h, s, l, match_end = line:sub(i):match "^hsl%(%s*(%d+)%s+(%d+)%%%s+(%d+)%%%s*%)()" - if not match_end then - return - end - end - h = tonumber(h) - if h > 360 then - return - end - s = tonumber(s) - if s > 100 then - return - end - l = tonumber(l) - if l > 100 then - return - end - local r, g, b = hsl_to_rgb(h / 360, s / 100, l / 100) - if r == nil or g == nil or b == nil then - return - end - local rgb_hex = string.format("%02x%02x%02x", r, g, b) - return match_end - 1, rgb_hex - end - - function css_fn.rgba(line, i) - if #line < i + CSS_RGBA_FN_MINIMUM_LENGTH then - return - end - local r, g, b, a, match_end = - line:sub(i):match "^rgba%(%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*([.%d]+)%s*%)()" - if not match_end then - r, g, b, a, match_end = line:sub(i):match "^rgba%(%s*(%d+%%?)%s+(%d+%%?)%s+(%d+%%?)%s+([.%d]+)%s*%)()" - if not match_end then - return - end - end - a = tonumber(a) - if not a or a > 1 then - return - end - r = percent_or_hex(r) - if not r then - return - end - g = percent_or_hex(g) - if not g then - return - end - b = percent_or_hex(b) - if not b then - return - end - local rgb_hex = string.format("%02x%02x%02x", r * a, g * a, b * a) - return match_end - 1, rgb_hex - end - - function css_fn.hsla(line, i) - if #line < i + CSS_HSLA_FN_MINIMUM_LENGTH then - return - end - local h, s, l, a, match_end = line:sub(i):match "^hsla%(%s*(%d+)%s*,%s*(%d+)%%%s*,%s*(%d+)%%%s*,%s*([.%d]+)%s*%)()" - if not match_end then - h, s, l, a, match_end = line:sub(i):match "^hsla%(%s*(%d+)%s+(%d+)%%%s+(%d+)%%%s+([.%d]+)%s*%)()" - if not match_end then - return - end - end - a = tonumber(a) - if not a or a > 1 then - return - end - h = tonumber(h) - if h > 360 then - return - end - s = tonumber(s) - if s > 100 then - return - end - l = tonumber(l) - if l > 100 then - return - end - local r, g, b = hsl_to_rgb(h / 360, s / 100, l / 100) - if r == nil or g == nil or b == nil then - return - end - local rgb_hex = string.format("%02x%02x%02x", r * a, g * a, b * a) - return match_end - 1, rgb_hex - end -end - -local css_function_parser, rgb_function_parser, hsl_function_parser -do - local CSS_FUNCTION_TRIE = Trie { "rgb", "rgba", "hsl", "hsla" } - local RGB_FUNCTION_TRIE = Trie { "rgb", "rgba" } - local HSL_FUNCTION_TRIE = Trie { "hsl", "hsla" } - css_function_parser = function(line, i) - local prefix = CSS_FUNCTION_TRIE:longest_prefix(line:sub(i)) - if prefix then - return css_fn[prefix](line, i) - end - end - rgb_function_parser = function(line, i) - local prefix = RGB_FUNCTION_TRIE:longest_prefix(line:sub(i)) - if prefix then - return css_fn[prefix](line, i) - end - end - hsl_function_parser = function(line, i) - local prefix = HSL_FUNCTION_TRIE:longest_prefix(line:sub(i)) - if prefix then - return css_fn[prefix](line, i) - end - end -end - -local function compile_matcher(matchers) - local parse_fn = matchers[1] - for j = 2, #matchers do - local old_parse_fn = parse_fn - local new_parse_fn = matchers[j] - parse_fn = function(line, i) - local length, rgb_hex = new_parse_fn(line, i) - if length then - return length, rgb_hex - end - return old_parse_fn(line, i) - end - end - return parse_fn -end - ---- Default namespace used in `highlight_buffer` and `attach_to_buffer`. --- The name is "terminal_highlight" --- @see highlight_buffer --- @see attach_to_buffer -local DEFAULT_NAMESPACE = api.nvim_create_namespace "colorizer" -local HIGHLIGHT_NAME_PREFIX = "colorizer" -local HIGHLIGHT_MODE_NAMES = { - background = "mb", - foreground = "mf", - virtualtext = "mv", -} -local HIGHLIGHT_CACHE = {} - ---- Make a deterministic name for a highlight given these attributes -local function make_highlight_name(rgb, mode) - return table.concat({ HIGHLIGHT_NAME_PREFIX, HIGHLIGHT_MODE_NAMES[mode], rgb }, "_") -end - -local function create_highlight(rgb_hex, options) - local mode = options.mode or "background" - -- TODO validate rgb format? - rgb_hex = rgb_hex:lower() - local cache_key = table.concat({ HIGHLIGHT_MODE_NAMES[mode], rgb_hex }, "_") - local highlight_name = HIGHLIGHT_CACHE[cache_key] - -- Look up in our cache. - if not highlight_name then - if #rgb_hex == 3 then - rgb_hex = table.concat { - rgb_hex:sub(1, 1):rep(2), - rgb_hex:sub(2, 2):rep(2), - rgb_hex:sub(3, 3):rep(2), - } - end - -- Create the highlight - highlight_name = make_highlight_name(rgb_hex, mode) - if mode == "foreground" then - set_highlight(0, highlight_name, { fg = "#" .. rgb_hex }) - else - local rr, gg, bb = rgb_hex:sub(1, 2), rgb_hex:sub(3, 4), rgb_hex:sub(5, 6) - local r, g, b = tonumber(rr, 16), tonumber(gg, 16), tonumber(bb, 16) - local fg_color - if color_is_bright(r, g, b) then - fg_color = "Black" - else - fg_color = "White" - end - set_highlight(0, highlight_name, { fg = fg_color, bg = "#" .. rgb_hex }) - end - HIGHLIGHT_CACHE[cache_key] = highlight_name + clear_namespace(buf, ns or DEFAULT_NAMESPACE, 0, -1) + for _, id in ipairs(BUFFER_AUTOCMDS[buf] or {}) do + pcall(api.nvim_del_autocmd, id) end - return highlight_name + -- because now the buffer is not visible, so delete its information + BUFFER_OPTIONS[buf] = nil + BUFFER_AUTOCMDS[buf] = nil end -local MATCHER_CACHE = {} -local function make_matcher(options) - local enable_names = options.css or options.names - local enable_RGB = options.css or options.RGB - local enable_RRGGBB = options.css or options.RRGGBB - local enable_RRGGBBAA = options.css or options.RRGGBBAA - local enable_AARRGGBB = options.AARRGGBB - local enable_rgb = options.css or options.css_fns or options.rgb_fn - local enable_hsl = options.css or options.css_fns or options.hsl_fn - - local matcher_key = bor( - lshift(enable_names and 1 or 0, 0), - lshift(enable_RGB and 1 or 0, 1), - lshift(enable_RRGGBB and 1 or 0, 2), - lshift(enable_RRGGBBAA and 1 or 0, 3), - lshift(enable_rgb and 1 or 0, 4), - lshift(enable_hsl and 1 or 0, 5) - ) - - if matcher_key == 0 then - return - end - - local loop_parse_fn = MATCHER_CACHE[matcher_key] - if loop_parse_fn then - return loop_parse_fn - end - - local loop_matchers = {} - if enable_names then - table.insert(loop_matchers, color_name_parser) - end - if enable_AARRGGBB then - table.insert(loop_matchers, rgb_0x_parser) - end - do - local valid_lengths = { [3] = enable_RGB, [6] = enable_RRGGBB, [8] = enable_RRGGBBAA } - local minlen, maxlen - for k, v in pairs(valid_lengths) do - if v then - minlen = minlen and min(k, minlen) or k - maxlen = maxlen and max(k, maxlen) or k - end - end - if minlen then - table.insert(loop_matchers, function(line, i) - local length, rgb_hex = rgb_hex_parser(line, i, minlen, maxlen) - if length and valid_lengths[length - 1] then - return length, rgb_hex - end - end) - end - end - if enable_rgb and enable_hsl then - table.insert(loop_matchers, css_function_parser) - elseif enable_rgb then - table.insert(loop_matchers, rgb_function_parser) - elseif enable_hsl then - table.insert(loop_matchers, hsl_function_parser) +---Attach to a buffer and continuously highlight changes. +---@param buf integer: A value of 0 implies the current buffer. +---@param options table: Configuration options as described in `setup` +---@param typ string|nil: "buf" or "file" - The type of buffer option +local function attach_to_buffer(buf, options, typ) + if buf == 0 or buf == nil then + buf = current_buf() end - loop_parse_fn = compile_matcher(loop_matchers) - MATCHER_CACHE[matcher_key] = loop_parse_fn - return loop_parse_fn -end -local function add_highlight(options, buf, ns, data) - for linenr, hls in pairs(data) do - if vim.tbl_contains({ "foreground", "background" }, options.mode) then - for _, hl in ipairs(hls) do - buf_add_highlight(buf, ns, hl.name, linenr, hl.range[1], hl.range[2]) - end - elseif options.mode == "virtualtext" then - local chunks = {} - for _, hl in ipairs(hls) do - table.insert(chunks, { options.virtualtext, hl.name }) - end - buf_set_virtual_text(buf, ns, linenr, chunks, {}) - end + if not options then + options = new_buffer_options(buf, typ) end -end ---[[-- Highlight the buffer region. -Highlight starting from `line_start` (0-indexed) for each line described by `lines` in the -buffer `buf` and attach it to the namespace `ns`. - -@tparam integer buf buffer id. -@tparam[opt=DEFAULT_NAMESPACE] integer ns the namespace id. Create it with `vim.api.create_namespace` -@tparam {string,...} lines the lines to highlight from the buffer. -@tparam integer line_start should be 0-indexed -@param options Configuration options as described in `setup` -@see setup -]] -local function highlight_buffer(buf, ns, lines, line_start, options) - -- TODO do I have to put this here? - initialize_trie() - ns = ns or DEFAULT_NAMESPACE - local loop_parse_fn = make_matcher(options) - local data = {} - local mode = options.mode == "background" and { mode = "background" } or { mode = "foreground" } - for current_linenum, line in ipairs(lines) do - current_linenum = current_linenum - 1 + line_start - -- Upvalues are options and current_linenum - local i = 1 - while i < #line do - local length, rgb_hex = loop_parse_fn(line, i) - if length then - local name = create_highlight(rgb_hex, mode) - local d = data[current_linenum] or {} - table.insert(d, { name = name, range = { i - 1, i + length - 1 } }) - data[current_linenum] = d - i = i + length - else - i = i + 1 - end + if not HIGHLIGHT_MODE_NAMES[options.mode] then + if options.mode ~= nil then + local mode = options.mode + vim.defer_fn(function() + -- just notify the user once + vim.notify_once(string.format("Warning: Invalid mode given to colorizer setup [ %s ]", mode)) + end, 0) end + options.mode = "background" end - add_highlight(options, buf, ns, data) -end - ---- --- USER FACING FUNCTIONALITY ---- - -local SETUP_SETTINGS = { - exclusions = {}, - default_options = DEFAULT_OPTIONS, -} -local BUFFER_OPTIONS = {} -local FILETYPE_OPTIONS = {} - -local function rehighlight_buffer(buf, options) - local ns = DEFAULT_NAMESPACE - assert(options) - local a = vim.api.nvim_buf_call(buf, function() - return { - vim.fn.line "w0", - vim.fn.line "w$", - } - end) - local min_row = a[1] - 1 - local max_row = a[2] - buf_clear_namespace(buf, ns, min_row, max_row) - local lines = buf_get_lines(buf, min_row, max_row, false) - highlight_buffer(buf, ns, lines, min_row, options) -end - -local function new_buffer_options(buf) - local filetype = buf_get_option(buf, "filetype") - return FILETYPE_OPTIONS[filetype] or SETUP_SETTINGS.default_options -end - ---- Check if attached to a buffer. --- @tparam[opt=0|nil] integer buf A value of 0 implies the current buffer. --- @return true if attached to the buffer, false otherwise. -local function is_buffer_attached(buf) - if buf == 0 or buf == nil then - buf = get_current_buf() - end - return BUFFER_OPTIONS[buf] ~= nil -end ---- Stop highlighting the current buffer. --- @tparam[opt=0|nil] integer buf A value of 0 or nil implies the current buffer. --- @tparam[opt=DEFAULT_NAMESPACE] integer ns the namespace id. -local function detach_from_buffer(buf, ns) - if buf == 0 or buf == nil then - buf = get_current_buf() - end - buf_clear_namespace(buf, ns or DEFAULT_NAMESPACE, 0, -1) - for _, id in ipairs(BUFFER_OPTIONS["autocmds"][buf]) do - pcall(api.nvim_del_autocmd, id) - end - BUFFER_OPTIONS["autocmds"][buf] = nil - BUFFER_OPTIONS[buf] = nil -end - ---- Attach to a buffer and continuously highlight changes. --- @tparam[opt=0|nil] integer buf A value of 0 implies the current buffer. --- @param[opt] options Configuration options as described in `setup` --- @see setup -local function attach_to_buffer(buf, options) - if buf == 0 or buf == nil then - buf = get_current_buf() - end - local already_attached = BUFFER_OPTIONS[buf] ~= nil - if not options then - options = new_buffer_options(buf) - end BUFFER_OPTIONS[buf] = options rehighlight_buffer(buf, options) - if already_attached then + BUFFER_INIT[buf] = true + + if BUFFER_AUTOCMDS[buf] then return end local autocmds = {} - local au_group_id = augroup("ColorizerSetup", {}) + local au_group_id = AUGROUP_ID - autocmds[#autocmds + 1] = vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI", "TextChangedP" }, { + autocmds[#autocmds + 1] = autocmd({ "TextChanged", "TextChangedI", "TextChangedP" }, { + group = au_group_id, buffer = buf, callback = function() - -- only reload if it was not disabled using :HighlightColorsOff + -- only reload if it was not disabled using detach_from_buffer if BUFFER_OPTIONS[buf] then rehighlight_buffer(buf, options) end end, }) - autocmds[#autocmds + 1] = vim.api.nvim_create_autocmd({ "WinScrolled" }, { + autocmds[#autocmds + 1] = autocmd({ "WinScrolled" }, { group = au_group_id, buffer = buf, callback = function() - -- only reload if it was not disabled using :HighlightColorsOff + -- only reload if it was not disabled using detach_from_buffer if BUFFER_OPTIONS[buf] then rehighlight_buffer(buf, options) end end, }) - vim.api.nvim_create_autocmd({ "BufUnload", "BufDelete", "BufHidden" }, { + autocmd({ "BufUnload", "BufDelete" }, { group = au_group_id, buffer = buf, callback = function() if BUFFER_OPTIONS[buf] then detach_from_buffer(buf) end + BUFFER_INIT[buf] = nil end, }) - if not BUFFER_OPTIONS["autocmds"] then - BUFFER_OPTIONS["autocmds"] = {} - end - BUFFER_OPTIONS["autocmds"][buf] = autocmds + BUFFER_AUTOCMDS[buf] = autocmds end ---- Easy to use function if you want the full setup without fine grained control. --- Setup an autocmd which enables colorizing for the filetypes and options specified. --- --- By default highlights all FileTypes. --- --- Example config: --- ``` --- { 'scss', 'html', css = { rgb_fn = true; }, javascript = { no_names = true } } --- ``` +---Easy to use function if you want the full setup without fine grained control. +--Setup an autocmd which enables colorizing for the filetypes and options specified. -- --- You can combine an array and more specific options. --- Possible options: --- - `no_names`: Don't highlight names like Blue --- - `rgb_fn`: Highlight `rgb(...)` functions. --- - `mode`: Highlight mode. Valid options: `foreground`,`background` +--By default highlights all FileTypes. -- --- @param[opt={'*'}] filetypes A table/array of filetypes to selectively enable and/or customize. By default, enables all filetypes. --- @tparam[opt] {[string]=string} default_options Default options to apply for the filetypes enable. --- @usage require'colorizer'.setup() -local function setup(filetypes, user_default_options) +--Example config:~ +--<pre> +-- { filetypes = { "css", "html" }, user_default_options = { names = true } } +--</pre> +--Setup with all the default options:~ +--<pre> +-- require("colorizer").setup { +-- filetypes = { "*" }, +-- user_default_options = { +-- RGB = true, -- #RGB hex codes +-- RRGGBB = true, -- #RRGGBB hex codes +-- names = true, -- "Name" codes like Blue or blue +-- RRGGBBAA = false, -- #RRGGBBAA hex codes +-- AARRGGBB = false, -- 0xAARRGGBB hex codes +-- rgb_fn = false, -- CSS rgb() and rgba() functions +-- hsl_fn = false, -- CSS hsl() and hsla() functions +-- css = false, -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, RRGGBB +-- css_fn = false, -- Enable all CSS *functions*: rgb_fn, hsl_fn +-- -- Available modes for `mode`: foreground, background, virtualtext +-- mode = "background", -- Set the display mode. +-- virtualtext = "■", +-- }, +-- -- all the sub-options of filetypes apply to buftypes +-- buftypes = {}, +-- } +--</pre> +---@param config table: Config containing above parameters. +---@usage `require'colorizer'.setup()` +local function setup(config) if not vim.opt.termguicolors then - vim.notify("&termguicolors must be set", "ErrorMsg") + vim.schedule(function() + vim.notify("Colorizer: Error: &termguicolors must be set", "Error") + end) return end - FILETYPE_OPTIONS = {} + + local conf = vim.deepcopy(config) + + -- TODO: Remove conf[1] style + -- Mostly here to not break existing setups + local filetypes = conf.filetypes + local user_default_options = conf.user_default_options + local buftypes = conf.buftypes + -- if nothing given the enable for all filtypes + filetypes = filetypes or conf[1] or { "*" } + user_default_options = user_default_options or conf[2] or {} + buftypes = buftypes or conf[3] or nil + + OPTIONS = { buf = {}, file = {} } SETUP_SETTINGS = { - exclusions = {}, - default_options = merge(DEFAULT_OPTIONS, user_default_options or {}), + exclusions = { buf = {}, file = {} }, + all = { file = false, buf = false }, + default_options = merge(USER_DEFAULT_OPTIONS, user_default_options), } - -- Initialize this AFTER setting COLOR_NAME_SETTINGS - initialize_trie() - function COLORIZER_SETUP_HOOK() + + local function COLORIZER_SETUP_HOOK(typ) local filetype = vim.bo.filetype - if SETUP_SETTINGS.exclusions[filetype] then + local buftype = vim.bo.buftype + if SETUP_SETTINGS.exclusions.file[filetype] or SETUP_SETTINGS.exclusions.buf[buftype] then return end - local options = FILETYPE_OPTIONS[filetype] or SETUP_SETTINGS.default_options - attach_to_buffer(get_current_buf(), options) + + local fopts, bopts, options = OPTIONS[typ][filetype], OPTIONS[typ][buftype], nil + if typ == "file" then + options = fopts + -- if buffer and filetype options both are given, then prefer fileoptions + elseif fopts and bopts then + options = fopts + else + options = bopts + end + + if not options and not SETUP_SETTINGS.all[typ] then + return + end + + options = options or SETUP_SETTINGS.default_options + + -- this should ideally be triggered one time per buffer + -- but BufWinEnter also triggers for split formation + -- but we don't want that so add a check using local buffer variable + local buf = current_buf() + if not BUFFER_INIT[buf] then + attach_to_buffer(buf, options, typ) + end end - local au_group_id = augroup("ColorizerSetup", {}) - autocmd("FileType", { - group = au_group_id, - callback = function() - COLORIZER_SETUP_HOOK() - end, - }) + local au_group_id = augroup(AUGROUP_NAME, {}) + AUGROUP_ID = au_group_id - if not filetypes then - autocmd("FileType", { - group = au_group_id, - callback = function() - COLORIZER_SETUP_HOOK() - end, - }) - else - for k, v in pairs(filetypes) do - local filetype - local options = SETUP_SETTINGS.default_options - if type(k) == "string" then - filetype = k - if type(v) ~= "table" then - vim.notify("colorizer: Invalid option type for filetype " .. filetype, "ErrorMsg") + local aucmd = { buf = "BufWinEnter", file = "FileType" } + local function parse_opts(typ, tbl) + if type(tbl) == "table" then + local list = {} + + for k, v in pairs(tbl) do + local value + local options = SETUP_SETTINGS.default_options + if type(k) == "string" then + value = k + if type(v) ~= "table" then + vim.notify("colorizer: Invalid option type for " .. typ .. "type" .. value, "ErrorMsg") + else + options = merge(SETUP_SETTINGS.default_options, v) + end else - options = merge(SETUP_SETTINGS.default_options, v) - assert( - HIGHLIGHT_MODE_NAMES[options.mode or "background"], - "colorizer: Invalid mode: " .. tostring(options.mode) - ) + value = v + end + -- Exclude + if value:sub(1, 1) == "!" then + SETUP_SETTINGS.exclusions[typ][value:sub(2)] = true + else + OPTIONS[typ][value] = options + if value == "*" then + SETUP_SETTINGS.all[typ] = true + else + table.insert(list, value) + end end - else - filetype = v - end - -- Exclude - if filetype:sub(1, 1) == "!" then - SETUP_SETTINGS.exclusions[filetype:sub(2)] = true - else - FILETYPE_OPTIONS[filetype] = options - autocmd("BufWinEnter", { - group = au_group_id, - pattern = filetype, - callback = function() - -- this should ideally be triggered one time per buffer - -- but BufWinEnter also triggers for split formation - -- but we don't want that so add a check using local buffer variable - local buf = get_current_buf() - if BUFFER_OPTIONS[buf] then - COLORIZER_SETUP_HOOK() - end - end, - }) end + autocmd({ aucmd[typ] }, { + group = au_group_id, + pattern = typ == "file" and (SETUP_SETTINGS.all[typ] and "*" or list) or nil, + callback = function() + COLORIZER_SETUP_HOOK(typ) + end, + }) + elseif tbl then + vim.notify_once(string.format("colorizer: Invalid type for %stypes %s", typ, vim.inspect(tbl)), "ErrorMsg") end end + + parse_opts("file", filetypes) + parse_opts("buf", buftypes) + autocmd("ColorScheme", { group = au_group_id, callback = function() @@ -862,10 +386,19 @@ local function setup(filetypes, user_default_options) }) end +--- Return the currently active buffer options. +---@param buf number|nil: Buffer number +local function get_buffer_options(buf) + if buf == 0 or buf == nil then + buf = current_buf() + end + return merge({}, BUFFER_OPTIONS[buf]) +end + --- Reload all of the currently active highlighted buffers. local function reload_all_buffers() for buf, _ in pairs(BUFFER_OPTIONS) do - attach_to_buffer(buf) + attach_to_buffer(buf, get_buffer_options(buf)) end end @@ -875,15 +408,6 @@ local function clear_highlight_cache() vim.schedule(reload_all_buffers) end ---- Return the currently active buffer options. --- @tparam[opt=0|nil] integer buf A value of 0 or nil implies the current buffer. -local function get_buffer_options(buf) - if buf == 0 or buf == nil then - buf = get_current_buf() - end - return merge({}, BUFFER_OPTIONS[buf]) -end - --- @export return { DEFAULT_NAMESPACE = DEFAULT_NAMESPACE, diff --git a/lua/colorizer/buffer_utils.lua b/lua/colorizer/buffer_utils.lua new file mode 100644 index 0000000..0f8517f --- /dev/null +++ b/lua/colorizer/buffer_utils.lua @@ -0,0 +1,196 @@ +---Helper functions to highlight buffer smartly +--@module colorizer.buffer_utils +local api = vim.api +local buf_set_virtual_text = api.nvim_buf_set_extmark +local buf_get_lines = api.nvim_buf_get_lines +local create_namespace = api.nvim_create_namespace +local clear_namespace = api.nvim_buf_clear_namespace +local set_highlight = api.nvim_set_hl + +local color_utils = require "colorizer.color_utils" +local color_is_bright = color_utils.color_is_bright + +local matcher_utils = require "colorizer.matcher_utils" +local make_matcher = matcher_utils.make_matcher + +--- Default namespace used in `highlight_buffer` and `colorizer.attach_to_buffer`. +-- @see highlight_buffer +-- @see colorizer.attach_to_buffer +local DEFAULT_NAMESPACE = create_namespace "colorizer" +local HIGHLIGHT_NAME_PREFIX = "colorizer" +--- Highlight mode which will be use to render the colour +local HIGHLIGHT_MODE_NAMES = { + background = "mb", + foreground = "mf", + virtualtext = "mv", +} +local HIGHLIGHT_CACHE = {} + +--- Make a deterministic name for a highlight given these attributes +local function make_highlight_name(rgb, mode) + return table.concat({ HIGHLIGHT_NAME_PREFIX, HIGHLIGHT_MODE_NAMES[mode], rgb }, "_") +end + +local function create_highlight(rgb_hex, options) + local mode = options.mode or "background" + -- TODO validate rgb format? + rgb_hex = rgb_hex:lower() + local cache_key = table.concat({ HIGHLIGHT_MODE_NAMES[mode], rgb_hex }, "_") + local highlight_name = HIGHLIGHT_CACHE[cache_key] + + -- Look up in our cache. + if highlight_name then + return highlight_name + end + + -- convert from #fff to #ffffff + if #rgb_hex == 3 then + rgb_hex = table.concat { + rgb_hex:sub(1, 1):rep(2), + rgb_hex:sub(2, 2):rep(2), + rgb_hex:sub(3, 3):rep(2), + } + end + + -- Create the highlight + highlight_name = make_highlight_name(rgb_hex, mode) + if mode == "foreground" then + set_highlight(0, highlight_name, { fg = "#" .. rgb_hex }) + else + local rr, gg, bb = rgb_hex:sub(1, 2), rgb_hex:sub(3, 4), rgb_hex:sub(5, 6) + local r, g, b = tonumber(rr, 16), tonumber(gg, 16), tonumber(bb, 16) + local fg_color + if color_is_bright(r, g, b) then + fg_color = "Black" + else + fg_color = "White" + end + set_highlight(0, highlight_name, { fg = fg_color, bg = "#" .. rgb_hex }) + end + HIGHLIGHT_CACHE[cache_key] = highlight_name + return highlight_name +end + +local function add_highlight(options, buf, ns, data) + if vim.tbl_contains({ "foreground", "background" }, options.mode) then + for linenr, hls in pairs(data) do + for _, hl in ipairs(hls) do + api.nvim_buf_add_highlight(buf, ns, hl.name, linenr, hl.range[1], hl.range[2]) + end + end + elseif options.mode == "virtualtext" then + for linenr, hls in pairs(data) do + for _, hl in ipairs(hls) do + buf_set_virtual_text(0, ns, linenr, hl.range[2], { + end_col = hl.range[2], + virt_text = { { options.virtualtext or "■", hl.name } }, + }) + end + end + end +end + +--- Highlight the buffer region. +-- Highlight starting from `line_start` (0-indexed) for each line described by `lines` in the +-- buffer `buf` and attach it to the namespace `ns`. +---@param buf number: buffer id +---@param ns number: The namespace id. Default is DEFAULT_NAMESPACE. Create it with `vim.api.create_namespace` +---@param lines table: the lines to highlight from the buffer. +---@param line_start number: line_start should be 0-indexed +---@param options table: Configuration options as described in `setup` +local function highlight_buffer(buf, ns, lines, line_start, options) + if buf == 0 or buf == nil then + buf = api.nvim_get_current_buf() + end + + ns = ns or DEFAULT_NAMESPACE + local loop_parse_fn = make_matcher(options) + if not loop_parse_fn then + return false + end + + local data = {} + local mode = options.mode == "background" and { mode = "background" } or { mode = "foreground" } + for current_linenum, line in ipairs(lines) do + current_linenum = current_linenum - 1 + line_start + -- Upvalues are options and current_linenum + local i = 1 + while i < #line do + local length, rgb_hex = loop_parse_fn(line, i) + if length then + local name = create_highlight(rgb_hex, mode) + local d = data[current_linenum] or {} + table.insert(d, { name = name, range = { i - 1, i + length - 1 } }) + data[current_linenum] = d + i = i + length + else + i = i + 1 + end + end + end + add_highlight(options, buf, ns, data) +end + +local BUFFER_LINES = {} +--- Rehighlight the buffer if colorizer is active +---@param buf number: Buffer number +---@param options table: Buffer options +local function rehighlight_buffer(buf, options) + if buf == 0 or buf == nil then + buf = api.nvim_get_current_buf() + end + + local ns = DEFAULT_NAMESPACE + + if not BUFFER_LINES[buf] then + BUFFER_LINES[buf] = {} + end + + local a = api.nvim_buf_call(buf, function() + return { + vim.fn.line "w0", + vim.fn.line "w$", + } + end) + local min, max + local new_min, new_max = a[1] - 1, a[2] + local old_min, old_max = BUFFER_LINES[buf]["min"], BUFFER_LINES[buf]["max"] + + if old_min and old_max then + -- Triggered for TextChanged autocmds + -- TODO: Find a way to just apply highlight to changed text lines + if old_max == new_max then + min, max = new_min, new_max + -- Triggered for WinScrolled autocmd - Scroll Down + elseif old_max < new_max then + min = old_max + max = new_max + -- Triggered for WinScrolled autocmd - Scroll Up + elseif old_max > new_max then + min = new_min + max = new_min + (old_max - new_max) + end + -- just in case a long jump was made + if max - min > new_max - new_min then + min = new_min + max = new_max + end + end + + min = min or new_min + max = max or new_max + clear_namespace(buf, ns, min, max) + local lines = buf_get_lines(buf, min, max, false) + highlight_buffer(buf, ns, lines, min, options) + -- store current window position to be used later to incremently highlight + BUFFER_LINES[buf]["max"] = new_max + BUFFER_LINES[buf]["min"] = new_min +end + +--- @export +return { + DEFAULT_NAMESPACE = DEFAULT_NAMESPACE, + HIGHLIGHT_MODE_NAMES = HIGHLIGHT_MODE_NAMES, + rehighlight_buffer = rehighlight_buffer, + highlight_buffer = highlight_buffer, +} diff --git a/lua/colorizer/color_utils.lua b/lua/colorizer/color_utils.lua new file mode 100644 index 0000000..433cea7 --- /dev/null +++ b/lua/colorizer/color_utils.lua @@ -0,0 +1,393 @@ +---Helper functions to parse different colour formats +--@module colorizer.color_utils +local Trie = require "colorizer.trie" + +local utils = require "colorizer.utils" +local byte_is_alphanumeric = utils.byte_is_alphanumeric +local byte_is_hex = utils.byte_is_hex +local parse_hex = utils.parse_hex +local percent_or_hex = utils.percent_or_hex + +local bit = require "bit" +local floor, min, max = math.floor, math.min, math.max +local band, rshift, lshift, tohex = bit.band, bit.rshift, bit.lshift, bit.tohex + +local api = vim.api + +---Determine whether to use black or white text. +-- +-- ref: https://stackoverflow.com/a/1855903/837964 +-- https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color +---@param r number: Red +---@param g number: Green +---@param b number: Blue +local function color_is_bright(r, g, b) + -- counting the perceptive luminance - human eye favors green color + local luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255 + if luminance > 0.5 then + return true -- bright colors, black font + else + return false -- dark colors, white font + end +end + +---Convert hsl colour values to rgb. +-- Source: https://gist.github.com/mjackson/5311256 +---@param p number +---@param q number +---@param t number +---@return number +local function hue_to_rgb(p, q, t) + if t < 0 then + t = t + 1 + end + if t > 1 then + t = t - 1 + end + if t < 1 / 6 then + return p + (q - p) * 6 * t + end + if t < 1 / 2 then + return q + end + if t < 2 / 3 then + return p + (q - p) * (2 / 3 - t) * 6 + end + return p +end + +local COLOR_MAP +local COLOR_TRIE +local COLOR_NAME_MINLEN, COLOR_NAME_MAXLEN +local COLOR_NAME_SETTINGS = { lowercase = true, strip_digits = false } +--- Grab all the colour values from `vim.api.nvim_get_color_map` and create a lookup table. +-- COLOR_MAP is used to store the colour values +---@param line string: Line to parse +---@param i number: Index of line from where to start parsing +local function color_name_parser(line, i) + --- Setup the COLOR_MAP and COLOR_TRIE + if not COLOR_TRIE then + COLOR_MAP = {} + COLOR_TRIE = Trie() + for k, v in pairs(api.nvim_get_color_map()) do + if not (COLOR_NAME_SETTINGS.strip_digits and k:match "%d+$") then + COLOR_NAME_MINLEN = COLOR_NAME_MINLEN and min(#k, COLOR_NAME_MINLEN) or #k + COLOR_NAME_MAXLEN = COLOR_NAME_MAXLEN and max(#k, COLOR_NAME_MAXLEN) or #k + local rgb_hex = tohex(v, 6) + COLOR_MAP[k] = rgb_hex + COLOR_TRIE:insert(k) + if COLOR_NAME_SETTINGS.lowercase then + local lowercase = k:lower() + COLOR_MAP[lowercase] = rgb_hex + COLOR_TRIE:insert(lowercase) + end + end + end + end + + if #line < i + COLOR_NAME_MINLEN - 1 then + return + end + + if i > 1 and byte_is_alphanumeric(line:byte(i - 1)) then + return + end + + local prefix = COLOR_TRIE:longest_prefix(line, i) + if prefix then + -- Check if there is a letter here so as to disallow matching here. + -- Take the Blue out of Blueberry + -- Line end or non-letter. + local next_byte_index = i + #prefix + if #line >= next_byte_index and byte_is_alphanumeric(line:byte(next_byte_index)) then + return + end + return #prefix, COLOR_MAP[prefix] + end +end + +--- Converts an HSL color value to RGB. +---@param h number: Hue +---@param s number: Saturation +---@param l number: Lightness +---@return number|nil,number|nil,number|nil +local function hsl_to_rgb(h, s, l) + if h > 1 or s > 1 or l > 1 then + return + end + if s == 0 then + local r = l * 255 + return r, r, r + end + local q + if l < 0.5 then + q = l * (1 + s) + else + q = l + s - l * s + end + local p = 2 * l - q + return 255 * hue_to_rgb(p, q, h + 1 / 3), 255 * hue_to_rgb(p, q, h), 255 * hue_to_rgb(p, q, h - 1 / 3) +end + +local CSS_RGB_FN_MINIMUM_LENGTH = #"rgb(0,0,0)" - 1 +---Parse for rgb() css function and return rgb hex. +---@param line string: Line to parse +---@param i number: Index of line from where to start parsing +---@return number|nil: Index of line where the rgb function ended +---@return string|nil: rgb hex value +local function rgb_function_parser(line, i) + if #line < i + CSS_RGB_FN_MINIMUM_LENGTH then + return + end + local r, g, b, match_end = line:sub(i):match "^rgb%(%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*(%d+%%?)%s*%)()" + if not match_end then + r, g, b, match_end = line:sub(i):match "^rgb%(%s*(%d+%%?)%s+(%d+%%?)%s+(%d+%%?)%s*%)()" + if not match_end then + return + end + end + r = percent_or_hex(r) + if not r then + return + end + g = percent_or_hex(g) + if not g then + return + end + b = percent_or_hex(b) + if not b then + return + end + local rgb_hex = string.format("%02x%02x%02x", r, g, b) + return match_end - 1, rgb_hex +end + +local CSS_RGBA_FN_MINIMUM_LENGTH = #"rgba(0,0,0,0)" - 1 +---Parse for rgba() css function and return rgb hex. +-- Todo consider removing the regexes here +-- Todo this might not be the best approach to alpha channel. +-- Things like pumblend might be useful here. +---@param line string: Line to parse +---@param i number: Index of line from where to start parsing +---@return number|nil: Index of line where the rgba function ended +---@return string|nil: rgb hex value +local function rgba_function_parser(line, i) + if #line < i + CSS_RGBA_FN_MINIMUM_LENGTH then + return + end + local r, g, b, a, match_end = + line:sub(i):match "^rgba%(%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*(%d+%%?)%s*,%s*([.%d]+)%s*%)()" + if not match_end then + r, g, b, a, match_end = line:sub(i):match "^rgba%(%s*(%d+%%?)%s+(%d+%%?)%s+(%d+%%?)%s+([.%d]+)%s*%)()" + if not match_end then + return + end + end + a = tonumber(a) + if not a or a > 1 then + return + end + r = percent_or_hex(r) + if not r then + return + end + g = percent_or_hex(g) + if not g then + return + end + b = percent_or_hex(b) + if not b then + return + end + local rgb_hex = string.format("%02x%02x%02x", r * a, g * a, b * a) + return match_end - 1, rgb_hex +end + +local CSS_HSL_FN_MINIMUM_LENGTH = #"hsl(0,0%,0%)" - 1 +---Parse for hsl() css function and return rgb hex. +---@param line string: Line to parse +---@param i number: Index of line from where to start parsing +---@return number|nil: Index of line where the hsl function ended +---@return string|nil: rgb hex value +local function hsl_function_parser(line, i) + if #line < i + CSS_HSL_FN_MINIMUM_LENGTH then + return + end + local h, s, l, match_end = line:sub(i):match "^hsl%(%s*(%d+)%s*,%s*(%d+)%%%s*,%s*(%d+)%%%s*%)()" + if not match_end then + h, s, l, match_end = line:sub(i):match "^hsl%(%s*(%d+)%s+(%d+)%%%s+(%d+)%%%s*%)()" + if not match_end then + return + end + end + h = tonumber(h) + if h > 360 then + return + end + s = tonumber(s) + if s > 100 then + return + end + l = tonumber(l) + if l > 100 then + return + end + local r, g, b = hsl_to_rgb(h / 360, s / 100, l / 100) + if r == nil or g == nil or b == nil then + return + end + local rgb_hex = string.format("%02x%02x%02x", r, g, b) + return match_end - 1, rgb_hex +end + +local CSS_HSLA_FN_MINIMUM_LENGTH = #"hsla(0,0%,0%,0)" - 1 +---Parse for hsl() css function and return rgb hex. +---@param line string: Line to parse +---@param i number: Index of line from where to start parsing +---@return number|nil: Index of line where the hsla function ended +---@return string|nil: rgb hex value +local function hsla_function_parser(line, i) + if #line < i + CSS_HSLA_FN_MINIMUM_LENGTH then + return + end + local h, s, l, a, match_end = line:sub(i):match "^hsla%(%s*(%d+)%s*,%s*(%d+)%%%s*,%s*(%d+)%%%s*,%s*([.%d]+)%s*%)()" + if not match_end then + h, s, l, a, match_end = line:sub(i):match "^hsla%(%s*(%d+)%s+(%d+)%%%s+(%d+)%%%s+([.%d]+)%s*%)()" + if not match_end then + return + end + end + a = tonumber(a) + if not a or a > 1 then + return + end + h = tonumber(h) + if h > 360 then + return + end + s = tonumber(s) + if s > 100 then + return + end + l = tonumber(l) + if l > 100 then + return + end + local r, g, b = hsl_to_rgb(h / 360, s / 100, l / 100) + if r == nil or g == nil or b == nil then + return + end + local rgb_hex = string.format("%02x%02x%02x", r * a, g * a, b * a) + return match_end - 1, rgb_hex +end + +local ARGB_MINIMUM_LENGTH = #"0xAARRGGBB" - 1 +---parse for 0xaarrggbb and return rgb hex. +-- a format used in android apps +---@param line string: line to parse +---@param i number: index of line from where to start parsing +---@return number|nil: index of line where the hex value ended +---@return string|nil: rgb hex value +local function argb_hex_parser(line, i) + if #line < i + ARGB_MINIMUM_LENGTH then + return + end + + local j = i + 2 + + local n = j + 8 + local alpha + local v = 0 + while j <= min(n, #line) do + local b = line:byte(j) + if not byte_is_hex(b) then + break + end + if j - i <= 3 then + alpha = parse_hex(b) + lshift(alpha or 0, 4) + else + v = parse_hex(b) + lshift(v, 4) + end + j = j + 1 + end + if #line >= j and byte_is_alphanumeric(line:byte(j)) then + return + end + local length = j - i + if length ~= 10 then + return + end + alpha = tonumber(alpha) / 255 + local r = floor(band(rshift(v, 16), 0xFF) * alpha) + local g = floor(band(rshift(v, 8), 0xFF) * alpha) + local b = floor(band(v, 0xFF) * alpha) + local rgb_hex = string.format("%02x%02x%02x", r, g, b) + return length, rgb_hex +end + +---parse for #rrggbbaa and return rgb hex. +-- a format used in android apps +---@param line string: line to parse +---@param i number: index of line from where to start parsing +---@param opts table: Containing minlen, maxlen, valid_lengths +---@return number|nil: index of line where the hex value ended +---@return string|nil: rgb hex value +local function rgba_hex_parser(line, i, opts) + local minlen, maxlen, valid_lengths = opts.minlen, opts.maxlen, opts.valid_lengths + local j = i + 1 + if #line < j + minlen - 1 then + return + end + + if i > 1 and byte_is_alphanumeric(line:byte(i - 1)) then + return + end + + local n = j + maxlen + local alpha + local v = 0 + + while j <= min(n, #line) do + local b = line:byte(j) + if not byte_is_hex(b) then + break + end + if j - i >= 7 then + alpha = parse_hex(b) + lshift(alpha or 0, 4) + else + v = parse_hex(b) + lshift(v, 4) + end + j = j + 1 + end + + if #line >= j and byte_is_alphanumeric(line:byte(j)) then + return + end + + local length = j - i + if length ~= 4 and length ~= 7 and length ~= 9 then + return + end + + if alpha then + alpha = tonumber(alpha) / 255 + local r = floor(band(rshift(v, 16), 0xFF) * alpha) + local g = floor(band(rshift(v, 8), 0xFF) * alpha) + local b = floor(band(v, 0xFF) * alpha) + local rgb_hex = string.format("%02x%02x%02x", r, g, b) + return 9, rgb_hex + end + return (valid_lengths[length - 1] and length), line:sub(i + 1, i + length - 1) +end + +--- @export +return { + color_is_bright = color_is_bright, + color_name_parser = color_name_parser, + rgba_hex_parser = rgba_hex_parser, + argb_hex_parser = argb_hex_parser, + rgb_function_parser = rgb_function_parser, + rgba_function_parser = rgba_function_parser, + hsl_function_parser = hsl_function_parser, + hsla_function_parser = hsla_function_parser, +} diff --git a/lua/colorizer/matcher_utils.lua b/lua/colorizer/matcher_utils.lua new file mode 100644 index 0000000..84ddece --- /dev/null +++ b/lua/colorizer/matcher_utils.lua @@ -0,0 +1,132 @@ +---Helper functions for colorizer to enable required parsers +--@module colorizer.matcher_utils +local Trie = require "colorizer.trie" +local min, max = math.min, math.max + +local color_utils = require "colorizer.color_utils" +local color_name_parser = color_utils.color_name_parser +local rgba_hex_parser = color_utils.rgba_hex_parser + +local parser = {} +parser["_0x"] = color_utils.argb_hex_parser +parser["_rgb"] = color_utils.rgb_function_parser +parser["_rgba"] = color_utils.rgba_function_parser +parser["_hsl"] = color_utils.hsl_function_parser +parser["_hsla"] = color_utils.hsla_function_parser + +---Form a trie stuct with the given prefixes +---@param matchers table: List of prefixes, {"rgb", "hsl"} +---@param matchers_trie table: Table containing information regarding non-trie based parsers +---@return function: function which will just parse the line for enabled parsers +local function compile_matcher(matchers, matchers_trie) + local trie = Trie(matchers_trie) + + local b_hash = ("#"):byte() + local function parse_fn(line, i) + -- prefix # + if matchers.rgba_hex_parser then + if line:byte(i) == b_hash then + return rgba_hex_parser(line, i, matchers.rgba_hex_parser) + end + end + + -- Prefix 0x, rgba, rgb, hsla, hsl + local prefix = trie:longest_prefix(line, i) + if prefix then + local fn = "_" .. prefix + return parser[fn](line, i, matchers[fn]) + end + + -- Colour names + if matchers.color_name_parser then + return color_name_parser(line, i) + end + end + return parse_fn +end + +local MATCHER_CACHE = {} +---Parse the given options and return a function with enabled parsers. +--if no parsers enabled then return false +--Do not try make the function again if it is present in the cache +---@param options table: options created in `colorizer.setup` +---@return function|boolean: function which will just parse the line for enabled parsers +local function make_matcher(options) + local enable_names = options.css or options.names + local enable_RGB = options.css or options.RGB + local enable_RRGGBB = options.css or options.RRGGBB + local enable_RRGGBBAA = options.css or options.RRGGBBAA + local enable_AARRGGBB = options.AARRGGBB + local enable_rgb = options.css or options.css_fns or options.rgb_fn + local enable_hsl = options.css or options.css_fns or options.hsl_fn + + local matcher_key = 0 + + (enable_names and 1 or 0) + + (enable_RGB and 1 or 1) + + (enable_RRGGBB and 1 or 2) + + (enable_RRGGBBAA and 1 or 3) + + (enable_AARRGGBB and 1 or 4) + + (enable_rgb and 1 or 5) + + (enable_hsl and 1 or 6) + + if matcher_key == 0 then + return false + end + + local loop_parse_fn = MATCHER_CACHE[matcher_key] + if loop_parse_fn then + return loop_parse_fn + end + + local matchers = {} + local matchers_prefix = {} + matchers.max_prefix_length = 0 + + if enable_names then + matchers.color_name_parser = true + end + + local valid_lengths = { [3] = enable_RGB, [6] = enable_RRGGBB, [8] = enable_RRGGBBAA } + local minlen, maxlen + for k, v in pairs(valid_lengths) do + if v then + minlen = minlen and min(k, minlen) or k + maxlen = maxlen and max(k, maxlen) or k + end + end + + if minlen then + matchers.rgba_hex_parser = {} + matchers.rgba_hex_parser.valid_lengths = valid_lengths + matchers.rgba_hex_parser.maxlen = maxlen + matchers.rgba_hex_parser.minlen = minlen + end + + if enable_AARRGGBB then + table.insert(matchers_prefix, "0x") + end + + -- do not mess with the sequence, hsla before hsl, etc + if enable_rgb and enable_hsl then + table.insert(matchers_prefix, "hsla") + table.insert(matchers_prefix, "rgba") + table.insert(matchers_prefix, "rgb") + table.insert(matchers_prefix, "hsl") + elseif enable_rgb then + table.insert(matchers_prefix, "rgba") + table.insert(matchers_prefix, "rgb") + elseif enable_hsl then + table.insert(matchers_prefix, "hsla") + table.insert(matchers_prefix, "hsl") + end + + loop_parse_fn = compile_matcher(matchers, matchers_prefix) + MATCHER_CACHE[matcher_key] = loop_parse_fn + + return loop_parse_fn +end + +--- @export +return { + make_matcher = make_matcher, +} diff --git a/lua/colorizer/trie.lua b/lua/colorizer/trie.lua index 21ea543..82a0d2d 100644 --- a/lua/colorizer/trie.lua +++ b/lua/colorizer/trie.lua @@ -1,18 +1,21 @@ ---- Trie implementation in luajit --- Copyright © 2019 Ashkan Kiani +---Trie implementation in luajit. +--todo: write documentation +-- Copyright © 2019 Ashkan Kiani -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. - +-- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. - +-- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. + +--@module trie local ffi = require "ffi" ffi.cdef [[ @@ -47,11 +50,12 @@ local function trie_destroy(trie) ffi.C.free(trie) end -local INDEX_LOOKUP_TABLE = ffi.new "uint8_t[256]" +local total_char = 255 +local INDEX_LOOKUP_TABLE = ffi.new("uint8_t[?]", total_char) local CHAR_LOOKUP_TABLE = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" do local b = string.byte - for i = 0, 255 do + for i = 0, total_char do if i >= b "0" and i <= b "9" then INDEX_LOOKUP_TABLE[i] = i - b "0" elseif i >= b "A" and i <= b "Z" then @@ -59,7 +63,7 @@ do elseif i >= b "a" and i <= b "z" then INDEX_LOOKUP_TABLE[i] = i - b "a" + 10 + 26 else - INDEX_LOOKUP_TABLE[i] = 255 + INDEX_LOOKUP_TABLE[i] = total_char end end end @@ -71,7 +75,7 @@ local function trie_insert(trie, value) local node = trie for i = 1, #value do local index = INDEX_LOOKUP_TABLE[value:byte(i)] - if index == 255 then + if index == total_char then return false end if node.character[index] == nil then @@ -90,7 +94,7 @@ local function trie_search(trie, value, start) local node = trie for i = (start or 1), #value do local index = INDEX_LOOKUP_TABLE[value:byte(i)] - if index == 255 then + if index == total_char then return end local child = node.character[index] @@ -113,7 +117,7 @@ local function trie_longest_prefix(trie, value, start) for i = start, #value do local index = INDEX_LOOKUP_TABLE[value:byte(i)] -- local index = INDEX_LOOKUP_TABLE[bor(insensitive, value:byte(i))] - if index == 255 then + if index == total_char then break end local child = node.character[index] @@ -189,7 +193,7 @@ local function print_trie_table(s) end local lines = {} for _, child in ipairs(s.children) do - local child_lines = print_trie_table(child, thicc) + local child_lines = print_trie_table(child) for _, child_line in ipairs(child_lines) do table.insert(lines, child_line) end @@ -242,6 +246,7 @@ local Trie_mt = { search = trie_search, longest_prefix = trie_longest_prefix, extend = trie_extend, + destroy = trie_destroy, }, __tostring = trie_to_string, __gc = trie_destroy, diff --git a/lua/colorizer/utils.lua b/lua/colorizer/utils.lua new file mode 100644 index 0000000..0cb09ee --- /dev/null +++ b/lua/colorizer/utils.lua @@ -0,0 +1,106 @@ +---Helper utils +--@module utils +local bit, ffi = require "bit", require "ffi" +local band, bor, rshift, lshift = bit.band, bit.bor, bit.rshift, bit.lshift + +-- -- TODO use rgb as the return value from the matcher functions +-- -- instead of the rgb_hex. Can be the highlight key as well +-- -- when you shift it left 8 bits. Use the lower 8 bits for +-- -- indicating which highlight mode to use. +-- ffi.cdef [[ +-- typedef struct { uint8_t r, g, b; } colorizer_rgb; +-- ]] +-- local rgb_t = ffi.typeof 'colorizer_rgb' + +-- Create a lookup table where the bottom 4 bits are used to indicate the +-- category and the top 4 bits are the hex value of the ASCII byte. +local BYTE_CATEGORY = ffi.new "uint8_t[256]" +local CATEGORY_DIGIT = lshift(1, 0) +local CATEGORY_ALPHA = lshift(1, 1) +local CATEGORY_HEX = lshift(1, 2) +local CATEGORY_ALPHANUM = bor(CATEGORY_ALPHA, CATEGORY_DIGIT) + +-- do not run the loop multiple times +local b = string.byte +for i = 0, 255 do + local v = 0 + -- Digit is bit 1 + if i >= b "0" and i <= b "9" then + v = bor(v, lshift(1, 0)) + v = bor(v, lshift(1, 2)) + v = bor(v, lshift(i - b "0", 4)) + end + local lowercase = bor(i, 0x20) + -- Alpha is bit 2 + if lowercase >= b "a" and lowercase <= b "z" then + v = bor(v, lshift(1, 1)) + if lowercase <= b "f" then + v = bor(v, lshift(1, 2)) + v = bor(v, lshift(lowercase - b "a" + 10, 4)) + end + end + BYTE_CATEGORY[i] = v +end + +---Obvious. +---@param byte number +---@return boolean +local function byte_is_alphanumeric(byte) + local category = BYTE_CATEGORY[byte] + return band(category, CATEGORY_ALPHANUM) ~= 0 +end + +---Obvious. +---@param byte number +---@return boolean +local function byte_is_hex(byte) + return band(BYTE_CATEGORY[byte], CATEGORY_HEX) ~= 0 +end + +---Merge two tables. +-- +-- todo: Remove this and use `vim.tbl_deep_extend` +---@return table +local function merge(...) + local res = {} + for i = 1, select("#", ...) do + local o = select(i, ...) + if type(o) ~= "table" then + return {} + end + for k, v in pairs(o) do + res[k] = v + end + end + return res +end + +--- Obvious. +---@param byte number +---@return number +local function parse_hex(byte) + return rshift(BYTE_CATEGORY[byte], 4) +end + +--- Obvious. +---@param v string +---@return number|nil +local function percent_or_hex(v) + if v:sub(-1, -1) == "%" then + return tonumber(v:sub(1, -2)) / 100 * 255 + end + local x = tonumber(v) + if x > 255 then + return + end + return x +end + +--- @export +return { + byte_is_alphanumeric = byte_is_alphanumeric, + byte_is_hex = byte_is_hex, + merge = merge, + parse_hex = parse_hex, + percent_or_hex = percent_or_hex, +} diff --git a/plugin/colorizer.lua b/plugin/colorizer.lua index 1e7ea61..979a888 100644 --- a/plugin/colorizer.lua +++ b/plugin/colorizer.lua @@ -8,6 +8,7 @@ command("ColorizerAttachToBuffer", function() require("colorizer").attach_to_buffer(0) end, {}) +-- Stop highlighting the current buffer (detach). command("ColorizerDetachFromBuffer", function() require("colorizer").detach_from_buffer(0) end, {}) diff --git a/scripts/gen_docs.sh b/scripts/gen_docs.sh new file mode 100644 index 0000000..3363d42 --- /dev/null +++ b/scripts/gen_docs.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +create_vim_doc() ( + local project_name="${1:?}" + local target="${2:?}" + local template="${3:?}" + local cur_dir + cur_dir="$(pwd)" + + if [[ -d "${target}" ]]; then + cp "${template}" "${TMP_DIR}/ldoc.ltp" || return 1 + else + echo "No such template exists" + return 1 + fi + + if [[ -d "${target}" ]]; then + ldoc -p "${project_name}" -t "${project_name} Docs" -u "${target}" -l "${TMP_DIR}" -d "${TMP_DIR}" || cleanup + cd "${TMP_DIR}/modules" || exit 1 + cat "${project_name}".html "${project_name}"*.*.html >"${project_name}".txt || cleanup + elif [[ -f "${target}" ]]; then + ldoc -p "${project_name}" -t "${project_name} Docs" -u "${target}" -l "${TMP_DIR}" -d "${TMP_DIR}" || cleanup + cd "${TMP_DIR}" || exit 1 + cat index.html >"${project_name}".txt || cleanup + else + echo "Invalid target" + return 1 + fi + echo "vim:tw=80:ts=8:noet:ft=help:norl:" >>"${project_name}".txt + # format each line to be within 80 columns + # replace <pre> and </pre> with > and < respectively + # Sometimes running the command one time is not enough, reason unknown + nvim --headless +"set tw=80" \ + +'%norm gqq' \ + +'%norm gqq' \ + +'%s/<pre>/>/g' \ + +'%s/<\/pre>/</g' \ + "${project_name}".txt \ + +"wqa" || { + echo "Coundn't format with nvim, but help file be placed" + } + mkdir -p "${cur_dir}/doc" + cp "${project_name}".txt "${cur_dir}/doc/${project_name}.txt" || cleanup + echo + echo "${cur_dir}/doc/${project_name}.txt" created + + return 0 +) + +main() { + TMP_DIR="$(mktemp -d)" + + cleanup() { rm -rf "${TMP_DIR}" exit 0; } + + project_name="colorizer" + if command -v ldoc 1>/dev/null; then + # html docs + ldoc -f discount -p "${project_name}" -t "${project_name} Docs" -u lua "${@}" -s doc || cleanup + + # vim docs + create_vim_doc "${project_name}" lua doc/ldoc_vim.ltp || cleanup + else + echo "Error: Install ldoc first" + fi + + cleanup +} + +main "${@}" diff --git a/test/expectation.txt b/test/expectation.txt index da3deb6..0969608 100644 --- a/test/expectation.txt +++ b/test/expectation.txt @@ -1,28 +1,28 @@ -- vim:ft=lua -require("colorizer").attach_to_buffer(0, { css = true }) - +require("colorizer").detach_from_buffer(0) +require("colorizer").attach_to_buffer(0, { AARRGGBB = true, css = true, mode = "background" }) --[[ SUCCESS -#F0F -#FF00FF +0xFf32A14B 0xFf32A14B +#32a14b + +#F0F #FF00FF #FFF00F8F #F0F #FF00FF +#FF32A14B #FFF00F8F - #F0F - #FF00FF - #FFF00F8F - #F0F #F00 - #FF00FF #F00 - #FFF00F8F #F00 -Blue Gray LightBlue Gray100 White +#F0F #F00 +#FF00FF #F00 +#FFF00F8F #F00 + +blue gray lightblue gray100 white gold blue +Blue LightBlue Gray100 White White -#def -#deadbeef -rgba(200,30,0,0) -rgb(0,0,0) -rgb(10, 100 , 100) -hsl(300,50%,50%) -hsla(300,50%,50%,0.5) + +#def #deadbeef + +rgb(0,0,0) rgb(10, 100 , 100) +rgba(200,30,0,1) rgba(200,30,0,0.5) +hsl(300,50%,50%) hsla(300,50%,50%,0.5) hsla(300,50%,50%,1.0000000000000001) hsla(360,50%,50%,1.0000000000000001) -blue gray lightblue gray100 white gold blue ]] --[[ FAIL diff --git a/test/print-trie.lua b/test/print-trie.lua index 7575b5c..90017ad 100644 --- a/test/print-trie.lua +++ b/test/print-trie.lua @@ -1,14 +1,5 @@ --- TODO this is kinda shitty -local function dirname(str, sep) - sep = sep or "/" - return str:match("(.*" .. sep .. ")") -end - -local script_dir = dirname(arg[0]) -package.path = script_dir .. "/../lua/?.lua;" .. package.path - -local Trie = require "trie" -local nvim = require "nvim" +local Trie = require "colorizer.trie" +local color_map = vim.api.nvim_get_color_map local function print_color_trie() local tohex = bit.tohex @@ -20,7 +11,7 @@ local function print_color_trie() } local COLOR_MAP = {} local COLOR_TRIE = Trie() - for k, v in pairs(nvim.get_color_map()) do + for k, v in pairs(color_map()) do if not (COLOR_NAME_SETTINGS.strip_digits and k:match "%d+$") then COLOR_NAME_MINLEN = COLOR_NAME_MINLEN and min(#k, COLOR_NAME_MINLEN) or #k COLOR_NAME_MAXLEN = COLOR_NAME_MAXLEN and max(#k, COLOR_NAME_MAXLEN) or #k |