Regenerate nvim config
This commit is contained in:
1
config/neovim/store/lazy-plugins/nvim-navbuddy/.github/FUNDING.yml
vendored
Normal file
1
config/neovim/store/lazy-plugins/nvim-navbuddy/.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: SmiteshP
|
||||
1
config/neovim/store/lazy-plugins/nvim-navbuddy/.gitignore
vendored
Normal file
1
config/neovim/store/lazy-plugins/nvim-navbuddy/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
doc/tags
|
||||
201
config/neovim/store/lazy-plugins/nvim-navbuddy/LICENSE.md
Normal file
201
config/neovim/store/lazy-plugins/nvim-navbuddy/LICENSE.md
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
254
config/neovim/store/lazy-plugins/nvim-navbuddy/README.md
Normal file
254
config/neovim/store/lazy-plugins/nvim-navbuddy/README.md
Normal file
@ -0,0 +1,254 @@
|
||||
# 🗺️ nvim-navbuddy
|
||||
|
||||
A simple popup display that provides breadcrumbs like navigation feature but
|
||||
in keyboard centric manner inspired by ranger file manager.
|
||||
|
||||
https://user-images.githubusercontent.com/43147494/227758807-13a614ff-a09d-4be0-8f6b-ac22f814ce6f.mp4
|
||||
|
||||
## ⚡️ Requirements
|
||||
|
||||
* Neovim >= 0.8.0
|
||||
* [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig)
|
||||
* [nvim-navic](https://github.com/SmiteshP/nvim-navic)
|
||||
* [nui.nvim](https://github.com/MunifTanjim/nui.nvim)
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
Install the plugin with your preferred package manager:
|
||||
|
||||
### [packer](https://github.com/wbthomason/packer.nvim)
|
||||
|
||||
```lua
|
||||
use {
|
||||
"SmiteshP/nvim-navbuddy",
|
||||
requires = {
|
||||
"neovim/nvim-lspconfig",
|
||||
"SmiteshP/nvim-navic",
|
||||
"MunifTanjim/nui.nvim",
|
||||
"numToStr/Comment.nvim", -- Optional
|
||||
"nvim-telescope/telescope.nvim" -- Optional
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### [vim-plug](https://github.com/junegunn/vim-plug)
|
||||
|
||||
```vim
|
||||
Plug "neovim/nvim-lspconfig"
|
||||
Plug "SmiteshP/nvim-navic"
|
||||
Plug "MunifTanjim/nui.nvim"
|
||||
Plug "numToStr/Comment.nvim", " Optional
|
||||
Plug "nvim-telescope/telescope.nvim" " Optional
|
||||
Plug "SmiteshP/nvim-navbuddy"
|
||||
```
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
If you want to lazy load navbuddy you need to load it before your Lsp related Stuff.
|
||||
|
||||
For Example with [Lazy](https://github.com/folke/lazy.nvim) and [lspconfig](https://github.com/neovim/nvim-lspconfig)
|
||||
|
||||
```lua
|
||||
return {
|
||||
"neovim/nvim-lspconfig",
|
||||
dependencies = {
|
||||
{
|
||||
"SmiteshP/nvim-navbuddy",
|
||||
dependencies = {
|
||||
"SmiteshP/nvim-navic",
|
||||
"MunifTanjim/nui.nvim"
|
||||
},
|
||||
opts = { lsp = { auto_attach = true } }
|
||||
}
|
||||
},
|
||||
-- your lsp config or other stuff
|
||||
}
|
||||
```
|
||||
|
||||
## ⚙️ Setup
|
||||
|
||||
nvim-navbuddy needs to be attached to lsp servers of the buffer to work. You can pass the
|
||||
navbuddy's `attach` function as `on_attach` while setting up the lsp server. You can skip this
|
||||
step if you have enabled `auto_attach` option in setup function.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local navbuddy = require("nvim-navbuddy")
|
||||
|
||||
require("lspconfig").clangd.setup {
|
||||
on_attach = function(client, bufnr)
|
||||
navbuddy.attach(client, bufnr)
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
## 🪄 Customise
|
||||
|
||||
Use `setup` to override any of the default options
|
||||
|
||||
* `icons` : Indicate the type of symbol captured. Default icons assume you have nerd-fonts.
|
||||
* `node_markers` : Indicate whether a node is a leaf or branch node. Default icons assume you have nerd-fonts.
|
||||
* `window` : Set options related to window's "border", "size", "position".
|
||||
* `use_default_mappings`: If set to false, only mappings set by user are set. Else default mappings are used for keys that are not set by user.
|
||||
* `mappings` : Actions to be triggered for specified keybindings. For each keybinding it takes a table of format { callback = <function_to_be_called>, description = "string"}. The callback function takes the "display" object as an argument.
|
||||
* `lsp` :
|
||||
* `auto_attach` : Enable to have Navbuddy automatically attach to every LSP for current buffer. Its disabled by default.
|
||||
* `preference` : Table ranking lsp_servers. Lower the index, higher the priority of the server. If there are more than one server attached to a buffer, navbuddy will refer to this list to make a decision on which one to use. for example - In case a buffer is attached to clangd and ccls both and the preference list is `{ "clangd", "pyright" }`. Then clangd will be prefered.
|
||||
* `source_buffer` :
|
||||
* `follow_node` : Keep the current node in focus on the source buffer
|
||||
* `highlight` : Highlight the currently focused node
|
||||
* reorient: Reorient buffer after changing nodes. options are "smart", "top", "mid" or "none"
|
||||
|
||||
```lua
|
||||
local navbuddy = require("nvim-navbuddy")
|
||||
local actions = require("nvim-navbuddy.actions")
|
||||
|
||||
navbuddy.setup {
|
||||
window = {
|
||||
border = "single", -- "rounded", "double", "solid", "none"
|
||||
-- or an array with eight chars building up the border in a clockwise fashion
|
||||
-- starting with the top-left corner. eg: { "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" }.
|
||||
size = "60%", -- Or table format example: { height = "40%", width = "100%"}
|
||||
position = "50%", -- Or table format example: { row = "100%", col = "0%"}
|
||||
scrolloff = nil, -- scrolloff value within navbuddy window
|
||||
sections = {
|
||||
left = {
|
||||
size = "20%",
|
||||
border = nil, -- You can set border style for each section individually as well.
|
||||
},
|
||||
mid = {
|
||||
size = "40%",
|
||||
border = nil,
|
||||
},
|
||||
right = {
|
||||
-- No size option for right most section. It fills to
|
||||
-- remaining area.
|
||||
border = nil,
|
||||
preview = "leaf", -- Right section can show previews too.
|
||||
-- Options: "leaf", "always" or "never"
|
||||
}
|
||||
},
|
||||
},
|
||||
node_markers = {
|
||||
enabled = true,
|
||||
icons = {
|
||||
leaf = " ",
|
||||
leaf_selected = " → ",
|
||||
branch = " ",
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
File = " ",
|
||||
Module = " ",
|
||||
Namespace = " ",
|
||||
Package = " ",
|
||||
Class = " ",
|
||||
Method = " ",
|
||||
Property = " ",
|
||||
Field = " ",
|
||||
Constructor = " ",
|
||||
Enum = "",
|
||||
Interface = "",
|
||||
Function = " ",
|
||||
Variable = " ",
|
||||
Constant = " ",
|
||||
String = " ",
|
||||
Number = " ",
|
||||
Boolean = "◩ ",
|
||||
Array = " ",
|
||||
Object = " ",
|
||||
Key = " ",
|
||||
Null = " ",
|
||||
EnumMember = " ",
|
||||
Struct = " ",
|
||||
Event = " ",
|
||||
Operator = " ",
|
||||
TypeParameter = " ",
|
||||
},
|
||||
use_default_mappings = true, -- If set to false, only mappings set
|
||||
-- by user are set. Else default
|
||||
-- mappings are used for keys
|
||||
-- that are not set by user
|
||||
mappings = {
|
||||
["<esc>"] = actions.close(), -- Close and cursor to original location
|
||||
["q"] = actions.close(),
|
||||
|
||||
["j"] = actions.next_sibling(), -- down
|
||||
["k"] = actions.previous_sibling(), -- up
|
||||
|
||||
["h"] = actions.parent(), -- Move to left panel
|
||||
["l"] = actions.children(), -- Move to right panel
|
||||
["0"] = actions.root(), -- Move to first panel
|
||||
|
||||
["v"] = actions.visual_name(), -- Visual selection of name
|
||||
["V"] = actions.visual_scope(), -- Visual selection of scope
|
||||
|
||||
["y"] = actions.yank_name(), -- Yank the name to system clipboard "+
|
||||
["Y"] = actions.yank_scope(), -- Yank the scope to system clipboard "+
|
||||
|
||||
["i"] = actions.insert_name(), -- Insert at start of name
|
||||
["I"] = actions.insert_scope(), -- Insert at start of scope
|
||||
|
||||
["a"] = actions.append_name(), -- Insert at end of name
|
||||
["A"] = actions.append_scope(), -- Insert at end of scope
|
||||
|
||||
["r"] = actions.rename(), -- Rename currently focused symbol
|
||||
|
||||
["d"] = actions.delete(), -- Delete scope
|
||||
|
||||
["f"] = actions.fold_create(), -- Create fold of current scope
|
||||
["F"] = actions.fold_delete(), -- Delete fold of current scope
|
||||
|
||||
["c"] = actions.comment(), -- Comment out current scope
|
||||
|
||||
["<enter>"] = actions.select(), -- Goto selected symbol
|
||||
["o"] = actions.select(),
|
||||
|
||||
["J"] = actions.move_down(), -- Move focused node down
|
||||
["K"] = actions.move_up(), -- Move focused node up
|
||||
|
||||
["s"] = actions.toggle_preview(), -- Show preview of current node
|
||||
|
||||
["<C-v>"] = actions.vsplit(), -- Open selected node in a vertical split
|
||||
["<C-s>"] = actions.hsplit(), -- Open selected node in a horizontal split
|
||||
|
||||
["t"] = actions.telescope({ -- Fuzzy finder at current level.
|
||||
layout_config = { -- All options that can be
|
||||
height = 0.60, -- passed to telescope.nvim's
|
||||
width = 0.60, -- default can be passed here.
|
||||
prompt_position = "top",
|
||||
preview_width = 0.50
|
||||
},
|
||||
layout_strategy = "horizontal"
|
||||
}),
|
||||
|
||||
["g?"] = actions.help(), -- Open mappings help window
|
||||
},
|
||||
lsp = {
|
||||
auto_attach = false, -- If set to true, you don't need to manually use attach function
|
||||
preference = nil, -- list of lsp server names in order of preference
|
||||
},
|
||||
source_buffer = {
|
||||
follow_node = true, -- Keep the current node in focus on the source buffer
|
||||
highlight = true, -- Highlight the currently focused node
|
||||
reorient = "smart", -- "smart", "top", "mid" or "none"
|
||||
scrolloff = nil -- scrolloff value when navbuddy is open
|
||||
},
|
||||
custom_hl_group = nil, -- "Visual" or any other hl group to use instead of inverted colors
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 Usage
|
||||
|
||||
`Navbuddy` command can be used to open navbuddy.
|
||||
|
||||
```
|
||||
:Navbuddy
|
||||
```
|
||||
|
||||
And alternatively lua function `open` can also be used to open navbuddy.
|
||||
|
||||
```
|
||||
:lua require("nvim-navbuddy").open()
|
||||
```
|
||||
|
||||
377
config/neovim/store/lazy-plugins/nvim-navbuddy/doc/navbuddy.txt
Normal file
377
config/neovim/store/lazy-plugins/nvim-navbuddy/doc/navbuddy.txt
Normal file
@ -0,0 +1,377 @@
|
||||
*nvim-navbuddy* *navbuddy*
|
||||
|
||||
A simple popup display that provides breadcrumbs like navigation feature but
|
||||
in keyboard centric manner inspired by ranger file manager.
|
||||
|
||||
Requires :
|
||||
- nvim-lspconfig: `https://github.com/neovim/nvim-lspconfig`
|
||||
- nvim-navic: `https://github.com/SmiteshP/nvim-navic`
|
||||
- nui.nvim: `https://github.com/MunifTanjim/nui.nvim`
|
||||
- Neovim: 0.8 or above
|
||||
|
||||
Optional requirements :
|
||||
- Comment.nvim: `https://github.com/numToStr/Comment.nvim`
|
||||
- telescope.nvim: `https://github.com/nvim-telescope/telescope.nvim`
|
||||
|
||||
=============================================================================
|
||||
CONTENTS *navbuddy-components*
|
||||
|
||||
API |navbuddy-api|
|
||||
Usage |navbuddy-usage|
|
||||
Customisation |navbuddy-customise|
|
||||
Actions |navbuddy-actions|
|
||||
Highlights |navbuddy-highlights|
|
||||
|
||||
=============================================================================
|
||||
API *navbuddy-api*
|
||||
|
||||
|nvim-navbuddy| provides the following functions for the user.
|
||||
|
||||
navbuddy.setup (opts)
|
||||
Configure |nvim-navbuddy|'s options. See more |navbuddy-customise|.
|
||||
|
||||
navbuddy.attach (client, bufnr)
|
||||
Used to attach |nvim-navbuddy| to lsp server. Pass this function as
|
||||
on_attach while setting up your desired lsp server. Manual attachment can
|
||||
be skiped if you have enabled auto_attach option.
|
||||
|
||||
navbuddy.open (bufnr)
|
||||
Opens the Navbuddy window.
|
||||
|
||||
=============================================================================
|
||||
Usage *navbuddy-usage*
|
||||
|
||||
|nvim-navbuddy| needs to be attached to lsp servers of the buffer to work. Use the
|
||||
|navbuddy.attach| function while setting up lsp servers. You can skip this
|
||||
step if you have enabled auto_attach option during setup.
|
||||
|
||||
Example: >lua
|
||||
require("lspconfig").clangd.setup {
|
||||
on_attach = function(client, bufnr)
|
||||
navbuddy.attach(client, bufnr)
|
||||
end
|
||||
}
|
||||
<
|
||||
Then simply use command "Navbuddy" to open the window.
|
||||
|
||||
=============================================================================
|
||||
Customisation *navbuddy-customise*
|
||||
|
||||
Use |navbuddy.setup| to override any of the default options
|
||||
|
||||
icons: table
|
||||
Icons to show for captured symbols. Default icons assume that you
|
||||
have nerd-fonts.
|
||||
|
||||
window: table
|
||||
Set options related to window's "border", "size", "position".
|
||||
|
||||
node_markers: table
|
||||
Indicate whether a node is a leaf or branch node. Default icons assume
|
||||
you have nerd-fonts.
|
||||
|
||||
use_default_mappings: boolean
|
||||
If set to false, only mappings set by user are set. Else default mappings
|
||||
are used for keys that are not set by user.
|
||||
|
||||
mappings: table
|
||||
Actions to be triggered for specified keybindings. For each keybinding
|
||||
it takes a table of format
|
||||
{ callback = <function_to_be_called>, description = "string"}.
|
||||
The callback function takes the "display" object as an argument.
|
||||
|
||||
lsp: table
|
||||
auto_attach: boolean
|
||||
Enable to have Navbuddy automatically attach to every LSP for
|
||||
current buffer. Its disabled by default.
|
||||
preference: table
|
||||
Table ranking lsp_servers. Lower the index, higher the priority of
|
||||
the server. If there are more than one server attached to a
|
||||
buffer, navbuddy will refer to this list to make a decision on
|
||||
which one to use.
|
||||
example: Incase a buffer is attached to clangd and ccls both and
|
||||
the preference list is { "clangd", "pyright" }. Then clangd will
|
||||
be prefered.
|
||||
|
||||
source_buffer:
|
||||
follow_node: boolean
|
||||
Move the source buffer such that focused node is visible.
|
||||
highlight: boolean
|
||||
Highlight focused node on source buffer
|
||||
reorient: string
|
||||
Reorient buffer after changing nodes. options are "smart", "top",
|
||||
"mid" or "none"
|
||||
|
||||
Defaults >lua
|
||||
|
||||
local navbuddy = require("nvim-navbuddy")
|
||||
local actions = require("nvim-navbuddy.actions")
|
||||
|
||||
navbuddy.setup {
|
||||
window = {
|
||||
border = "single", -- "rounded", "double", "solid", "none"
|
||||
-- or an array with eight chars building up the border in a clockwise fashion
|
||||
-- starting with the top-left corner. eg: { "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" }.
|
||||
size = "60%", -- Or table format example: { height = "40%", width = "100%"}
|
||||
position = "50%", -- Or table format example: { row = "100%", col = "0%"}
|
||||
scrolloff = nil, -- scrolloff value within navbuddy window
|
||||
sections = {
|
||||
left = {
|
||||
size = "20%",
|
||||
border = nil, -- You can set border style for each section individually as well.
|
||||
},
|
||||
mid = {
|
||||
size = "40%",
|
||||
border = nil,
|
||||
},
|
||||
right = {
|
||||
-- No size option for right most section. It fills to
|
||||
-- remaining area.
|
||||
border = nil,
|
||||
preview = "leaf", -- Right section can show previews too.
|
||||
-- Options: "leaf", "always" or "never"
|
||||
}
|
||||
}
|
||||
},
|
||||
node_markers = {
|
||||
enabled = true,
|
||||
icons = {
|
||||
leaf = " ",
|
||||
leaf_selected = " → ",
|
||||
branch = " ",
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
[1] = " ", -- File
|
||||
[2] = " ", -- Module
|
||||
[3] = " ", -- Namespace
|
||||
[4] = " ", -- Package
|
||||
[5] = " ", -- Class
|
||||
[6] = " ", -- Method
|
||||
[7] = " ", -- Property
|
||||
[8] = " ", -- Field
|
||||
[9] = " ", -- Constructor
|
||||
[10] = "", -- Enum
|
||||
[11] = "", -- Interface
|
||||
[12] = " ", -- Function
|
||||
[13] = " ", -- Variable
|
||||
[14] = " ", -- Constant
|
||||
[15] = " ", -- String
|
||||
[16] = " ", -- Number
|
||||
[17] = "◩ ", -- Boolean
|
||||
[18] = " ", -- Array
|
||||
[19] = " ", -- Object
|
||||
[20] = " ", -- Key
|
||||
[21] = " ", -- Null
|
||||
[22] = " ", -- EnumMember
|
||||
[23] = " ", -- Struct
|
||||
[24] = " ", -- Event
|
||||
[25] = " ", -- Operator
|
||||
[26] = " ", -- TypeParameter
|
||||
[255] = " ", -- Macro
|
||||
},
|
||||
use_default_mappings = true, -- If set to false, only mappings set
|
||||
-- by user are set. Else default
|
||||
-- mappings are used for keys
|
||||
-- that are not set by user
|
||||
mappings = {
|
||||
["<esc>"] = actions.close(), -- Close and cursor to original location
|
||||
["q"] = actions.close(),
|
||||
|
||||
["j"] = actions.next_sibling(), -- down
|
||||
["k"] = actions.previous_sibling(), -- up
|
||||
|
||||
["h"] = actions.parent(), -- Move to left panel
|
||||
["l"] = actions.children(), -- Move to right panel
|
||||
["0"] = actions.root(), -- Move to first panel
|
||||
|
||||
["v"] = actions.visual_name(), -- Visual selection of name
|
||||
["V"] = actions.visual_scope(), -- Visual selection of scope
|
||||
|
||||
["y"] = actions.yank_name(), -- Yank the name to system clipboard "+
|
||||
["Y"] = actions.yank_scope(), -- Yank the scope to system clipboard "+
|
||||
|
||||
["i"] = actions.insert_name(), -- Insert at start of name
|
||||
["I"] = actions.insert_scope(), -- Insert at start of scope
|
||||
|
||||
["a"] = actions.append_name(), -- Insert at end of name
|
||||
["A"] = actions.append_scope(), -- Insert at end of scope
|
||||
|
||||
["r"] = actions.rename(), -- Rename currently focused symbol
|
||||
|
||||
["d"] = actions.delete(), -- Delete scope
|
||||
|
||||
["f"] = actions.fold_create(), -- Create fold of current scope
|
||||
["F"] = actions.fold_delete(), -- Delete fold of current scope
|
||||
|
||||
["c"] = actions.comment(), -- Comment out current scope
|
||||
|
||||
["<enter>"] = actions.select(), -- Goto selected symbol
|
||||
["o"] = actions.select(),
|
||||
|
||||
["J"] = actions.move_down(), -- Move focused node down
|
||||
["K"] = actions.move_up(), -- Move focused node up
|
||||
|
||||
["s"] = actions.toggle_preview(), -- Show preview of current node
|
||||
|
||||
["<C-v>"] = actions.vsplit(), -- Open selected node in a vertical split
|
||||
["<C-s>"] = actions.hsplit(), -- Open selected node in a horizontal split
|
||||
|
||||
["t"] = actions.telescope({ -- Fuzzy finder at current level.
|
||||
layout_config = { -- All options that can be
|
||||
height = 0.60, -- passed to telescope.nvim's
|
||||
width = 0.60, -- default can be passed here.
|
||||
prompt_position = "top",
|
||||
preview_width = 0.50
|
||||
},
|
||||
layout_strategy = "horizontal",
|
||||
})
|
||||
|
||||
["g?"] = actions.help(), -- Open mappings help window
|
||||
},
|
||||
lsp = {
|
||||
auto_attach = false, -- If set to true, you don't need to manually use attach function
|
||||
preference = nil -- list of lsp server names in order of preference
|
||||
},
|
||||
source_buffer = {
|
||||
follow_node = true, -- Keep the current node in focus on the source buffer
|
||||
highlight = true, -- Highlight the currently focused node
|
||||
reorient = "smart", -- "smart", "top", "mid" or "none"
|
||||
scrolloff = nil -- scrolloff value when navbuddy is open
|
||||
},
|
||||
custom_hl_group = nil, -- "Visual" or any other hl group to use instead of inverted colors
|
||||
}
|
||||
<
|
||||
=============================================================================
|
||||
Actions *navbuddy-actions*
|
||||
|
||||
|nvim-navbuddy| provides the following actions for the user.
|
||||
|
||||
actions.close ()
|
||||
Close the Navbuddy window and return cursor to original location.
|
||||
|
||||
actions.next_sibling ()
|
||||
Move to next_sibling, below current node, in Navbuddy window.
|
||||
|
||||
actions.previous_sibling ()
|
||||
Move to previous_sibling, above current node, in Navbuddy window.
|
||||
|
||||
actions.parent ()
|
||||
Move to parent of current, left of current node, in Navbuddy window.
|
||||
|
||||
actions.children ()
|
||||
Move to children of current, right of current node, in Navbuddy window.
|
||||
|
||||
actions.root ()
|
||||
Move to root node, the first node left of current node, in Navbuddy window.
|
||||
|
||||
actions.select ()
|
||||
Goto currently focus node.
|
||||
|
||||
actions.visual_name ()
|
||||
Visual select the name of current node.
|
||||
|
||||
actions.visual_scope ()
|
||||
Visual select the scope of current node.
|
||||
|
||||
actions.yank_name ()
|
||||
Yank the name of current node.
|
||||
|
||||
actions.yank_scope ()
|
||||
Yank the scope of current node.
|
||||
|
||||
actions.insert_name ()
|
||||
Start insert at begin of name.
|
||||
|
||||
actions.insert_scope ()
|
||||
Start insert at begin of scope.
|
||||
|
||||
actions.append_name ()
|
||||
Start insert at end of name.
|
||||
|
||||
actions.append_scope ()
|
||||
Start insert at end of scope.
|
||||
|
||||
actions.rename ()
|
||||
Trigger lsp rename for current node.
|
||||
|
||||
actions.delete ()
|
||||
Delete currently focused scope.
|
||||
|
||||
actions.fold_create ()
|
||||
Create fold for current scope. Requires fold methos to be "manual".
|
||||
|
||||
actions.fold_delete ()
|
||||
Delete fold for current scope. Requires fold methos to be "manual".
|
||||
|
||||
actions.comment ()
|
||||
Comment selected scope. Require Comment.nvim plugin to be installed.
|
||||
|
||||
actions.move_down ()
|
||||
Move currently focued node down. Copies entire lines and works only in case
|
||||
there are no overlapping lines between current node and next node.
|
||||
|
||||
actions.move_up ()
|
||||
Move currently focued node up. Copies entire lines and works only in case
|
||||
there are no overlapping lines between current node and previous node.
|
||||
|
||||
actions.vsplit ()
|
||||
Opens vertical split with currently selected node.
|
||||
Will not remember top line like |winsaveview()| does.
|
||||
NOTE: Direction of split is controlled by 'splitright'
|
||||
|
||||
actions.hsplit ()
|
||||
Acts akin to vsplit, but splits horizontally.
|
||||
NOTE: Direction of split is controlled by 'splitbelow'
|
||||
|
||||
actions.telescope (opts)
|
||||
Open Fuzzy finder with telescope to search sibling nodes on current level.
|
||||
Can be customized during setup by passing opts table, all configuration
|
||||
passed to telescope.nvim's default option can be passed here.
|
||||
|
||||
=============================================================================
|
||||
Highlight *navbuddy-highlights*
|
||||
|
||||
|nvim-navbuddy| provides the following highlights which get used when
|
||||
available.
|
||||
|
||||
`NavbuddyName` - highlight for name in source buffer
|
||||
`NavbuddyScope` - highlight for scope of context in source buffer
|
||||
`NavbuddyFloatBorder` - Floatborder highlight
|
||||
`NavbuddyNormalFloat` - Float normal highlight
|
||||
|
||||
The following highlights are are used to highlight elements in the navbuddy
|
||||
window according to their type. If you have "NavicIcons<type>" highlights
|
||||
already defined, these will automatically get linked to them unless defined
|
||||
explicitly.
|
||||
|
||||
`NavbuddyFile`
|
||||
`NavbuddyModule`
|
||||
`NavbuddyNamespace`
|
||||
`NavbuddyPackage`
|
||||
`NavbuddyClass`
|
||||
`NavbuddyMethod`
|
||||
`NavbuddyProperty`
|
||||
`NavbuddyField`
|
||||
`NavbuddyConstructor`
|
||||
`NavbuddyEnum`
|
||||
`NavbuddyInterface`
|
||||
`NavbuddyFunction`
|
||||
`NavbuddyVariable`
|
||||
`NavbuddyConstant`
|
||||
`NavbuddyString`
|
||||
`NavbuddyNumber`
|
||||
`NavbuddyBoolean`
|
||||
`NavbuddyArray`
|
||||
`NavbuddyObject`
|
||||
`NavbuddyKey`
|
||||
`NavbuddyNull`
|
||||
`NavbuddyEnumMember`
|
||||
`NavbuddyStruct`
|
||||
`NavbuddyEvent`
|
||||
`NavbuddyOperator`
|
||||
`NavbuddyTypeParameter`
|
||||
|
||||
|
||||
=============================================================================
|
||||
vim:tw=78:ts=4:ft=help:norl:
|
||||
@ -0,0 +1,754 @@
|
||||
local actions = {}
|
||||
|
||||
local function fix_end_character_position(bufnr, name_range_or_scope)
|
||||
if name_range_or_scope["end"].character == 0 and (name_range_or_scope["end"].line - name_range_or_scope["start"].line) > 0 then
|
||||
name_range_or_scope["end"].line = name_range_or_scope["end"].line - 1
|
||||
name_range_or_scope["end"].character = string.len(vim.api.nvim_buf_get_lines(bufnr, name_range_or_scope["end"].line - 1, name_range_or_scope["end"].line, false)[1])
|
||||
end
|
||||
end
|
||||
|
||||
function actions.close()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
vim.api.nvim_win_set_cursor(display.for_win, display.start_cursor)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Close Navbuddy"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.next_sibling()
|
||||
local callback = function(display)
|
||||
if display.focus_node.next == nil then
|
||||
return
|
||||
end
|
||||
|
||||
for _ = 1, vim.v.count1 do
|
||||
local next_node = display.focus_node.next
|
||||
if next_node == nil then
|
||||
break
|
||||
end
|
||||
display.focus_node = next_node
|
||||
end
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move down to next node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.previous_sibling()
|
||||
local callback = function(display)
|
||||
if display.focus_node.prev == nil then
|
||||
return
|
||||
end
|
||||
|
||||
for _ = 1, vim.v.count1 do
|
||||
local prev_node = display.focus_node.prev
|
||||
if prev_node == nil then
|
||||
break
|
||||
end
|
||||
display.focus_node = prev_node
|
||||
end
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move up to previous node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.parent()
|
||||
local callback = function(display)
|
||||
if display.focus_node.parent.is_root then
|
||||
return
|
||||
end
|
||||
|
||||
local parent_node = display.focus_node.parent
|
||||
display.focus_node = parent_node
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move left to parent level"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.children()
|
||||
local callback = function(display)
|
||||
if display.focus_node.children == nil then
|
||||
actions.select().callback(display)
|
||||
return
|
||||
end
|
||||
|
||||
local child_node
|
||||
if display.focus_node.memory then
|
||||
child_node = display.focus_node.children[display.focus_node.memory]
|
||||
else
|
||||
child_node = display.focus_node.children[1]
|
||||
end
|
||||
display.focus_node = child_node
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move right to child node level"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.root()
|
||||
local callback = function(display)
|
||||
if display.focus_node.parent.is_root then
|
||||
return
|
||||
end
|
||||
|
||||
while not display.focus_node.parent.is_root do
|
||||
display.focus_node.parent.memory = display.focus_node.index
|
||||
display.focus_node = display.focus_node.parent
|
||||
end
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move to top most node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.select()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
-- to push location to jumplist:
|
||||
-- move display to start_cursor, set mark ', then move to new location
|
||||
vim.api.nvim_win_set_cursor(display.for_win, display.start_cursor)
|
||||
vim.api.nvim_command("normal! m'")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
|
||||
if display.config.source_buffer.reorient == "smart" then
|
||||
local total_lines = display.focus_node.scope["end"].line - display.focus_node.scope["start"].line + 1
|
||||
|
||||
if total_lines >= vim.api.nvim_win_get_height(display.for_win) then
|
||||
vim.api.nvim_command("normal! zt")
|
||||
else
|
||||
local mid_line =
|
||||
bit.rshift(display.focus_node.scope["start"].line + display.focus_node.scope["end"].line, 1)
|
||||
vim.api.nvim_win_set_cursor(display.for_win, { mid_line, 0 })
|
||||
vim.api.nvim_command("normal! zz")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
end
|
||||
elseif display.config.source_buffer.reorient == "mid" then
|
||||
vim.api.nvim_command("normal! zz")
|
||||
elseif display.config.source_buffer.reorient == "top" then
|
||||
vim.api.nvim_command("normal! zt")
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Select and Goto current node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.yank_name()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["end"].line, display.focus_node.name_range["end"].character - 1 }
|
||||
)
|
||||
vim.api.nvim_command('normal! "+y')
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Yank node name"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.yank_scope()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
vim.api.nvim_command('normal! "+y')
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Yank node scope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.visual_name()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["end"].line, display.focus_node.name_range["end"].character - 1 }
|
||||
)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Visual select node name"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.visual_scope()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Visual select node scope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.insert_name()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["start"].line, display.focus_node.name_range["start"].character }
|
||||
)
|
||||
vim.api.nvim_feedkeys("i", "n", false)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Insert node name"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.insert_scope()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_feedkeys("i", "n", false)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Insert node scope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.append_name()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.name_range)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.name_range["end"].line, display.focus_node.name_range["end"].character - 1 }
|
||||
)
|
||||
vim.api.nvim_feedkeys("a", "n", false)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Append node name"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.append_scope()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
if
|
||||
string.len(
|
||||
vim.api.nvim_buf_get_lines(
|
||||
display.for_buf,
|
||||
display.focus_node.scope["end"].line - 1,
|
||||
display.focus_node.scope["end"].line,
|
||||
false
|
||||
)[1]
|
||||
) == display.focus_node.scope["end"].character
|
||||
then
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character }
|
||||
)
|
||||
else
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
end
|
||||
vim.api.nvim_feedkeys("a", "n", false)
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Append node scope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.rename()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
vim.lsp.buf.rename()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Rename"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.delete()
|
||||
local callback = function(display)
|
||||
actions.visual_scope().callback(display)
|
||||
vim.api.nvim_command("normal! d")
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Delete"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.fold_create()
|
||||
local callback = function(display)
|
||||
if vim.o.foldmethod ~= "manual" then
|
||||
vim.notify("Fold create action works only when foldmethod is 'manual'", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
display.state.leaving_window_for_action = true
|
||||
vim.api.nvim_set_current_win(display.for_win)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
vim.api.nvim_command("normal! zf")
|
||||
vim.api.nvim_set_current_win(display.mid.winid)
|
||||
display.state.leaving_window_for_action = false
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Create fold"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.fold_delete()
|
||||
local callback = function(display)
|
||||
if vim.o.foldmethod ~= "manual" then
|
||||
vim.notify("Fold delete action works only when foldmethod is 'manual'", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
display.state.leaving_window_for_action = true
|
||||
vim.api.nvim_set_current_win(display.for_win)
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["start"].line, display.focus_node.scope["start"].character }
|
||||
)
|
||||
vim.api.nvim_command("normal! v")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
display.for_win,
|
||||
{ display.focus_node.scope["end"].line, display.focus_node.scope["end"].character - 1 }
|
||||
)
|
||||
pcall(vim.api.nvim_command, "normal! zd")
|
||||
vim.api.nvim_set_current_win(display.mid.winid)
|
||||
display.state.leaving_window_for_action = false
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Delete fold"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.comment()
|
||||
local callback = function(display)
|
||||
local status_ok, comment = pcall(require, "Comment.api")
|
||||
if not status_ok then
|
||||
vim.notify("Comment.nvim not found", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
fix_end_character_position(display.for_buf, display.focus_node.scope)
|
||||
display.state.leaving_window_for_action = true
|
||||
vim.api.nvim_set_current_win(display.for_win)
|
||||
vim.api.nvim_buf_set_mark(
|
||||
display.for_buf,
|
||||
"<",
|
||||
display.focus_node.scope["start"].line,
|
||||
display.focus_node.scope["start"].character,
|
||||
{}
|
||||
)
|
||||
vim.api.nvim_buf_set_mark(
|
||||
display.for_buf,
|
||||
">",
|
||||
display.focus_node.scope["end"].line,
|
||||
display.focus_node.scope["end"].character,
|
||||
{}
|
||||
)
|
||||
comment.locked("toggle.linewise")("v")
|
||||
vim.api.nvim_set_current_win(display.mid.winid)
|
||||
display.state.leaving_window_for_action = false
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Comment"
|
||||
}
|
||||
end
|
||||
|
||||
local function swap_nodes(for_buf, nodeA, nodeB)
|
||||
-- nodeA
|
||||
-- ^
|
||||
-- |
|
||||
-- v
|
||||
-- nodeB
|
||||
|
||||
fix_end_character_position(for_buf, nodeA.scope)
|
||||
fix_end_character_position(for_buf, nodeB.scope)
|
||||
|
||||
if nodeA.scope["end"].line >= nodeB.scope["start"].line and nodeA.parent == nodeB.parent then
|
||||
vim.notify("Cannot swap!", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local nodeA_text = vim.api.nvim_buf_get_lines(for_buf, nodeA.scope["start"].line-1, nodeA.scope["end"].line-1+1, false)
|
||||
local mid_text = vim.api.nvim_buf_get_lines(for_buf, nodeA.scope["end"].line-1+1, nodeB.scope["start"].line-1, false)
|
||||
local nodeB_text = vim.api.nvim_buf_get_lines(for_buf, nodeB.scope["start"].line-1, nodeB.scope["end"].line-1+1, false)
|
||||
|
||||
local start_line = nodeA.scope["start"].line-1
|
||||
local nodeA_line_cnt = nodeA.scope["end"].line + 1 - nodeA.scope["start"].line
|
||||
local mid_line_cnt = nodeB.scope["start"].line - nodeA.scope["end"].line - 1
|
||||
local nodeB_line_cnt = nodeB.scope["end"].line + 1 - nodeB.scope["start"].line
|
||||
|
||||
-- Swap pointers
|
||||
nodeA.next = nodeB.next
|
||||
nodeB.next = nodeA
|
||||
|
||||
nodeB.prev = nodeA.prev
|
||||
nodeA.prev = nodeB
|
||||
|
||||
-- Swap index
|
||||
local nodeB_index = nodeB.index
|
||||
nodeB.index = nodeA.index
|
||||
nodeA.index = nodeB_index
|
||||
|
||||
-- Swap in parent's children array
|
||||
local parent = nodeA.parent
|
||||
parent.children[nodeA.index] = nodeA
|
||||
parent.children[nodeB.index] = nodeB
|
||||
|
||||
-- Adjust line numbers
|
||||
nodeA.scope["start"].line = nodeA.scope["start"].line + nodeB_line_cnt + mid_line_cnt
|
||||
nodeA.scope["end"].line = nodeA.scope["end"].line + nodeB_line_cnt + mid_line_cnt
|
||||
nodeA.name_range["start"].line = nodeA.name_range["start"].line + nodeB_line_cnt + mid_line_cnt
|
||||
nodeA.name_range["end"].line = nodeA.name_range["end"].line + nodeB_line_cnt + mid_line_cnt
|
||||
|
||||
nodeB.scope["start"].line = nodeB.scope["start"].line - nodeA_line_cnt - mid_line_cnt
|
||||
nodeB.scope["end"].line = nodeB.scope["end"].line - nodeA_line_cnt - mid_line_cnt
|
||||
nodeB.name_range["start"].line = nodeB.name_range["start"].line - nodeA_line_cnt - mid_line_cnt
|
||||
nodeB.name_range["end"].line = nodeB.name_range["end"].line - nodeA_line_cnt - mid_line_cnt
|
||||
|
||||
-- Set lines
|
||||
vim.api.nvim_buf_set_lines(for_buf, start_line, start_line + nodeB_line_cnt, false, nodeB_text)
|
||||
vim.api.nvim_buf_set_lines(for_buf, start_line + nodeB_line_cnt, start_line + nodeB_line_cnt + mid_line_cnt, false, mid_text)
|
||||
vim.api.nvim_buf_set_lines(for_buf, start_line + nodeB_line_cnt + mid_line_cnt, start_line + nodeB_line_cnt + mid_line_cnt + nodeA_line_cnt, false, nodeA_text)
|
||||
end
|
||||
|
||||
function actions.move_down()
|
||||
local callback = function(display)
|
||||
if display.focus_node.next == nil then
|
||||
return
|
||||
end
|
||||
|
||||
swap_nodes(display.for_buf, display.focus_node, display.focus_node.next)
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move code block down"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.move_up()
|
||||
local callback = function(display)
|
||||
if display.focus_node.prev == nil then
|
||||
return
|
||||
end
|
||||
|
||||
swap_nodes(display.for_buf, display.focus_node.prev, display.focus_node)
|
||||
|
||||
display:redraw()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Move code block up"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.toggle_preview()
|
||||
local callback = function(display)
|
||||
if vim.api.nvim_win_get_buf(display.right.winid) == display.right.bufnr then
|
||||
display:show_preview()
|
||||
else
|
||||
display:hide_preview()
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Show preview of current node"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.vsplit()
|
||||
local callback = function(display)
|
||||
actions.close().callback(display)
|
||||
vim.api.nvim_command("vsplit")
|
||||
display.for_win = vim.api.nvim_get_current_win()
|
||||
actions.select().callback(display)
|
||||
vim.api.nvim_command("normal! zv")
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Open selected node in a vertical split"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.hsplit()
|
||||
local callback = function(display)
|
||||
actions.close().callback(display)
|
||||
vim.api.nvim_command("split")
|
||||
display.for_win = vim.api.nvim_get_current_win()
|
||||
actions.select().callback(display)
|
||||
vim.api.nvim_command("normal! zv")
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Open selected node in a horizontal split"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.telescope(opts)
|
||||
local callback = function(display)
|
||||
local status_ok, _ = pcall(require, "telescope")
|
||||
if not status_ok then
|
||||
vim.notify("telescope.nvim not found", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local navic = require("nvim-navic.lib")
|
||||
local pickers = require("telescope.pickers")
|
||||
local entry_display = require("telescope.pickers.entry_display")
|
||||
local finders = require("telescope.finders")
|
||||
local conf = require("telescope.config").values
|
||||
local t_actions = require("telescope.actions")
|
||||
local action_state = require("telescope.actions.state")
|
||||
|
||||
local displayer = entry_display.create({
|
||||
separator = " ",
|
||||
items = {
|
||||
{ width = 14 },
|
||||
{ remaining = true },
|
||||
},
|
||||
})
|
||||
|
||||
local function make_display(entry)
|
||||
local node = entry.value
|
||||
local kind = navic.adapt_lsp_num_to_str(node.kind)
|
||||
local kind_hl = "Navbuddy"..kind
|
||||
local name_hl = "NavbuddyNormalFloat"
|
||||
local columns = {
|
||||
{ string.lower(kind), kind_hl },
|
||||
{ node.name, name_hl},
|
||||
}
|
||||
return displayer(columns)
|
||||
end
|
||||
|
||||
local function make_entry(node)
|
||||
return {
|
||||
value = node,
|
||||
display = make_display,
|
||||
name = node.name,
|
||||
ordinal = string.lower(navic.adapt_lsp_num_to_str(node.kind)).." "..node.name,
|
||||
lnum = node.name_range["start"].line,
|
||||
col = node.name_range["start"].character,
|
||||
bufnr = display.for_buf,
|
||||
filename = vim.api.nvim_buf_get_name(display.for_buf),
|
||||
}
|
||||
end
|
||||
|
||||
display:close()
|
||||
pickers.new(opts, {
|
||||
prompt_title = "Fuzzy Search",
|
||||
finder = finders.new_table({
|
||||
results = display.focus_node.parent.children,
|
||||
entry_maker = make_entry
|
||||
}),
|
||||
sorter = conf.generic_sorter(opts),
|
||||
previewer = conf.qflist_previewer(opts),
|
||||
attach_mappings = function(prompt_bufnr, _)
|
||||
t_actions.select_default:replace(function()
|
||||
local selection = action_state.get_selected_entry()
|
||||
display.focus_node = selection.value
|
||||
t_actions.close(prompt_bufnr)
|
||||
end)
|
||||
t_actions.close:enhance({
|
||||
post = function()
|
||||
display = require("nvim-navbuddy.display"):new(display)
|
||||
end
|
||||
})
|
||||
return true
|
||||
end,
|
||||
}):find()
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Fuzzy search current level with telescope"
|
||||
}
|
||||
end
|
||||
|
||||
function actions.help()
|
||||
local callback = function(display)
|
||||
display:close()
|
||||
|
||||
local nui_popup = require("nui.popup")
|
||||
|
||||
local help_popup = nui_popup({
|
||||
relative = "editor",
|
||||
position = display.config.window.position,
|
||||
size = display.config.window.size,
|
||||
enter = true,
|
||||
focusable = true,
|
||||
border = display.config.window.border,
|
||||
win_options = {
|
||||
winhighlight = "Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder",
|
||||
},
|
||||
buf_options = {
|
||||
modifiable = false,
|
||||
},
|
||||
})
|
||||
|
||||
local function quit_help()
|
||||
help_popup:unmount()
|
||||
require("nvim-navbuddy.display"):new(display)
|
||||
end
|
||||
|
||||
help_popup:map("n", "q", quit_help)
|
||||
help_popup:map("n", "<esc>", quit_help)
|
||||
|
||||
help_popup:mount()
|
||||
|
||||
local max_keybinding_len = 0
|
||||
for k, _ in pairs(display.config.mappings) do
|
||||
max_keybinding_len = math.max(#k, max_keybinding_len)
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
for k, v in pairs(display.config.mappings) do
|
||||
local text = " " .. k .. string.rep(" ", max_keybinding_len - #k) .. " | " .. v.description
|
||||
table.insert(lines, text)
|
||||
end
|
||||
table.sort(lines)
|
||||
table.insert(lines, 1, " Navbuddy Mappings" .. string.rep(" ", math.max(1, vim.api.nvim_win_get_width(help_popup.winid) - 18*2)) .. "press 'q' to exit ")
|
||||
table.insert(lines, 2, string.rep("-", vim.api.nvim_win_get_width(help_popup.winid)))
|
||||
|
||||
vim.api.nvim_buf_set_option(help_popup.bufnr, "modifiable", true)
|
||||
vim.api.nvim_buf_set_lines(help_popup.bufnr, 0, -1, false, lines)
|
||||
vim.api.nvim_buf_set_option(help_popup.bufnr, "modifiable", false)
|
||||
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
help_popup.bufnr,
|
||||
-1,
|
||||
"NavbuddyFunction",
|
||||
0,
|
||||
0,
|
||||
-1
|
||||
)
|
||||
for i = 2, #lines do
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
help_popup.bufnr,
|
||||
-1,
|
||||
"NavbuddyKey",
|
||||
i - 1,
|
||||
0,
|
||||
max_keybinding_len + 3
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
callback = callback,
|
||||
description = "Show mappings"
|
||||
}
|
||||
end
|
||||
|
||||
return actions
|
||||
@ -0,0 +1,405 @@
|
||||
local navic = require("nvim-navic.lib")
|
||||
|
||||
local nui_popup = require("nui.popup")
|
||||
local nui_layout = require("nui.layout")
|
||||
local nui_text = require("nui.text")
|
||||
|
||||
local ui = require("nvim-navbuddy.ui")
|
||||
|
||||
local ns = vim.api.nvim_create_namespace("nvim-navbuddy")
|
||||
|
||||
local function clear_buffer(buf)
|
||||
vim.api.nvim_win_set_buf(buf.winid, buf.bufnr)
|
||||
|
||||
vim.api.nvim_win_set_option(buf.winid, "signcolumn", "no")
|
||||
vim.api.nvim_win_set_option(buf.winid, "foldlevel", 100)
|
||||
vim.api.nvim_win_set_option(buf.winid, "wrap", true)
|
||||
|
||||
vim.api.nvim_buf_set_option(buf.bufnr, "modifiable", true)
|
||||
vim.api.nvim_buf_set_lines(buf.bufnr, 0, -1, false, {})
|
||||
vim.api.nvim_buf_set_option(buf.bufnr, "modifiable", false)
|
||||
for _, extmark in ipairs(vim.api.nvim_buf_get_extmarks(buf.bufnr, ns, 0, -1, {})) do
|
||||
vim.api.nvim_buf_del_extmark(buf.bufnr, ns, extmark[1])
|
||||
end
|
||||
end
|
||||
|
||||
local function fill_buffer(buf, node, config)
|
||||
local cursor_pos = vim.api.nvim_win_get_cursor(buf.winid)
|
||||
clear_buffer(buf)
|
||||
|
||||
local parent = node.parent
|
||||
|
||||
local lines = {}
|
||||
for _, child_node in ipairs(parent.children) do
|
||||
local text = " " .. config.icons[child_node.kind] .. child_node.name
|
||||
table.insert(lines, text)
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_set_option(buf.bufnr, "modifiable", true)
|
||||
vim.api.nvim_buf_set_lines(buf.bufnr, 0, -1, false, lines)
|
||||
vim.api.nvim_buf_set_option(buf.bufnr, "modifiable", false)
|
||||
|
||||
if cursor_pos[1] ~= node.index then
|
||||
cursor_pos[1] = node.index
|
||||
end
|
||||
|
||||
for i, child_node in ipairs(parent.children) do
|
||||
local hl_group = "Navbuddy" .. navic.adapt_lsp_num_to_str(child_node.kind)
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
buf.bufnr,
|
||||
ns,
|
||||
hl_group,
|
||||
i - 1,
|
||||
0,
|
||||
-1
|
||||
)
|
||||
if config.node_markers.enabled then
|
||||
vim.api.nvim_buf_set_extmark(buf.bufnr, ns, i - 1, #lines[i], {
|
||||
virt_text = { {
|
||||
child_node.children ~= nil and config.node_markers.icons.branch
|
||||
or i == cursor_pos[1] and config.node_markers.icons.leaf_selected
|
||||
or config.node_markers.icons.leaf,
|
||||
i == cursor_pos[1] and { "NavbuddyCursorLine", hl_group } or hl_group,
|
||||
} },
|
||||
virt_text_pos = "right_align",
|
||||
virt_text_hide = false,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_add_highlight(buf.bufnr, ns, "NavbuddyCursorLine", cursor_pos[1] - 1, 0, -1)
|
||||
vim.api.nvim_buf_set_extmark(buf.bufnr, ns, cursor_pos[1] - 1, #lines[cursor_pos[1]], {
|
||||
end_row = cursor_pos[1],
|
||||
hl_eol = true,
|
||||
hl_group = "NavbuddyCursorLine" .. navic.adapt_lsp_num_to_str(node.kind),
|
||||
})
|
||||
vim.api.nvim_win_set_cursor(buf.winid, cursor_pos)
|
||||
end
|
||||
|
||||
local display = {}
|
||||
|
||||
function display:new(obj)
|
||||
ui.highlight_setup(obj.config)
|
||||
|
||||
-- Object
|
||||
setmetatable(obj, self)
|
||||
self.__index = self
|
||||
|
||||
local config = obj.config
|
||||
|
||||
-- NUI elements
|
||||
local left_popup = nui_popup({
|
||||
focusable = false,
|
||||
border = config.window.sections.left.border or ui.get_border_chars(config.window.border, "left"),
|
||||
win_options = {
|
||||
winhighlight = "Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder",
|
||||
},
|
||||
buf_options = {
|
||||
modifiable = false,
|
||||
},
|
||||
})
|
||||
|
||||
local mid_popup = nui_popup({
|
||||
enter = true,
|
||||
border = config.window.sections.mid.border or ui.get_border_chars(config.window.border, "mid"),
|
||||
win_options = {
|
||||
winhighlight = "Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder",
|
||||
scrolloff = config.window.scrolloff
|
||||
},
|
||||
buf_options = {
|
||||
modifiable = false,
|
||||
},
|
||||
})
|
||||
|
||||
local lsp_name = {
|
||||
bottom = nui_text("[" .. obj.lsp_name .. "]", "NavbuddyFloatBorder"),
|
||||
bottom_align = "right",
|
||||
}
|
||||
|
||||
if
|
||||
config.window.sections.right.border == "none"
|
||||
or config.window.border == "none"
|
||||
or config.window.sections.right.border == "shadow"
|
||||
or config.window.border == "shadow"
|
||||
or config.window.sections.right.border == "solid"
|
||||
or config.window.border == "solid"
|
||||
then
|
||||
lsp_name = nil
|
||||
end
|
||||
|
||||
local right_popup = nui_popup({
|
||||
focusable = false,
|
||||
border = {
|
||||
style = config.window.sections.right.border or ui.get_border_chars(config.window.border, "right"),
|
||||
text = lsp_name,
|
||||
},
|
||||
win_options = {
|
||||
winhighlight = "Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder",
|
||||
scrolloff = 0,
|
||||
},
|
||||
buf_options = {
|
||||
modifiable = false,
|
||||
},
|
||||
})
|
||||
|
||||
local layout = nui_layout(
|
||||
{
|
||||
relative = "editor",
|
||||
position = config.window.position,
|
||||
size = config.window.size,
|
||||
},
|
||||
nui_layout.Box({
|
||||
nui_layout.Box(left_popup, { size = config.window.sections.left.size }),
|
||||
nui_layout.Box(mid_popup, { size = config.window.sections.mid.size }),
|
||||
nui_layout.Box(right_popup, { grow = 1 }),
|
||||
}, { dir = "row" })
|
||||
)
|
||||
|
||||
obj.layout = layout
|
||||
obj.left = left_popup
|
||||
obj.mid = mid_popup
|
||||
obj.right = right_popup
|
||||
obj.state = {
|
||||
leaving_window_for_action = false,
|
||||
leaving_window_for_reorientation = false,
|
||||
closed = false,
|
||||
-- user_gui_cursor = nil,
|
||||
source_buffer_scrolloff = nil
|
||||
}
|
||||
|
||||
-- Set filetype
|
||||
vim.api.nvim_buf_set_option(obj.mid.bufnr, "filetype", "Navbuddy")
|
||||
|
||||
-- Hidden cursor
|
||||
if obj.state.user_gui_cursor == nil then
|
||||
obj.state.user_gui_cursor = vim.api.nvim_get_option("guicursor")
|
||||
end
|
||||
obj.state.user_gui_cursor = vim.api.nvim_get_option("guicursor")
|
||||
if obj.state.user_gui_cursor ~= "" then
|
||||
vim.api.nvim_set_option("guicursor", "a:NavbuddyCursor")
|
||||
end
|
||||
|
||||
-- User Scrolloff
|
||||
if config.source_buffer.scrolloff then
|
||||
obj.state.source_buffer_scrolloff = vim.api.nvim_get_option("scrolloff")
|
||||
vim.api.nvim_set_option("scrolloff", config.source_buffer.scrolloff)
|
||||
end
|
||||
|
||||
-- Autocmds
|
||||
local augroup = vim.api.nvim_create_augroup("Navbuddy", { clear = false })
|
||||
vim.api.nvim_clear_autocmds({ buffer = obj.mid.bufnr })
|
||||
vim.api.nvim_create_autocmd("CursorMoved", {
|
||||
group = augroup,
|
||||
buffer = obj.mid.bufnr,
|
||||
callback = function()
|
||||
local cursor_pos = vim.api.nvim_win_get_cursor(obj.mid.winid)
|
||||
if obj.focus_node ~= obj.focus_node.parent.children[cursor_pos[1]] then
|
||||
obj.focus_node = obj.focus_node.parent.children[cursor_pos[1]]
|
||||
obj:redraw()
|
||||
end
|
||||
|
||||
obj.focus_node.parent.memory = obj.focus_node.index
|
||||
|
||||
obj:clear_highlights()
|
||||
obj:focus_range()
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("BufLeave", {
|
||||
group = augroup,
|
||||
buffer = obj.mid.bufnr,
|
||||
callback = function()
|
||||
if
|
||||
obj.state.leaving_window_for_action == false
|
||||
and obj.state.leaving_window_for_reorientation == false
|
||||
and obj.state.closed == false
|
||||
then
|
||||
obj:close()
|
||||
end
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("CmdlineEnter", {
|
||||
group = augroup,
|
||||
buffer = obj.mid.bufnr,
|
||||
callback = function()
|
||||
vim.api.nvim_set_option("guicursor", obj.state.user_gui_cursor)
|
||||
end
|
||||
})
|
||||
vim.api.nvim_create_autocmd("CmdlineLeave", {
|
||||
group = augroup,
|
||||
buffer = obj.mid.bufnr,
|
||||
callback = function()
|
||||
if obj.state.user_gui_cursor ~= "" then
|
||||
vim.api.nvim_set_option("guicursor", "a:NavbuddyCursor")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Mappings
|
||||
for i, v in pairs(config.mappings) do
|
||||
obj.mid:map("n", i,
|
||||
function()
|
||||
v.callback(obj)
|
||||
end,
|
||||
{ nowait=true })
|
||||
end
|
||||
|
||||
-- Display
|
||||
layout:mount()
|
||||
obj:redraw()
|
||||
obj:focus_range()
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
function display:focus_range()
|
||||
local ranges = nil
|
||||
|
||||
if vim.deep_equal(self.focus_node.scope, self.focus_node.name_range) then
|
||||
ranges = { { "NavbuddyScope", self.focus_node.scope } }
|
||||
else
|
||||
ranges = { { "NavbuddyScope", self.focus_node.scope }, { "NavbuddyName", self.focus_node.name_range } }
|
||||
end
|
||||
|
||||
if self.config.source_buffer.highlight then
|
||||
for _, v in ipairs(ranges) do
|
||||
local highlight, range = unpack(v)
|
||||
|
||||
if range["start"].line == range["end"].line then
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
self.for_buf,
|
||||
ns,
|
||||
highlight,
|
||||
range["start"].line - 1,
|
||||
range["start"].character,
|
||||
range["end"].character
|
||||
)
|
||||
else
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
self.for_buf,
|
||||
ns,
|
||||
highlight,
|
||||
range["start"].line - 1,
|
||||
range["start"].character,
|
||||
-1
|
||||
)
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
self.for_buf,
|
||||
ns,
|
||||
highlight,
|
||||
range["end"].line - 1,
|
||||
0,
|
||||
range["end"].character
|
||||
)
|
||||
for i = range["start"].line, range["end"].line - 2, 1 do
|
||||
vim.api.nvim_buf_add_highlight(self.for_buf, ns, highlight, i, 0, -1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.config.source_buffer.follow_node then
|
||||
self:reorient(self.for_win, self.config.source_buffer.reorient)
|
||||
end
|
||||
end
|
||||
|
||||
function display:reorient(ro_win, reorient_method)
|
||||
vim.api.nvim_win_set_cursor(ro_win, { self.focus_node.name_range["start"].line, self.focus_node.name_range["start"].character })
|
||||
|
||||
self.state.leaving_window_for_reorientation = true
|
||||
vim.api.nvim_set_current_win(ro_win)
|
||||
|
||||
if reorient_method == "smart" then
|
||||
local total_lines = self.focus_node.scope["end"].line - self.focus_node.scope["start"].line + 1
|
||||
|
||||
if total_lines >= vim.api.nvim_win_get_height(ro_win) then
|
||||
vim.api.nvim_command("normal! zt")
|
||||
else
|
||||
local mid_line = bit.rshift(self.focus_node.scope["start"].line + self.focus_node.scope["end"].line, 1)
|
||||
vim.api.nvim_win_set_cursor(ro_win, { mid_line, 0 })
|
||||
vim.api.nvim_command("normal! zz")
|
||||
vim.api.nvim_win_set_cursor(
|
||||
ro_win,
|
||||
{ self.focus_node.name_range["start"].line, self.focus_node.name_range["start"].character }
|
||||
)
|
||||
end
|
||||
elseif reorient_method == "mid" then
|
||||
vim.api.nvim_command("normal! zz")
|
||||
elseif reorient_method == "top" then
|
||||
vim.api.nvim_command("normal! zt")
|
||||
end
|
||||
|
||||
vim.api.nvim_set_current_win(self.mid.winid)
|
||||
self.state.leaving_window_for_reorientation = false
|
||||
end
|
||||
|
||||
function display:show_preview()
|
||||
vim.api.nvim_win_set_buf(self.right.winid, self.for_buf)
|
||||
|
||||
vim.api.nvim_win_set_option(self.right.winid, 'winhighlight', 'Normal:NavbuddyNormalFloat,FloatBorder:NavbuddyFloatBorder')
|
||||
vim.api.nvim_win_set_option(self.right.winid, "signcolumn", "no")
|
||||
vim.api.nvim_win_set_option(self.right.winid, "foldlevel", 100)
|
||||
vim.api.nvim_win_set_option(self.right.winid, "wrap", false)
|
||||
|
||||
self:reorient(self.right.winid, "smart")
|
||||
end
|
||||
|
||||
function display:hide_preview()
|
||||
vim.api.nvim_win_set_buf(self.right.winid, self.right.bufnr)
|
||||
local node = self.focus_node
|
||||
if node.children then
|
||||
if node.memory then
|
||||
fill_buffer(self.right, node.children[node.memory], self.config)
|
||||
else
|
||||
fill_buffer(self.right, node.children[1], self.config)
|
||||
end
|
||||
else
|
||||
clear_buffer(self.right)
|
||||
end
|
||||
end
|
||||
|
||||
function display:clear_highlights()
|
||||
vim.api.nvim_buf_clear_highlight(self.for_buf, ns, 0, -1)
|
||||
end
|
||||
|
||||
function display:redraw()
|
||||
local node = self.focus_node
|
||||
fill_buffer(self.mid, node, self.config)
|
||||
|
||||
local preview_method = self.config.window.sections.right.preview
|
||||
|
||||
if preview_method == "always" then
|
||||
self:show_preview()
|
||||
else
|
||||
if node.children then
|
||||
if node.memory then
|
||||
fill_buffer(self.right, node.children[node.memory], self.config)
|
||||
else
|
||||
fill_buffer(self.right, node.children[1], self.config)
|
||||
end
|
||||
else
|
||||
if preview_method == "leaf" then
|
||||
self:show_preview()
|
||||
else
|
||||
clear_buffer(self.right)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if node.parent.is_root then
|
||||
clear_buffer(self.left)
|
||||
else
|
||||
fill_buffer(self.left, node.parent, self.config)
|
||||
end
|
||||
end
|
||||
|
||||
function display:close()
|
||||
self.state.closed = true
|
||||
vim.api.nvim_set_option("guicursor", self.state.user_gui_cursor)
|
||||
if self.state.source_buffer_scrolloff then
|
||||
vim.api.nvim_set_option("scrolloff", self.state.source_buffer_scrolloff)
|
||||
end
|
||||
self.layout:unmount()
|
||||
self:clear_highlights()
|
||||
end
|
||||
|
||||
return display
|
||||
@ -0,0 +1,435 @@
|
||||
local navic = require("nvim-navic.lib")
|
||||
|
||||
local nui_menu = require("nui.menu")
|
||||
|
||||
local display = require("nvim-navbuddy.display")
|
||||
local actions = require("nvim-navbuddy.actions")
|
||||
|
||||
local config = {
|
||||
window = {
|
||||
border = "single",
|
||||
size = "60%",
|
||||
position = "50%",
|
||||
scrolloff = nil,
|
||||
sections = {
|
||||
left = {
|
||||
size = "20%",
|
||||
},
|
||||
mid = {
|
||||
size = "40%",
|
||||
},
|
||||
right = {
|
||||
preview = "leaf",
|
||||
},
|
||||
},
|
||||
},
|
||||
node_markers = {
|
||||
enabled = true,
|
||||
icons = {
|
||||
leaf = " ",
|
||||
leaf_selected = " → ",
|
||||
branch = " ",
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
[1] = " ", -- File
|
||||
[2] = " ", -- Module
|
||||
[3] = " ", -- Namespace
|
||||
[4] = " ", -- Package
|
||||
[5] = " ", -- Class
|
||||
[6] = " ", -- Method
|
||||
[7] = " ", -- Property
|
||||
[8] = " ", -- Field
|
||||
[9] = " ", -- Constructor
|
||||
[10] = "", -- Enum
|
||||
[11] = "", -- Interface
|
||||
[12] = " ", -- Function
|
||||
[13] = " ", -- Variable
|
||||
[14] = " ", -- Constant
|
||||
[15] = " ", -- String
|
||||
[16] = " ", -- Number
|
||||
[17] = "◩ ", -- Boolean
|
||||
[18] = " ", -- Array
|
||||
[19] = " ", -- Object
|
||||
[20] = " ", -- Key
|
||||
[21] = " ", -- Null
|
||||
[22] = " ", -- EnumMember
|
||||
[23] = " ", -- Struct
|
||||
[24] = " ", -- Event
|
||||
[25] = " ", -- Operator
|
||||
[26] = " ", -- TypeParameter
|
||||
[255] = " ", -- Macro
|
||||
},
|
||||
use_default_mappings = true,
|
||||
mappings = {
|
||||
["<esc>"] = actions.close(),
|
||||
["q"] = actions.close(),
|
||||
|
||||
["j"] = actions.next_sibling(),
|
||||
["k"] = actions.previous_sibling(),
|
||||
|
||||
["h"] = actions.parent(),
|
||||
["l"] = actions.children(),
|
||||
["0"] = actions.root(),
|
||||
|
||||
["v"] = actions.visual_name(),
|
||||
["V"] = actions.visual_scope(),
|
||||
|
||||
["y"] = actions.yank_name(),
|
||||
["Y"] = actions.yank_scope(),
|
||||
|
||||
["i"] = actions.insert_name(),
|
||||
["I"] = actions.insert_scope(),
|
||||
|
||||
["a"] = actions.append_name(),
|
||||
["A"] = actions.append_scope(),
|
||||
|
||||
["r"] = actions.rename(),
|
||||
|
||||
["d"] = actions.delete(),
|
||||
|
||||
["f"] = actions.fold_create(),
|
||||
["F"] = actions.fold_delete(),
|
||||
|
||||
["c"] = actions.comment(),
|
||||
|
||||
["<enter>"] = actions.select(),
|
||||
["o"] = actions.select(),
|
||||
|
||||
["J"] = actions.move_down(),
|
||||
["K"] = actions.move_up(),
|
||||
|
||||
["s"] = actions.toggle_preview(),
|
||||
|
||||
["<C-v>"] = actions.vsplit(),
|
||||
["<C-s>"] = actions.hsplit(),
|
||||
|
||||
["t"] = actions.telescope({
|
||||
layout_strategy = "horizontal",
|
||||
layout_config = {
|
||||
height = 0.60,
|
||||
width = 0.60,
|
||||
prompt_position = "top",
|
||||
preview_width = 0.50,
|
||||
},
|
||||
}),
|
||||
|
||||
["g?"] = actions.help(),
|
||||
},
|
||||
lsp = {
|
||||
auto_attach = false,
|
||||
preference = nil,
|
||||
},
|
||||
source_buffer = {
|
||||
follow_node = true,
|
||||
highlight = true,
|
||||
reorient = "smart",
|
||||
scrolloff = nil,
|
||||
},
|
||||
custom_hl_group = nil,
|
||||
}
|
||||
|
||||
setmetatable(config.icons, {
|
||||
__index = function()
|
||||
return "? "
|
||||
end,
|
||||
})
|
||||
|
||||
local navbuddy_attached_clients = {}
|
||||
|
||||
-- @Private Methods
|
||||
|
||||
local function choose_lsp_menu(for_buf, make_request)
|
||||
local style = nil
|
||||
|
||||
if config.window.border ~= nil and config.window.border ~= "None" then
|
||||
style = config.window.border
|
||||
else
|
||||
style = "single"
|
||||
end
|
||||
|
||||
local min_width = 23
|
||||
local lines = {}
|
||||
|
||||
for _, v in ipairs(navbuddy_attached_clients[for_buf]) do
|
||||
min_width = math.max(min_width, #v.name)
|
||||
table.insert(lines, nui_menu.item(v.id .. ":" .. v.name))
|
||||
end
|
||||
|
||||
local min_height = #lines
|
||||
|
||||
local menu = nui_menu({
|
||||
relative = "editor",
|
||||
position = "50%",
|
||||
border = {
|
||||
style = style,
|
||||
text = {
|
||||
top = "[Choose LSP Client]",
|
||||
top_align = "center",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
lines = lines,
|
||||
min_width = min_width,
|
||||
min_height = min_height,
|
||||
keymap = {
|
||||
focus_next = { "j", "<Down>", "<Tab>" },
|
||||
focus_prev = { "k", "<Up>", "<S-Tab>" },
|
||||
close = { "<Esc>", "q", "<C-c>" },
|
||||
submit = { "<CR>", "<Space>", "l" },
|
||||
},
|
||||
on_close = function() end,
|
||||
on_submit = function(item)
|
||||
local id = tonumber(string.match(item.text, "%d+"))
|
||||
for _, check_client in ipairs(navbuddy_attached_clients[for_buf]) do
|
||||
if id == check_client.id then
|
||||
make_request(check_client)
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
menu:mount()
|
||||
end
|
||||
|
||||
local function request(for_buf, handler)
|
||||
local function make_request(client)
|
||||
navic.request_symbol(for_buf, function(bufnr, symbols)
|
||||
navic.update_data(bufnr, symbols)
|
||||
navic.update_context(bufnr)
|
||||
local context_data = navic.get_context_data(bufnr)
|
||||
|
||||
local curr_node = context_data[#context_data]
|
||||
|
||||
handler(for_buf, curr_node, client.name)
|
||||
end, client)
|
||||
end
|
||||
|
||||
if navbuddy_attached_clients[for_buf] == nil then
|
||||
vim.notify("No lsp servers attached", vim.log.levels.ERROR)
|
||||
elseif #navbuddy_attached_clients[for_buf] == 1 then
|
||||
make_request(navbuddy_attached_clients[for_buf][1])
|
||||
elseif config.lsp.preference ~= nil then
|
||||
local found = false
|
||||
|
||||
for _, preferred_lsp in ipairs(config.lsp.preference) do
|
||||
for _, attached_lsp in ipairs(navbuddy_attached_clients[for_buf]) do
|
||||
if preferred_lsp == attached_lsp.name then
|
||||
navbuddy_attached_clients[for_buf] = { attached_lsp }
|
||||
found = true
|
||||
make_request(attached_lsp)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if found then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
choose_lsp_menu(for_buf, make_request)
|
||||
end
|
||||
else
|
||||
choose_lsp_menu(for_buf, make_request)
|
||||
end
|
||||
end
|
||||
|
||||
local function handler(bufnr, curr_node, lsp_name)
|
||||
if curr_node.is_root then
|
||||
if curr_node.children then
|
||||
local curr_line = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local closest_dist = math.abs(curr_line - curr_node.children[1].scope["start"].line)
|
||||
local closest_node = curr_node.children[1]
|
||||
|
||||
for _, node in ipairs(curr_node.children) do
|
||||
if math.abs(curr_line - node.scope["start"].line) < closest_dist then
|
||||
closest_dist = math.abs(curr_line - node.scope["start"].line)
|
||||
closest_node = node
|
||||
end
|
||||
end
|
||||
|
||||
curr_node = closest_node
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
display:new({
|
||||
for_buf = bufnr,
|
||||
for_win = vim.api.nvim_get_current_win(),
|
||||
start_cursor = vim.api.nvim_win_get_cursor(vim.api.nvim_get_current_win()),
|
||||
focus_node = curr_node,
|
||||
config = config,
|
||||
lsp_name = lsp_name,
|
||||
})
|
||||
end
|
||||
|
||||
-- @Public Methods
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.open(bufnr)
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
request(bufnr, handler)
|
||||
end
|
||||
|
||||
function M.attach(client, bufnr)
|
||||
if not client.server_capabilities.documentSymbolProvider then
|
||||
if not vim.g.navbuddy_silence then
|
||||
vim.notify(
|
||||
'nvim-navbuddy: Server "' .. client.name .. '" does not support documentSymbols.',
|
||||
vim.log.levels.ERROR
|
||||
)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if navbuddy_attached_clients[bufnr] == nil then
|
||||
navbuddy_attached_clients[bufnr] = {}
|
||||
end
|
||||
|
||||
-- Check if already attached
|
||||
for _, c in ipairs(navbuddy_attached_clients[bufnr]) do
|
||||
if c.id == client.id then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Check for stopped lsp servers
|
||||
for i, c in ipairs(navbuddy_attached_clients[bufnr]) do
|
||||
if c.is_stopped then
|
||||
table.remove(navbuddy_attached_clients[bufnr], i)
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(navbuddy_attached_clients[bufnr], client)
|
||||
|
||||
local navbuddy_augroup = vim.api.nvim_create_augroup("navbuddy", { clear = false })
|
||||
vim.api.nvim_clear_autocmds({
|
||||
buffer = bufnr,
|
||||
group = navbuddy_augroup,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("BufDelete", {
|
||||
callback = function()
|
||||
navic.clear_buffer_data(bufnr)
|
||||
navbuddy_attached_clients[bufnr] = nil
|
||||
end,
|
||||
group = navbuddy_augroup,
|
||||
buffer = bufnr,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("LspDetach", {
|
||||
callback = function()
|
||||
if navbuddy_attached_clients[bufnr] ~= nil then
|
||||
for i, c in ipairs(navbuddy_attached_clients[bufnr]) do
|
||||
if c.id == client.id then
|
||||
table.remove(navbuddy_attached_clients[bufnr], i)
|
||||
break
|
||||
end
|
||||
end
|
||||
if #navbuddy_attached_clients[bufnr] == 0 then
|
||||
navbuddy_attached_clients[bufnr] = nil
|
||||
end
|
||||
end
|
||||
end,
|
||||
group = navbuddy_augroup,
|
||||
buffer = bufnr,
|
||||
})
|
||||
|
||||
vim.api.nvim_buf_create_user_command(bufnr, "Navbuddy", function()
|
||||
M.open(bufnr)
|
||||
end, {})
|
||||
end
|
||||
|
||||
function M.setup(user_config)
|
||||
if user_config ~= nil then
|
||||
if user_config.window ~= nil then
|
||||
config.window = vim.tbl_deep_extend("keep", user_config.window, config.window)
|
||||
end
|
||||
|
||||
-- If one is set, default for others should be none
|
||||
if
|
||||
config.window.sections.left.border ~= nil
|
||||
or config.window.sections.mid.border ~= nil
|
||||
or config.window.sections.right.border ~= nil
|
||||
then
|
||||
config.window.sections.left.border = config.window.sections.left.border or "none"
|
||||
config.window.sections.mid.border = config.window.sections.mid.border or "none"
|
||||
config.window.sections.right.border = config.window.sections.right.border or "none"
|
||||
end
|
||||
|
||||
if user_config.node_markers ~= nil then
|
||||
config.node_markers = vim.tbl_deep_extend("keep", user_config.node_markers, config.node_markers)
|
||||
end
|
||||
|
||||
if user_config.icons ~= nil then
|
||||
for k, v in pairs(user_config.icons) do
|
||||
if navic.adapt_lsp_str_to_num(k) then
|
||||
config.icons[navic.adapt_lsp_str_to_num(k)] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if user_config.use_default_mappings ~= nil then
|
||||
config.use_default_mappings = user_config.use_default_mappings
|
||||
end
|
||||
|
||||
if user_config.mappings ~= nil then
|
||||
if config.use_default_mappings then
|
||||
config.mappings = vim.tbl_deep_extend("keep", user_config.mappings, config.mappings)
|
||||
else
|
||||
config.mappings = user_config.mappings
|
||||
end
|
||||
end
|
||||
|
||||
if user_config.lsp ~= nil then
|
||||
config.lsp = vim.tbl_deep_extend("keep", user_config.lsp, config.lsp)
|
||||
end
|
||||
|
||||
if user_config.source_buffer ~= nil then
|
||||
config.source_buffer = vim.tbl_deep_extend("keep", user_config.source_buffer, config.source_buffer)
|
||||
end
|
||||
|
||||
if user_config.custom_hl_group ~= nil then
|
||||
config.custom_hl_group = user_config.custom_hl_group
|
||||
end
|
||||
end
|
||||
|
||||
if config.lsp.auto_attach == true then
|
||||
local navbuddy_augroup = vim.api.nvim_create_augroup("navbuddy", { clear = false })
|
||||
vim.api.nvim_clear_autocmds({
|
||||
group = navbuddy_augroup,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("LspAttach", {
|
||||
callback = function(args)
|
||||
local bufnr = args.buf
|
||||
if args.data == nil and args.data.client_id == nil then
|
||||
return
|
||||
end
|
||||
local client = vim.lsp.get_client_by_id(args.data.client_id)
|
||||
if not client.server_capabilities.documentSymbolProvider then
|
||||
return
|
||||
end
|
||||
M.attach(client, bufnr)
|
||||
end,
|
||||
})
|
||||
|
||||
--- Attach to already active clients.
|
||||
local all_clients = vim.lsp.get_clients()
|
||||
|
||||
local supported_clients = vim.tbl_filter(function(client)
|
||||
return client.server_capabilities.documentSymbolProvider
|
||||
end, all_clients)
|
||||
|
||||
for _, client in ipairs(supported_clients) do
|
||||
local buffers_of_client = vim.lsp.get_buffers_by_client_id(client.id)
|
||||
|
||||
for _, buffer_number in ipairs(buffers_of_client) do
|
||||
M.attach(client, buffer_number)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,196 @@
|
||||
local navic = require("nvim-navic.lib")
|
||||
|
||||
local ui = {}
|
||||
|
||||
function ui.get_border_chars(style, section)
|
||||
if style ~= "single" and style ~= "rounded" and style ~= "double" and style ~= "solid" then
|
||||
return style
|
||||
end
|
||||
|
||||
-- stylua: ignore
|
||||
local border_chars = {
|
||||
top_left = {
|
||||
single = "┌",
|
||||
rounded = "╭",
|
||||
double = "╔",
|
||||
solid = "▛",
|
||||
},
|
||||
top = {
|
||||
single = "─",
|
||||
rounded = "─",
|
||||
double = "═",
|
||||
solid = "▀",
|
||||
},
|
||||
top_right = {
|
||||
single = "┐",
|
||||
rounded = "╮",
|
||||
double = "╗",
|
||||
solid = "▜",
|
||||
},
|
||||
right = {
|
||||
single = "│",
|
||||
rounded = "│",
|
||||
double = "║",
|
||||
solid = "▐",
|
||||
},
|
||||
bottom_right = {
|
||||
single = "┘",
|
||||
rounded = "╯",
|
||||
double = "╝",
|
||||
solid = "▟",
|
||||
},
|
||||
bottom = {
|
||||
single = "─",
|
||||
rounded = "─",
|
||||
double = "═",
|
||||
solid = "▄",
|
||||
},
|
||||
bottom_left = {
|
||||
single = "└",
|
||||
rounded = "╰",
|
||||
double = "╚",
|
||||
solid = "▙",
|
||||
},
|
||||
left = {
|
||||
single = "│",
|
||||
rounded = "│",
|
||||
double = "║",
|
||||
solid = "▌",
|
||||
},
|
||||
top_T = {
|
||||
single = "┬",
|
||||
rounded = "┬",
|
||||
double = "╦",
|
||||
solid = "▛",
|
||||
},
|
||||
bottom_T = {
|
||||
single = "┴",
|
||||
rounded = "┴",
|
||||
double = "╩",
|
||||
solid = "▙",
|
||||
},
|
||||
blank = "",
|
||||
}
|
||||
|
||||
local border_chars_map = {
|
||||
left = {
|
||||
style = {
|
||||
border_chars.top_left[style],
|
||||
border_chars.top[style],
|
||||
border_chars.top[style],
|
||||
border_chars.blank,
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom_left[style],
|
||||
border_chars.left[style],
|
||||
},
|
||||
},
|
||||
mid = {
|
||||
style = {
|
||||
border_chars.top_T[style],
|
||||
border_chars.top[style],
|
||||
border_chars.top[style],
|
||||
border_chars.blank,
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom_T[style],
|
||||
border_chars.left[style],
|
||||
},
|
||||
},
|
||||
right = {
|
||||
border_chars.top_T[style],
|
||||
border_chars.top[style],
|
||||
border_chars.top_right[style],
|
||||
border_chars.right[style],
|
||||
border_chars.bottom_right[style],
|
||||
border_chars.bottom[style],
|
||||
border_chars.bottom_T[style],
|
||||
border_chars.left[style],
|
||||
},
|
||||
}
|
||||
return border_chars_map[section]
|
||||
end
|
||||
|
||||
function ui.highlight_setup(config)
|
||||
for lsp_num = 1, 26 do
|
||||
local navbuddy_ok, _ =
|
||||
pcall(vim.api.nvim_get_hl_by_name, "Navbuddy" .. navic.adapt_lsp_num_to_str(lsp_num), false)
|
||||
local navic_ok, navic_hl =
|
||||
pcall(vim.api.nvim_get_hl_by_name, "NavicIcons" .. navic.adapt_lsp_num_to_str(lsp_num), true)
|
||||
|
||||
if not navbuddy_ok and navic_ok then
|
||||
navic_hl = navic_hl["foreground"]
|
||||
|
||||
vim.api.nvim_set_hl(0, "Navbuddy" .. navic.adapt_lsp_num_to_str(lsp_num), {
|
||||
fg = navic_hl,
|
||||
})
|
||||
end
|
||||
|
||||
local ok, navbuddy_hl =
|
||||
pcall(vim.api.nvim_get_hl_by_name, "Navbuddy" .. navic.adapt_lsp_num_to_str(lsp_num), true)
|
||||
if ok then
|
||||
navbuddy_hl = navbuddy_hl["foreground"]
|
||||
|
||||
local highlight
|
||||
if config.custom_hl_group ~= nil then
|
||||
highlight = { link = config.custom_hl_group }
|
||||
else
|
||||
highlight = { bg = navbuddy_hl }
|
||||
end
|
||||
vim.api.nvim_set_hl(0, "NavbuddyCursorLine" .. navic.adapt_lsp_num_to_str(lsp_num), highlight)
|
||||
else
|
||||
local _, normal_hl = pcall(vim.api.nvim_get_hl_by_name, "Normal", true)
|
||||
normal_hl = normal_hl["foreground"]
|
||||
vim.api.nvim_set_hl(0, "Navbuddy" .. navic.adapt_lsp_num_to_str(lsp_num), { fg = normal_hl })
|
||||
|
||||
local highlight
|
||||
if config.custom_hl_group ~= nil then
|
||||
highlight = { link = config.custom_hl_group }
|
||||
else
|
||||
highlight = { bg = normal_hl }
|
||||
end
|
||||
vim.api.nvim_set_hl(0, "NavbuddyCursorLine" .. navic.adapt_lsp_num_to_str(lsp_num), highlight)
|
||||
end
|
||||
end
|
||||
|
||||
local ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyCursorLine", false)
|
||||
if not ok then
|
||||
local highlight
|
||||
if config.custom_hl_group ~= nil then
|
||||
highlight = { link = config.custom_hl_group }
|
||||
else
|
||||
highlight = { reverse = true, bold = true }
|
||||
end
|
||||
vim.api.nvim_set_hl(0, "NavbuddyCursorLine", highlight)
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyCursor", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyCursor", {
|
||||
bg = "#000000",
|
||||
blend = 100,
|
||||
})
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyName", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyName", { link = "IncSearch" })
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyScope", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyScope", { link = "Visual" })
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyFloatBorder", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyFloatBorder", { link = "FloatBorder" })
|
||||
end
|
||||
|
||||
ok, _ = pcall(vim.api.nvim_get_hl_by_name, "NavbuddyNormalFloat", false)
|
||||
if not ok then
|
||||
vim.api.nvim_set_hl(0, "NavbuddyNormalFloat", { link = "NormalFloat" })
|
||||
end
|
||||
end
|
||||
|
||||
return ui
|
||||
Reference in New Issue
Block a user