Skip to content

Commit

Permalink
Merge pull request #147 from nanozuki/tab-jumper
Browse files Browse the repository at this point in the history
feat: magic jump
  • Loading branch information
nanozuki authored Jul 31, 2024
2 parents 8d0216f + 3674d3a commit 43d61e7
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 33 deletions.
71 changes: 59 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

# tabby.nvim

A declarative, highly configurable, and neovim style tabline plugin. Use your
nvim tabs as a workspace multiplexer!
A highly configurable, and neovim style tabline plugin. Use your nvim tabs as
a workspace multiplexer!

![](https://raw.githubusercontent.com/wiki/nanozuki/tabby.nvim/assets/banner.png)

Expand All @@ -26,13 +26,13 @@ changes will be introduced.
At next major version, v3, `tabby.nvim` will cleaner all deprecated apis and
remove all vimscript.

## Concept
## Features

**A line for the vim tab page, not for buffers**
### Tabline, not bufferline

A tab page in vim holds one or more windows(not buffers). You can easily switch
between tab pages to have several collections of windows to work on different
things.
A line for the vim tab page, not for buffers. A tabpage in vim holds one or
more windows(not buffers). You can easily switch between tab pages to have
several collections of windows to work on different things.

Tabline can help you use multiple tabs. Meanwhile, the bufferline is simply an
array of opened files. As a result, Bufferline limits the power of vim,
Expand All @@ -47,12 +47,46 @@ For example, you are writing a backend service:
- Tab4: Neogit.nvim
```

**Declarative, highly configurable**
### Highly configurable

Tabby provides a declarative way to configure tabline. You can set the tabline
to whatever neovim natively supports and complete the config with any lua code.
At least that's the goal of tabby. And also, the tabby provides some presets to
quick start or as your example.
Tabby provides a highly configurable way to set up your personalized tabline.
There is no DSL for config; you can write any lua codes following the type hint.
But also, Tabby provides some presets for quick start and as your example.

### Tab rename

You can rename a tab by `Tabby rename_tab <tabname>`. Display the tab name by
`tab.name()` (reference: [Tab](#Tab)) in your config. Config fallback name by
[Line-Option](#Line-Option)

### Window picker

Use command `Tabby pick_window` to open a selector to pick window in tabpages.
This picker use native neovim selector, you can use a general UI plugin to
enhance the appearance.

### Jump mode for tabs

Inspired by [barbar.nvim](https://github.com/romgrk/barbar.nvim?tab=readme-ov-file#jump-to-buffer-mode).
Type one key to jump to a tabpage.

<!-- panvimdoc-ignore-start -->

![](https://github.com/nanozuki/tabby.nvim/wiki/assets/tab-jump-mode.png)

<!-- panvimdoc-ignore-end -->

Use command `Tabby jump_to_tab` to get into jump mode. In jump mode, each tab
have a key which displayed in tabline by `tab.jump_key()`. You can check if in
jump mode by `tab.in_jump_mode()`. (reference: [Tab](#Tab))

For example in your config:

```lua
tab.in_jump_mode() and tab.jump_key() or tab.number()
```

The jump char is also displayed in presets.

## Playground

Expand Down Expand Up @@ -183,6 +217,8 @@ If you want to quick start? That's fine, you can [Use Preset Configs](#Use-Prese
- `Tabby rename_tab <tabname>`: Rename tab. Use name in line by `tab.name()`
(ref: [Tab](#Tab)). Config fallback name by [Line-Option](#Line-Option)
- `Tabby pick_window`: Open a selector to pick window in tabpages.
- `Tabby jump_to_tab`: Get one key to jump to tabpage, each keys are displayed
in tabline by `tab.jump_key()`

### Key mapping example

Expand Down Expand Up @@ -427,6 +463,17 @@ tab.close_btn({symbol}) *tabby.tab.close_btn()*
Return: ~
Node |tabby-node|, close button node.
tab.jump_key() *tabby.tab.jump_key()*
In jump mode, return a key to jump to this tab, otherwise return empty
string.
Return: ~
String, a key to jump to this tab.
tab.in_jump_mode() *tabby.tab.in_jump_mode()*
Return: ~
Boolean, if this tab is in jump mode.
```

### Win
Expand Down
75 changes: 64 additions & 11 deletions doc/tabby.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
Table of Contents *tabby-table-of-contents*

1. Compatibility and Versions |tabby-compatibility-and-versions|
2. Concept |tabby-concept|
2. Features |tabby-features|
- Tabline, not bufferline |tabby-features-tabline,-not-bufferline|
- Highly configurable |tabby-features-highly-configurable|
- Tab rename |tabby-features-tab-rename|
- Window picker |tabby-features-window-picker|
- Jump mode for tabs |tabby-features-jump-mode-for-tabs|
3. Playground |tabby-playground|
4. Install |tabby-install|
5. Setup |tabby-setup|
Expand Down Expand Up @@ -46,13 +51,14 @@ remove all vimscript.


==============================================================================
2. Concept *tabby-concept*
2. Features *tabby-features*

**A line for the vim tab page, not for buffers**

A tab page in vim holds one or more windows(not buffers). You can easily switch
between tab pages to have several collections of windows to work on different
things.
TABLINE, NOT BUFFERLINE *tabby-features-tabline,-not-bufferline*

A line for the vim tab page, not for buffers. A tabpage in vim holds one or
more windows(not buffers). You can easily switch between tab pages to have
several collections of windows to work on different things.

Tabline can help you use multiple tabs. Meanwhile, the bufferline is simply an
array of opened files. As a result, Bufferline limits the power of vim,
Expand All @@ -67,12 +73,46 @@ For example, you are writing a backend service:
- Tab4: Neogit.nvim
<

**Declarative, highly configurable**

Tabby provides a declarative way to configure tabline. You can set the tabline
to whatever neovim natively supports and complete the config with any lua code.
At least that’s the goal of tabby. And also, the tabby provides some presets
to quick start or as your example.
HIGHLY CONFIGURABLE *tabby-features-highly-configurable*

Tabby provides a highly configurable way to set up your personalized tabline.
There is no DSL for config; you can write any lua codes following the type
hint. But also, Tabby provides some presets for quick start and as your
example.


TAB RENAME *tabby-features-tab-rename*

You can rename a tab by `Tabby rename_tab <tabname>`. Display the tab name by
`tab.name()` (reference: |tabby-tab|) in your config. Config fallback name by
|tabby-line-option|


WINDOW PICKER *tabby-features-window-picker*

Use command `Tabby pick_window` to open a selector to pick window in tabpages.
This picker use native neovim selector, you can use a general UI plugin to
enhance the appearance.


JUMP MODE FOR TABS *tabby-features-jump-mode-for-tabs*

Inspired by barbar.nvim
<https://github.com/romgrk/barbar.nvim?tab=readme-ov-file#jump-to-buffer-mode>.
Type one key to jump to a tabpage.

Use command `Tabby jump_to_tab` to get into jump mode. In jump mode, each tab
have a key which displayed in tabline by `tab.jump_key()`. You can check if in
jump mode by `tab.in_jump_mode()`. (reference: |tabby-tab|)

For example in your config:

>lua
tab.in_jump_mode() and tab.jump_key() or tab.number()
<

The jump char is also displayed in presets.


==============================================================================
Expand Down Expand Up @@ -218,6 +258,8 @@ COMMANDS *tabby-setup-commands*
- `Tabby rename_tab <tabname>`: Rename tab. Use name in line by `tab.name()`
(ref: |tabby-tab|). Config fallback name by |tabby-line-option|
- `Tabby pick_window`: Open a selector to pick window in tabpages.
- `Tabby jump_to_tab`: Get one key to jump to tabpage, each keys are displayed
in tabline by `tab.jump_key()`


KEY MAPPING EXAMPLE *tabby-setup-key-mapping-example*
Expand Down Expand Up @@ -466,6 +508,17 @@ tab.close_btn({symbol}) *tabby.tab.close_btn()*
Return: ~
Node |tabby-node|, close button node.

tab.jump_key() *tabby.tab.jump_key()*
In jump mode, return a key to jump to this tab, otherwise return empty
string.

Return: ~
String, a key to jump to this tab.

tab.in_jump_mode() *tabby.tab.in_jump_mode()*
Return: ~
Boolean, if this tab is in jump mode.


WIN *tabby-customize-win*

Expand Down
78 changes: 78 additions & 0 deletions lua/tabby/feature/tab_jumper.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
local tab_jumper = {
line = nil,
char_to_tabid = {}, ---@type table<string,number>
tabid_to_char = {}, ---@type table<number,string>
is_start = false,
}

local alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

---@param line TabbyLine
function tab_jumper.pre_render(line)
tab_jumper.line = line
end

function tab_jumper.reset()
tab_jumper.char_to_tabid = {}
tab_jumper.tabid_to_char = {}
end

function tab_jumper.build_indexes()
if tab_jumper.line == nil then
return
end
local tabs = tab_jumper.line.tabs().tabs

-- use the first, not used char of tab's name
for _, tab in ipairs(tabs) do
local name = tab.name()
for i = 1, #name do
local char = name:sub(i, i):upper()
if tab_jumper.char_to_tabid[char] == nil then
tab_jumper.char_to_tabid[char] = tab.id
tab_jumper.tabid_to_char[tostring(tab.id)] = char
break
end
end
end

-- then, for the remain tabs, use the first, not used char of alphabet
for _, tab in ipairs(tabs) do
if tab_jumper.tabid_to_char[tostring(tab.id)] == nil then
for i = 1, #alphabet do
local char = alphabet:sub(i, i)
if tab_jumper.char_to_tabid[char] == nil then
tab_jumper.char_to_tabid[char] = tab.id
tab_jumper.tabid_to_char[tostring(tab.id)] = char
break
end
end
end
end
end

function tab_jumper.get_char(tabid)
local char = tab_jumper.tabid_to_char[tostring(tabid)] or '??'
return char
end

function tab_jumper.start()
tab_jumper.build_indexes()
tab_jumper.is_start = true

vim.cmd.redrawtabline()
local ok, tabid = pcall(function()
local c = string.char(vim.fn.getchar()):upper()
return tab_jumper.char_to_tabid[c]
end)

tab_jumper.is_start = false
tab_jumper.reset()
if ok and tabid then
vim.api.nvim_set_current_tabpage(tabid)
else
vim.cmd.redrawtabline()
end
end

return tab_jumper
12 changes: 12 additions & 0 deletions lua/tabby/feature/tabwins.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local tabwins = {}

local api = require('tabby.module.api')
local tab_jumper = require('tabby.feature.tab_jumper')

---@class TabbyTab
---@field id number tabid
Expand All @@ -10,6 +11,8 @@ local api = require('tabby.module.api')
---@field is_current fun():boolean return if this tab is current tab
---@field name fun():string return tab name
---@field close_btn fun(symbol:string):TabbyNode return close btn
---@field in_jump_mode fun():boolean return if tab is in jump mode
---@field jump_key fun():TabbyNode return jumper

---new TabbyTab
---@param tabid number
Expand Down Expand Up @@ -48,6 +51,15 @@ function tabwins.new_tab(tabid, opt)
return ''
end
end,
in_jump_mode = function()
return tab_jumper.is_start
end,
jump_key = function()
if tab_jumper.is_start then
return tab_jumper.get_char(tabid)
end
return ''
end,
}
end

Expand Down
2 changes: 1 addition & 1 deletion lua/tabby/module/node.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
---@field lo? TabbyLayout
---@field click? TabbyClickHandler
---@field margin? string
---@field [...] TabbyNode[] children node
---@field [...] TabbyNode children node

---@class TabbyLayout
---@field justify? 'left'|'right' justify @default 'left'
Expand Down
Loading

0 comments on commit 43d61e7

Please sign in to comment.