Use dotter

This commit is contained in:
Kristofers Solo
2024-08-28 09:02:07 +03:00
parent d888080cc7
commit a42ded1119
1200 changed files with 1231 additions and 2261 deletions

View 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.

View 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` |

View 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,
}