{"id":13411011,"url":"https://github.com/kevinhwang91/nvim-hlslens","last_synced_at":"2025-05-15T07:06:20.417Z","repository":{"id":41263286,"uuid":"313093499","full_name":"kevinhwang91/nvim-hlslens","owner":"kevinhwang91","description":"Hlsearch Lens for Neovim","archived":false,"fork":false,"pushed_at":"2025-04-26T05:35:21.000Z","size":190,"stargazers_count":824,"open_issues_count":7,"forks_count":13,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-26T06:32:58.760Z","etag":null,"topics":["lua","neovim","neovim-lua","neovim-plugin","nvim"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kevinhwang91.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-11-15T18:11:55.000Z","updated_at":"2025-04-26T05:35:25.000Z","dependencies_parsed_at":"2024-11-29T14:11:31.437Z","dependency_job_id":"a26239d8-086a-46a1-bd21-660ff1c3b6ea","html_url":"https://github.com/kevinhwang91/nvim-hlslens","commit_stats":{"total_commits":190,"total_committers":5,"mean_commits":38.0,"dds":0.02631578947368418,"last_synced_commit":"e22f8448b571b56d6140427e27e02406bcf4e059"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinhwang91%2Fnvim-hlslens","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinhwang91%2Fnvim-hlslens/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinhwang91%2Fnvim-hlslens/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinhwang91%2Fnvim-hlslens/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kevinhwang91","download_url":"https://codeload.github.com/kevinhwang91/nvim-hlslens/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292042,"owners_count":22046426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","neovim","neovim-lua","neovim-plugin","nvim"],"created_at":"2024-07-30T20:01:10.830Z","updated_at":"2025-05-15T07:06:15.407Z","avatar_url":"https://github.com/kevinhwang91.png","language":"Lua","funding_links":[],"categories":["Search","Lua"],"sub_categories":["Markdown and LaTeX","Assembly"],"readme":"# nvim-hlslens\n\nnvim-hlslens helps you better glance at matched information, seamlessly jump between matched\ninstances.\n\n\u003chttps://user-images.githubusercontent.com/17562139/144654751-0d439610-b913-4e72-b473-e49db3317fab.mp4\u003e\n\n## Table of contents\n\n- [Table of contents](#table-of-contents)\n- [Features](#features)\n- [Quickstart](#quickstart)\n  - [Requirements](#requirements)\n  - [Installation](#installation)\n  - [Minimal configuration](#minimal-configuration)\n  - [Usage](#usage)\n    - [Start hlslens](#start-hlslens)\n    - [Stop hlslens](#stop-hlslens)\n- [Documentation](#documentation)\n  - [Setup and description](#setup-and-description)\n  - [Highlight](#highlight)\n  - [Commands](#commands)\n  - [API](#api)\n- [Advanced configuration](#advanced-configuration)\n  - [Customize configuration](#customize-configuration)\n  - [Customize virtual text](#customize-virtual-text)\n  - [Integrate with other plugins](#integrate-with-other-plugins)\n    - [vim-asterisk](https://github.com/haya14busa/vim-asterisk)\n    - [nvim-ufo](https://github.com/kevinhwang91/nvim-ufo)\n    - [vim-visual-multi](https://github.com/mg979/vim-visual-multi)\n- [Feedback](#feedback)\n- [License](#license)\n\n## Features\n\n- Fully customizable style of virtual text\n- Clear highlighting and virtual text when cursor is out of range\n- Display search result dynamically while cursor is moving\n- Display search result for the current matched instance while searching\n- Display search result for some built-in commands that support incsearch (need Neovim 0.8.0)\n\n\u003e Need `vim.api.nvim_parse_cmd` to parse built-in commands if incsearch is enabled.\n\n## Quickstart\n\n### Requirements\n\n- [Neovim](https://github.com/neovim/neovim) 0.7.2 or later\n- [nvim-ufo](https://github.com/kevinhwang91/nvim-ufo) (optional)\n\n### Installation\n\nInstall nvim-hlslens with [Packer.nvim](https://github.com/wbthomason/packer.nvim):\n\n```lua\nuse {'kevinhwang91/nvim-hlslens'}\n```\n\n### Minimal configuration\n\n```lua\nrequire('hlslens').setup()\n\nlocal kopts = {noremap = true, silent = true}\n\nvim.api.nvim_set_keymap('n', 'n',\n    [[\u003cCmd\u003eexecute('normal! ' . v:count1 . 'n')\u003cCR\u003e\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]],\n    kopts)\nvim.api.nvim_set_keymap('n', 'N',\n    [[\u003cCmd\u003eexecute('normal! ' . v:count1 . 'N')\u003cCR\u003e\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]],\n    kopts)\nvim.api.nvim_set_keymap('n', '*', [[*\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], kopts)\nvim.api.nvim_set_keymap('n', '#', [[#\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], kopts)\nvim.api.nvim_set_keymap('n', 'g*', [[g*\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], kopts)\nvim.api.nvim_set_keymap('n', 'g#', [[g#\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], kopts)\n\nvim.api.nvim_set_keymap('n', '\u003cLeader\u003el', '\u003cCmd\u003enoh\u003cCR\u003e', kopts)\n```\n\n### Usage\n\nAfter using [Minimal configuration](#minimal-configuration):\n\nHlslens will add virtual text at the end of the line if the room is enough for virtual text,\notherwise, add a floating window to overlay the statusline to display lens.\n\nYou can glance at the result provided by lens while searching when `incsearch` is on. Hlslens also\nsupports `\u003cC-g\u003e` and `\u003cC-t\u003e` to move to the next and previous match.\n\n#### Start hlslens\n\n1. Press `/` or `?` to search text, `/s` and `/e` offsets are supported;\n2. Invoke API `require('hlslens').start()`;\n\n#### Stop hlslens\n\n1. Run ex command `nohlsearch`;\n2. Map key to `:nohlsearch`;\n3. Invoke API `require('hlslens').stop()`;\n\n## Documentation\n\n### Setup and description\n\n```lua\n{\n    auto_enable = {\n        description = [[Enable nvim-hlslens automatically]],\n        default = true\n    },\n    enable_incsearch = {\n        description = [[When `incsearch` option is on and enable_incsearch is true, add lens\n            for the current matched instance]],\n        default = true\n    },\n    calm_down = {\n        description = [[If calm_down is true, clear all lens and highlighting When the cursor is\n            out of the position range of the matched instance or any texts are changed]],\n        default = false,\n    },\n    nearest_only = {\n        description = [[Only add lens for the nearest matched instance and ignore others]],\n        default = false\n    },\n    nearest_float_when = {\n        description = [[When to open the floating window for the nearest lens.\n            'auto': floating window will be opened if room isn't enough for virtual text;\n            'always': always use floating window instead of virtual text;\n            'never': never use floating window for the nearest lens]],\n        default = 'auto',\n    },\n    float_shadow_blend = {\n        description = [[Winblend of the nearest floating window. `:h winbl` for more details]],\n        default = 50,\n    },\n    virt_priority = {\n        description = [[Priority of virtual text, set it lower to overlay others.\n        `:h nvim_buf_set_extmark` for more details]],\n        default = 100,\n    },\n    override_lens  = {\n        description = [[Hackable function for customizing the lens. If you like hacking, you\n            should search `override_lens` and inspect the corresponding source code.\n            There's no guarantee that this function will not be changed in the future. If it is\n            changed, it will be listed in the CHANGES file.\n            @param render table an inner module for hlslens, use `setVirt` to set virtual text\n            @param splist table (1,1)-indexed position\n            @param nearest boolean whether nearest lens\n            @param idx number nearest index in the plist\n            @param relIdx number relative index, negative means before current position,\n                                  positive means after\n        ]],\n        default = nil\n    },\n}\n```\n\n### Highlight\n\n```vim\nhi default link HlSearchNear CurSearch\nhi default link HlSearchLens WildMenu\nhi default link HlSearchLensNear CurSearch\n```\n\n1. HlSearchLensNear: highlight the nearest virtual text for the floating window\n2. HlSearchLens: highlight virtual text except for the nearest one\n3. HlSearchNear: highlight the nearest matched instance\n\n### Commands\n\n- `HlSearchLensToggle`: Toggle nvim-hlslens enable/disable\n- `HlSearchLensEnable`: Enable nvim-hlslens\n- `HlSearchLensDisable`: Disable nvim-hlslens\n\n### API\n\n[hlslens.lua](./lua/hlslens.lua)\n\n## Advanced configuration\n\n### Customize configuration\n\n```lua\nrequire('hlslens').setup({\n    calm_down = true,\n    nearest_only = true,\n    nearest_float_when = 'always'\n})\n\n-- run `:nohlsearch` and export results to quickfix\n-- if Neovim is 0.8.0 before, remap yourself.\nvim.keymap.set({'n', 'x'}, '\u003cLeader\u003eL', function()\n    vim.schedule(function()\n        if require('hlslens').exportLastSearchToQuickfix() then\n            vim.cmd('cw')\n        end\n    end)\n    return ':noh\u003cCR\u003e'\nend, {expr = true})\n```\n\n\u003chttps://user-images.githubusercontent.com/17562139/144655283-f5e3cf34-6c14-464d-9e09-6f57140c0dda.mp4\u003e\n\n### Customize virtual text\n\n```lua\nrequire('hlslens').setup({\n    override_lens = function(render, posList, nearest, idx, relIdx)\n        local sfw = vim.v.searchforward == 1\n        local indicator, text, chunks\n        local absRelIdx = math.abs(relIdx)\n        if absRelIdx \u003e 1 then\n            indicator = ('%d%s'):format(absRelIdx, sfw ~= (relIdx \u003e 1) and '▲' or '▼')\n        elseif absRelIdx == 1 then\n            indicator = sfw ~= (relIdx == 1) and '▲' or '▼'\n        else\n            indicator = ''\n        end\n\n        local lnum, col = unpack(posList[idx])\n        if nearest then\n            local cnt = #posList\n            if indicator ~= '' then\n                text = ('[%s %d/%d]'):format(indicator, idx, cnt)\n            else\n                text = ('[%d/%d]'):format(idx, cnt)\n            end\n            chunks = {{' '}, {text, 'HlSearchLensNear'}}\n        else\n            text = ('[%s %d]'):format(indicator, idx)\n            chunks = {{' '}, {text, 'HlSearchLens'}}\n        end\n        render.setVirt(0, lnum - 1, col - 1, chunks, nearest)\n    end\n})\n```\n\n\u003cp align=\"center\"\u003e\n    \u003cimg width=\"864px\" src=https://user-images.githubusercontent.com/17562139/115062493-fd26a100-9f1c-11eb-9305-20ef83d08e40.png\u003e\n\u003c/p\u003e\n\n### Integrate with other plugins\n\n#### [vim-asterisk](https://github.com/haya14busa/vim-asterisk)\n\n```lua\n-- packer\nuse 'haya14busa/vim-asterisk'\n\nvim.api.nvim_set_keymap('n', '*', [[\u003cPlug\u003e(asterisk-z*)\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], {})\nvim.api.nvim_set_keymap('n', '#', [[\u003cPlug\u003e(asterisk-z#)\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], {})\nvim.api.nvim_set_keymap('n', 'g*', [[\u003cPlug\u003e(asterisk-gz*)\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], {})\nvim.api.nvim_set_keymap('n', 'g#', [[\u003cPlug\u003e(asterisk-gz#)\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], {})\n\nvim.api.nvim_set_keymap('x', '*', [[\u003cPlug\u003e(asterisk-z*)\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], {})\nvim.api.nvim_set_keymap('x', '#', [[\u003cPlug\u003e(asterisk-z#)\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], {})\nvim.api.nvim_set_keymap('x', 'g*', [[\u003cPlug\u003e(asterisk-gz*)\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], {})\nvim.api.nvim_set_keymap('x', 'g#', [[\u003cPlug\u003e(asterisk-gz#)\u003cCmd\u003elua require('hlslens').start()\u003cCR\u003e]], {})\n```\n\n#### [nvim-ufo](https://github.com/kevinhwang91/nvim-ufo)\n\nThe lens has been adapted to the folds of nvim-ufo, still need remap `n` and `N` action if you want\nto peek at folded lines.\n\n```lua\n-- packer\nuse {'kevinhwang91/nvim-ufo', requires = 'kevinhwang91/promise-async'}\n\n-- if Neovim is 0.8.0 before, remap yourself.\nlocal function nN(char)\n    local ok, winid = hlslens.nNPeekWithUFO(char)\n    if ok and winid then\n        -- Safe to override buffer scope keymaps remapped by ufo,\n        -- ufo will restore previous buffer keymaps before closing preview window\n        -- Type \u003cCR\u003e will switch to preview window and fire `trace` action\n        vim.keymap.set('n', '\u003cCR\u003e', function()\n            return '\u003cTab\u003e\u003cCR\u003e'\n        end, {buffer = true, remap = true, expr = true})\n    end\nend\n\nvim.keymap.set({'n', 'x'}, 'n', function() nN('n') end)\nvim.keymap.set({'n', 'x'}, 'N', function() nN('N') end)\n```\n\n#### [vim-visual-multi](https://github.com/mg979/vim-visual-multi)\n\n\u003chttps://user-images.githubusercontent.com/17562139/144655345-9185df0e-e27e-4877-9ee6-d0acb811c907.mp4\u003e\n\n```lua\n-- packer\nuse 'mg979/vim-visual-multi'\n\nlocal hlslens = require('hlslens')\nif hlslens then\n    local overrideLens = function(render, posList, nearest, idx, relIdx)\n        local _ = relIdx\n        local lnum, col = unpack(posList[idx])\n\n        local text, chunks\n        if nearest then\n            text = ('[%d/%d]'):format(idx, #posList)\n            chunks = {{' ', 'Ignore'}, {text, 'VM_Extend'}}\n        else\n            text = ('[%d]'):format(idx)\n            chunks = {{' ', 'Ignore'}, {text, 'HlSearchLens'}}\n        end\n        render.setVirt(0, lnum - 1, col - 1, chunks, nearest)\n    end\n    local lensBak\n    local config = require('hlslens.config')\n    local gid = vim.api.nvim_create_augroup('VMlens', {})\n    vim.api.nvim_create_autocmd('User', {\n        pattern = {'visual_multi_start', 'visual_multi_exit'},\n        group = gid,\n        callback = function(ev)\n            if ev.match == 'visual_multi_start' then\n                lensBak = config.override_lens\n                config.override_lens = overrideLens\n            else\n                config.override_lens = lensBak\n            end\n            hlslens.start()\n        end\n    })\nend\n```\n\n## Feedback\n\n- If you get an issue or come up with an awesome idea, don't hesitate to open an issue in github.\n- If you think this plugin is useful or cool, consider rewarding it a star.\n\n## License\n\nThe project is licensed under a BSD-3-clause license. See [LICENSE](./LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevinhwang91%2Fnvim-hlslens","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkevinhwang91%2Fnvim-hlslens","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevinhwang91%2Fnvim-hlslens/lists"}