Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 166 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Requires neovim >= 0.10.

### Navigation

The following table lists the treeclimber navigation commands, along with their default keybindings.
See [Configuration](#configuration) for details on changing the defaults.

| Key binding | Action | Demo |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `alt-h` | Select the previous sibling node. | ![select-prev](https://user-images.githubusercontent.com/3162299/203088192-5c3a7f49-aa8f-4927-b9f2-1dc9c5245364.gif) |
Expand Down Expand Up @@ -46,44 +49,190 @@ https://user-images.githubusercontent.com/3162299/203097777-a9a84c2d-8dec-4db8-a

## Installation

Use your preferred package manager, or the built-in package system (`:help packages`).
User your preferred package manager, or the built-in package system (`:help packages`).

### [lazy.nvim](https://github.com/folke/lazy.nvim)

```lua
{
"dkendal/nvim-treeclimber",
opts = {
-- Provide your desired configuration here, or leave empty to use defaults.
-- See Configuration section for details...
},
}
```

### Manual installation

#### Installation via Bash command-line

```sh
mkdir -p ~/.config/nvim/pack/dkendal/opt
cd ~/.config/nvim/pack/dkendal/opt
git clone https://github.com/dkendal/nvim-treeclimber.git
```

#### Loading via Neovim package system

```lua
-- ~/.config/nvim/init.lua
vim.cmd.packadd('nvim-treeclimber')

require('nvim-treeclimber').setup()
require('nvim-treeclimber').setup({ --[[ your config here ]] })
```

If you want to change the default keybindings, call `require('nvim-treeclimber')` rather than calling setup.
See [configuration](#configuration).
**Note:** If you call the `setup()` function without arguments, treeclimber uses the defaults documented in the following section.

## Configuration

**To use default highlight, keymaps, and commands call `require('nvim-treeclimber').setup()`.**
To override specific elements of the default configuration, provide a sparse option table containing only the keys you wish to change.
The default option table is provided below, with comments documenting the meanings of the various keys.
Any table you provide to `setup()` will be merged into this one, with preference given to your override.
If your override has an invalid format, treeclimber will generally emit a warning and fall back to the default setting.

To manually specify the configuration options, take a look at the contents of `lua/nvim-treeclimber.lua` and import or modify the portions that you need.

For example, if you just want the built in user commands and highlights but you want your own keybindings, you can do the following:
### Default Option Table

```lua
{
ui = {
-- ** Keymaps **
-- Each entry of the 'keys' table configures the keymap for a single treeclimber function.
-- Note: The `keys` key itself can be set to a boolean to enable defaults or disable keymaps
-- altogether.
---@alias modestr "n"|"v"|"x"|"o"|"s"|"i"|"!"|""
---@alias lhs string # Used as <lhs> in call to `vim.keymap.set`
---@alias KeymapSingle
---| [(modestr|modestr[]), lhs] # override the default <lhs> and/or modes
---@alias KeymapEntry
---| boolean # true to accept default, false to disable
---| nil # accept default (same as omitting the command name from table)
---| lhs # override the default <lhs> in default mode(s)
---| KeymapSingle # override the default <lhs> and/or modes
---| KeymapSingle[] # idem, but allows multiple, mode-specific <lhs>'s
---@type table<string, KeymapEntry>
keys = {
show_control_flow = { "n", "<leader>k"},
select_current_node = {
{"n", "<M-k>"},
{{ "x", "o" }, "i."}
},
select_first_sibling = {{ "n", "x", "o" }, "<M-[>"},
select_last_sibling = {{ "n", "x", "o" }, "<M-]>"},
select_top_level = {{ "n", "x", "o" }, "<M-g>"},
select_forward = {{ "n", "x", "o" }, "<M-l>"},
select_backward = {{ "n", "x", "o" }, "<M-h>"},
select_forward_end = {{ "n", "x", "o" }, "<M-e>"},
select_grow_forward = {{ "n", "x", "o" }, "<M-L>"},
select_grow_backward = {{ "n", "x", "o" }, "<M-H>"},
select_expand = {
{{"x", "o"}, "a."},
{{"x", "o"}, "<M-k>"}
},
select_shrink = {{ "n", "x", "o" }, "<M-j>"},
},

-- ** User commands **
-- Each entry of the 'cmds table configures the user command for a single treeclimber function.
-- Note: The 'cmds' key itself can be set to a boolean to enable the defaults or disable user
-- commands altogether.
---@alias UserCommandEntry
---| string # desired name of the user command for this function
---| boolean # true to create the command with the default name, false to disable
---@type {[string]: UserCommandEntry}|boolean
cmds = {
diff_this = "TCDiffThis",
highlight_external_definitions = "TCHighlightExternalDefinitions",
show_control_flow = "TCShowControlFlow",
},
},

-- ** Display **
display = {
regions = {
-- Each entry in the table below defines the highlighting applied to one of several regions
-- relative to the current selection and its siblings/parent. To override the highlighting
-- for a specific region, set the corresponding key to either a `vim.api.keyset.highlight` or
-- a callback function that returns one. The callback will be invoked upon colorscheme load
-- with an `HSLUVHighlights` object that may be used to "mix" new colors from the currently
-- active normal and visual mode fg/bg colors.
-- Important Note: The `HSLUV` class provides many color-manipulation methods in addition to
-- the `mix()` method used in the defaults. The class's type annotation is provided in the
-- next section. Additional detail may be found in "vivid/hsl_like.lua" in the treeclimber
-- source.
-- Note: The `vim.api.keyset.highlight` can be used to specify more than just fg/bg colors:
-- e.g., the following override would make the currently selected region bold and its siblings
-- italic:
-- highlights = {
-- Selection = {bold = true},
-- Sibling = {italic = true)
-- }
-- Note: You can also disable unwanted regions by setting the corresponding key(s) `false`.
-- E.g., to disable all but the primary selection region (Selection)...
-- highlights = {
-- SiblingStart = false, Sibling = false, Parent = false, ParentStart = false
-- }
---@alias HSLUVHighlight {bg: HSLUV?, fg: HSLUV?, ctermbg: HSLUV?, ctermfg: HSLUV?}
---@alias HSLUVHighlights {normal: HSLUVHighlight, visual: HSLUVHighlight}
---@alias HighlightCallback fun(o: HSLUVHighlights) : vim.api.keyset.highlight
---@alias HighlightEntry
---| vim.api.keyset.highlight # passed to `nvim_set_hl()`
---| HighlightCallback # must return a `vim.api.keyset.highlight`
---| boolean # true for default highlighting, false to disable the group
---| nil # default highlighting
---@type table<string, HighlightEntry>
highlights = {
Selection = function(o) return { bold = true, bg = o.visual.bg.hex } end,
SiblingStart = false,
Sibling = function(o) return { bg = o.visual.bg.mix(o.normal.bg, 50).hex } end,
-- Make Parent bg color noticeably lighter than Siblings.
Parent = function(o) return { bg = o.visual.bg.mix(o.normal.bg, 80).hex } end,
ParentStart = false,
},
Comment on lines +183 to +190

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of having these highlights configurable - however the choice of the current normal and visual highlight feels arbitrary. I would prefer either make the callback accept 0 parameters, or have one parameter which is the hsluv module.

I'm somewhat of the mind that it's more flexible to not include this in configuration, beyond static values - and just provide an example in the readme on how to define an autocommand that sets the highlights when the colourscheme changes.

-- `true` to cause attributes like bold and italic to "bleed through" from Parent
-- to Siblings.
inherit_attrs = true,
-- `true` to replace default 'highlights' with user overrides, false or nil to merge
replace_defaults = false,
Comment on lines +191 to +195

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to the comments above, I would prefer to not introduce any custom configuration DSL, as it increases the documentation and learning surface area. I'm okay with exposing options that are just delegates to vim api functions, but for anything more advanced I'd prefer to only provide example in the README.

This is inline with the advice here.

},
},
}
```

local tc = require('nvim-treeclimber')
### HSLUV Color Support

tc.setup_augroups()
tc.setup_user_commands()
As mentioned in the default option comments, an object of type `HSLUV` is made available to the `highlights` option callback functions.
This object facilitates working with *HSL* colors in the more human-friendly *HSLUV* color space.
Its methods and fields are shown here. For further details, look in the treeclimber source (vivid/hsl_like.lua).

-- Copied from setup_keymaps
vim.keymap.set("n", "<leader>k", tc.show_control_flow, {})
vim.keymap.set({ "x", "o" }, "i.", tc.select_current_node, { desc = "select current node" })
vim.keymap.set({ "x", "o" }, "a.", tc.select_expand, { desc = "select parent node" })
...
```lua
---@class HSLUV
---@field hex string
---@field h number
---@field s number
---@field l number
---@field rotate fun(n: number): HSLUV
---@field ro fun(n: number): HSLUV
---@field saturate fun(n: number): HSLUV
---@field sa fun(n: number): HSLUV
---@field abs_saturate fun(n: number): HSLUV
---@field abs_sa fun(n: number): HSLUV
---@field desaturate fun(n: number): HSLUV
---@field de fun(n: number): HSLUV
---@field abs_desaturate fun(n: number): HSLUV
---@field abs_de fun(n: number): HSLUV
---@field lighten fun(n: number): HSLUV
---@field li fun(n: number): HSLUV
---@field abs_lighten fun(n: number): HSLUV
---@field abs_li fun(n: number): HSLUV
---@field darken fun(n: number): HSLUV
---@field da fun(n: number): HSLUV
---@field abs_darken fun(n: number): HSLUV
---@field abs_da fun(n: number): HSLUV
---@field mix fun(color: HSLUV, n: number): HSLUV
---@field readable fun(): HSLUV
---@field hue fun(n: number): HSLUV
---@field saturation fun(n: number): HSLUV
---@field lightness fun(n: number): HSLUV
```

---
Expand Down
Loading