mirror of
https://github.com/kristoferssolo/solorice.git
synced 2026-02-04 06:32:03 +00:00
Use dotter
This commit is contained in:
19
config/yazi/plugins/relative-motions.yazi/LICENSE
Normal file
19
config/yazi/plugins/relative-motions.yazi/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2024 dedukun
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
167
config/yazi/plugins/relative-motions.yazi/README.md
Normal file
167
config/yazi/plugins/relative-motions.yazi/README.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# relative-motions.yazi
|
||||
|
||||
A [Yazi](https://github.com/sxyazi/yazi) plugin based about vim motions.
|
||||
|
||||
https://github.com/dedukun/relative-motions.yazi/assets/25795432/04fb186a-5efe-442d-8d7b-2dccb6eee408
|
||||
|
||||
## Requirements
|
||||
|
||||
- [Yazi](https://github.com/sxyazi/yazi) v0.2.4+
|
||||
|
||||
## Installation
|
||||
|
||||
<details>
|
||||
<summary>Yazi v0.2.5 and before (manual installation)</summary>
|
||||
|
||||
```sh
|
||||
# Linux/macOS
|
||||
git clone https://github.com/dedukun/relative-motions.yazi.git ~/.config/yazi/plugins/relative-motions.yazi
|
||||
|
||||
# Windows
|
||||
git clone https://github.com/dedukun/relative-motions.yazi.git %AppData%\yazi\config\plugins\relative-motions.yazi
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Latest commit in Yazi (package manager)</summary>
|
||||
|
||||
```sh
|
||||
# Add the plugin
|
||||
ya pack -a dedukun/relative-motions
|
||||
|
||||
# Install plugin
|
||||
ya pack -i
|
||||
|
||||
# Update plugin
|
||||
ya pack -u
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Configuration
|
||||
|
||||
If you want to use the numbers directly to start a motion add this to your `keymap.toml`:
|
||||
|
||||
<details>
|
||||
|
||||
```toml
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "1" ]
|
||||
run = "plugin relative-motions --args=1"
|
||||
desc = "Move in relative steps"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "2" ]
|
||||
run = "plugin relative-motions --args=2"
|
||||
desc = "Move in relative steps"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "3" ]
|
||||
run = "plugin relative-motions --args=3"
|
||||
desc = "Move in relative steps"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "4" ]
|
||||
run = "plugin relative-motions --args=4"
|
||||
desc = "Move in relative steps"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "5" ]
|
||||
run = "plugin relative-motions --args=5"
|
||||
desc = "Move in relative steps"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "6" ]
|
||||
run = "plugin relative-motions --args=6"
|
||||
desc = "Move in relative steps"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "7" ]
|
||||
run = "plugin relative-motions --args=7"
|
||||
desc = "Move in relative steps"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "8" ]
|
||||
run = "plugin relative-motions --args=8"
|
||||
desc = "Move in relative steps"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "9" ]
|
||||
run = "plugin relative-motions --args=9"
|
||||
desc = "Move in relative steps"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Alternatively you can use a key to trigger a new motion without any initial value, for that add the following in `keymap.toml`:
|
||||
|
||||
```toml
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "m" ]
|
||||
run = "plugin relative-motions"
|
||||
desc = "Trigger a new relative motion"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Additionally there are a couple of initial configurations that can be given to the plugin's `setup` function:
|
||||
|
||||
| Configuration | Values | Default | Description |
|
||||
| -------------- | ----------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `show_numbers` | `relative`, `absolute`, `relative_absolute` or `none` | `none` | Shows relative or absolute numbers before the file icon |
|
||||
| `show_motion` | `true` or `false` | `false` | Shows current motion in Status bar |
|
||||
| `only_motions` | `true` or `false` | `false` | If true, only the motion movements will be enabled, i.e., the commands for delete, cut, yank and visual selection will be disabled |
|
||||
|
||||
If you want, for example, to enable relative numbers as well as to show the motion in the status bar,
|
||||
add the following to Yazi's `init.lua`, i.e. `~/.config/yazi/init.lua`:
|
||||
|
||||
```lua
|
||||
-- ~/.config/yazi/init.lua
|
||||
require("relative-motions"):setup({ show_numbers="relative", show_motion = true })
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> The `show_numbers` and `show_motion` functionalities overwrite [`Current:render`](https://github.com/sxyazi/yazi/blob/e51e8ad789914b2ab4a9485da7aa7fbc7b3bb450/yazi-plugin/preset/components/current.lua#L5)
|
||||
> and [`Status:render`](https://github.com/sxyazi/yazi/blob/e51e8ad789914b2ab4a9485da7aa7fbc7b3bb450/yazi-plugin/preset/components/status.lua#L111) respectively.
|
||||
> If you have custom implementations for any of this functions
|
||||
> you can add the provided `File:number` and `Status:motion` to your implementations, just check [here](https://github.com/dedukun/relative-motions.yazi/blob/main/init.lua#L39) how we are doing things.
|
||||
|
||||
## Usage
|
||||
|
||||
This plugin adds the some basic vim motions like `3k`, `12j`, `10gg`, etc.
|
||||
The following table show all the available motions:
|
||||
|
||||
| Command | Description |
|
||||
| -------------- | ------------------- |
|
||||
| `j`/`<Down>` | Move `n` lines down |
|
||||
| `k`/`<Up>` | Move `n` lines up |
|
||||
| `gj`/`g<Down>` | Go `n` lines down |
|
||||
| `gk`/`g<Up>` | Go `n` lines up |
|
||||
| `gg` | Go to line |
|
||||
|
||||
Furthermore, the following operations were also added:
|
||||
|
||||
| Command | Description |
|
||||
| ------- | ------------- |
|
||||
| `v` | visual select |
|
||||
| `y` | Yank |
|
||||
| `x` | Cut |
|
||||
| `d` | Delete motion |
|
||||
|
||||
This however must be followed by a direction, which can be `j`/`<Down>`, `k`/`<Up>` or repeating the command key,
|
||||
which will operate from the cursor down, e.g. `2yy` will copy two files.
|
||||
|
||||
Finally, we also support some tab operations:
|
||||
|
||||
| Command | Description |
|
||||
| ------- | ------------------------------------ |
|
||||
| `t` | create `n` tabs |
|
||||
| `H` | Move `n` tabs left |
|
||||
| `L` | Move `n` tabs right |
|
||||
| `gt` | Go to the `n` tab |
|
||||
| `w` | Close tab `n` |
|
||||
| `W` | Close `n` tabs right |
|
||||
| `<` | Swap current tab with `n` tabs left |
|
||||
| `>` | Swap current tab with `n` tabs right |
|
||||
| `~` | Swap current tab with tab `n` |
|
||||
330
config/yazi/plugins/relative-motions.yazi/init.lua
Normal file
330
config/yazi/plugins/relative-motions.yazi/init.lua
Normal file
@@ -0,0 +1,330 @@
|
||||
-- stylua: ignore
|
||||
local MOTIONS_AND_OP_KEYS = {
|
||||
{ on = "0" }, { on = "1" }, { on = "2" }, { on = "3" }, { on = "4" },
|
||||
{ on = "5" }, { on = "6" }, { on = "7" }, { on = "8" }, { on = "9" },
|
||||
-- commands
|
||||
{ on = "d" }, { on = "v" }, { on = "y" }, { on = "x" },
|
||||
-- tab commands
|
||||
{ on = "t" }, { on = "L" }, { on = "H" }, { on = "w" },
|
||||
{ on = "W" }, { on = "<" }, { on = ">" }, { on = "~" },
|
||||
-- movement
|
||||
{ on = "g" }, { on = "j" }, { on = "k" }, { on = "<Down>" }, { on = "<Up>" }
|
||||
}
|
||||
|
||||
-- stylua: ignore
|
||||
local MOTION_KEYS = {
|
||||
{ on = "0" }, { on = "1" }, { on = "2" }, { on = "3" }, { on = "4" },
|
||||
{ on = "5" }, { on = "6" }, { on = "7" }, { on = "8" }, { on = "9" },
|
||||
-- movement
|
||||
{ on = "g" }, { on = "j" }, { on = "k" }
|
||||
}
|
||||
|
||||
-- stylua: ignore
|
||||
local DIRECTION_KEYS = {
|
||||
{ on = "j" }, { on = "k" }, { on = "<Down>" }, { on = "<Up>" },
|
||||
-- tab movement
|
||||
{ on = "t" }
|
||||
}
|
||||
|
||||
local SHOW_NUMBERS_ABSOLUTE = 0
|
||||
local SHOW_NUMBERS_RELATIVE = 1
|
||||
local SHOW_NUMBERS_RELATIVE_ABSOLUTE = 2
|
||||
|
||||
-----------------------------------------------
|
||||
----------------- R E N D E R -----------------
|
||||
-----------------------------------------------
|
||||
|
||||
local render_motion_setup = ya.sync(function()
|
||||
ya.render()
|
||||
|
||||
Status.motion = function() return ui.Span("") end
|
||||
|
||||
Status.render = function(self, area)
|
||||
self.area = area
|
||||
|
||||
local left = ui.Line { self:mode(), self:size(), self:name() }
|
||||
local right = ui.Line { self:motion(), self:permissions(), self:percentage(), self:position() }
|
||||
return {
|
||||
ui.Paragraph(area, { left }),
|
||||
ui.Paragraph(area, { right }):align(ui.Paragraph.RIGHT),
|
||||
table.unpack(Progress:render(area, right:width())),
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
||||
local render_motion = ya.sync(function(_, motion_num, motion_cmd)
|
||||
ya.render()
|
||||
|
||||
Status.motion = function(self)
|
||||
if not motion_num then
|
||||
return ui.Span("")
|
||||
end
|
||||
|
||||
local style = self.style()
|
||||
|
||||
local motion_span
|
||||
if not motion_cmd then
|
||||
motion_span = ui.Span(string.format(" %3d ", motion_num)):style(style)
|
||||
else
|
||||
motion_span = ui.Span(string.format(" %3d%s ", motion_num, motion_cmd)):style(style)
|
||||
end
|
||||
|
||||
return ui.Line {
|
||||
ui.Span(THEME.status.separator_open):fg(style.bg),
|
||||
motion_span,
|
||||
ui.Span(THEME.status.separator_close):fg(style.bg),
|
||||
ui.Span(" "),
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
||||
local render_numbers = ya.sync(function(_, mode)
|
||||
ya.render()
|
||||
|
||||
File.number = function(_, index, file, hovered)
|
||||
local idx
|
||||
if mode == SHOW_NUMBERS_RELATIVE then
|
||||
idx = math.abs(hovered - index)
|
||||
elseif mode == SHOW_NUMBERS_ABSOLUTE then
|
||||
idx = file.idx
|
||||
else -- SHOW_NUMBERS_RELATIVE_ABSOLUTE
|
||||
if hovered == index then
|
||||
idx = file.idx
|
||||
else
|
||||
idx = math.abs(hovered - index)
|
||||
end
|
||||
end
|
||||
|
||||
-- emulate vim's hovered offset
|
||||
if idx >= 100 then
|
||||
return ui.Span(string.format("%4d ", idx))
|
||||
elseif hovered == index then
|
||||
return ui.Span(string.format("%3d ", idx))
|
||||
else
|
||||
return ui.Span(string.format(" %3d ", idx))
|
||||
end
|
||||
end
|
||||
|
||||
Current.render = function(self, area)
|
||||
self.area = area
|
||||
|
||||
local files = Folder:by_kind(Folder.CURRENT).window
|
||||
if #files == 0 then
|
||||
return self:empty(area)
|
||||
end
|
||||
|
||||
local hovered_index
|
||||
for i, f in ipairs(files) do
|
||||
if f:is_hovered() then
|
||||
hovered_index = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local items, markers = {}, {}
|
||||
for i, f in ipairs(files) do
|
||||
items[#items + 1] = ui.ListItem(ui.Line(ya.flat { File:number(i, f, hovered_index), File:full(f) }))
|
||||
:style(File:style(f))
|
||||
|
||||
-- Yanked/marked/selected files
|
||||
local marker = File:marker(f)
|
||||
if marker ~= 0 then
|
||||
markers[#markers + 1] = { i, marker }
|
||||
end
|
||||
end
|
||||
|
||||
return ya.flat {
|
||||
ui.List(area, items),
|
||||
Folder:linemode(area, files),
|
||||
Folder:markers(area, markers),
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
||||
local function render_clear() render_motion() end
|
||||
|
||||
-----------------------------------------------
|
||||
--------- C O M M A N D P A R S E R ---------
|
||||
-----------------------------------------------
|
||||
|
||||
local get_keys = ya.sync(function(state) return state._only_motions and MOTION_KEYS or MOTIONS_AND_OP_KEYS end)
|
||||
|
||||
local function normal_direction(dir)
|
||||
if dir == "<Down>" then
|
||||
return "j"
|
||||
elseif dir == "<Up>" then
|
||||
return "k"
|
||||
end
|
||||
return dir
|
||||
end
|
||||
|
||||
local function get_cmd(first_char, keys)
|
||||
local last_key
|
||||
local lines = first_char or ""
|
||||
|
||||
while true do
|
||||
render_motion(tonumber(lines))
|
||||
local key = ya.which { cands = keys, silent = true }
|
||||
if not key then
|
||||
return nil, nil, nil
|
||||
end
|
||||
|
||||
last_key = keys[key].on
|
||||
if not tonumber(last_key) then
|
||||
last_key = normal_direction(last_key)
|
||||
break
|
||||
end
|
||||
|
||||
lines = lines .. last_key
|
||||
end
|
||||
|
||||
render_motion(tonumber(lines), last_key)
|
||||
|
||||
-- command direction
|
||||
local direction
|
||||
if last_key == "g" or last_key == "v" or last_key == "d" or last_key == "y" or last_key == "x" then
|
||||
DIRECTION_KEYS[#DIRECTION_KEYS + 1] = {
|
||||
on = last_key,
|
||||
}
|
||||
local direction_key = ya.which { cands = DIRECTION_KEYS, silent = true }
|
||||
if not direction_key then
|
||||
return nil, nil, nil
|
||||
end
|
||||
|
||||
direction = DIRECTION_KEYS[direction_key].on
|
||||
direction = normal_direction(direction)
|
||||
end
|
||||
|
||||
return tonumber(lines), last_key, direction
|
||||
end
|
||||
|
||||
local function is_tab_command(command)
|
||||
local tab_commands = { "t", "L", "H", "w", "W", "<", ">", "~" }
|
||||
for _, cmd in ipairs(tab_commands) do
|
||||
if command == cmd then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local get_active_tab = ya.sync(function(_) return cx.tabs.idx end)
|
||||
|
||||
-----------------------------------------------
|
||||
---------- E N T R Y / S E T U P ----------
|
||||
-----------------------------------------------
|
||||
|
||||
return {
|
||||
entry = function(_, args)
|
||||
local initial_value
|
||||
|
||||
-- this is checking if the argument is a valid number
|
||||
if args then
|
||||
initial_value = tostring(tonumber(args[1]))
|
||||
if initial_value == "nil" then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local lines, cmd, direction = get_cmd(initial_value, get_keys())
|
||||
if not lines or not cmd then
|
||||
-- command was cancelled
|
||||
render_clear()
|
||||
return
|
||||
end
|
||||
|
||||
if cmd == "g" then
|
||||
if direction == "g" then
|
||||
ya.manager_emit("arrow", { -99999999 })
|
||||
ya.manager_emit("arrow", { lines - 1 })
|
||||
render_clear()
|
||||
return
|
||||
elseif direction == "j" then
|
||||
cmd = "j"
|
||||
elseif direction == "k" then
|
||||
cmd = "k"
|
||||
elseif direction == "t" then
|
||||
ya.manager_emit("tab_switch", { lines - 1 })
|
||||
render_clear()
|
||||
return
|
||||
else
|
||||
-- no valid direction
|
||||
render_clear()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if cmd == "j" then
|
||||
ya.manager_emit("arrow", { lines })
|
||||
elseif cmd == "k" then
|
||||
ya.manager_emit("arrow", { -lines })
|
||||
elseif is_tab_command(cmd) then
|
||||
if cmd == "t" then
|
||||
for _ = 1, lines do
|
||||
ya.manager_emit("tab_create", {})
|
||||
end
|
||||
elseif cmd == "H" then
|
||||
ya.manager_emit("tab_switch", { -lines, relative = true })
|
||||
elseif cmd == "L" then
|
||||
ya.manager_emit("tab_switch", { lines, relative = true })
|
||||
elseif cmd == "w" then
|
||||
ya.manager_emit("tab_close", { lines - 1 })
|
||||
elseif cmd == "W" then
|
||||
local curr_tab = get_active_tab()
|
||||
local del_tab = curr_tab + lines - 1
|
||||
for _ = curr_tab, del_tab do
|
||||
ya.manager_emit("tab_close", { curr_tab - 1 })
|
||||
end
|
||||
ya.manager_emit("tab_switch", { curr_tab - 1 })
|
||||
elseif cmd == "<" then
|
||||
ya.manager_emit("tab_swap", { -lines })
|
||||
elseif cmd == ">" then
|
||||
ya.manager_emit("tab_swap", { lines })
|
||||
elseif cmd == "~" then
|
||||
local jump = lines - get_active_tab()
|
||||
ya.manager_emit("tab_swap", { jump })
|
||||
end
|
||||
else
|
||||
ya.manager_emit("visual_mode", {})
|
||||
-- invert direction when user specifies it
|
||||
if direction == "k" then
|
||||
ya.manager_emit("arrow", { -lines })
|
||||
elseif direction == "j" then
|
||||
ya.manager_emit("arrow", { lines })
|
||||
else
|
||||
ya.manager_emit("arrow", { lines - 1 })
|
||||
end
|
||||
ya.manager_emit("escape", {})
|
||||
|
||||
if cmd == "d" then
|
||||
ya.manager_emit("remove", {})
|
||||
elseif cmd == "y" then
|
||||
ya.manager_emit("yank", {})
|
||||
elseif cmd == "x" then
|
||||
ya.manager_emit("yank", { cut = true })
|
||||
end
|
||||
end
|
||||
|
||||
render_clear()
|
||||
end,
|
||||
setup = function(state, args)
|
||||
if not args then
|
||||
return
|
||||
end
|
||||
|
||||
-- initialize state variables
|
||||
state._only_motions = args["only_motions"] or false
|
||||
|
||||
if args["show_motion"] then
|
||||
render_motion_setup()
|
||||
end
|
||||
|
||||
if args["show_numbers"] == "absolute" then
|
||||
render_numbers(SHOW_NUMBERS_ABSOLUTE)
|
||||
elseif args["show_numbers"] == "relative" then
|
||||
render_numbers(SHOW_NUMBERS_RELATIVE)
|
||||
elseif args["show_numbers"] == "relative_absolute" then
|
||||
render_numbers(SHOW_NUMBERS_RELATIVE_ABSOLUTE)
|
||||
end
|
||||
end,
|
||||
}
|
||||
Reference in New Issue
Block a user