diff --git a/.config/kitty/current-theme.conf b/.config/kitty/current-theme.conf
index 16a5fd0..dac89d0 100644
--- a/.config/kitty/current-theme.conf
+++ b/.config/kitty/current-theme.conf
@@ -6,8 +6,8 @@ color0 #383838
color8 #474747
color1 #a95551
color9 #a97775
-color2 #666666
-color10 #8c8c8c
+color2 #6b8f4e
+color10 #8fb86a
color3 #a98051
color11 #a99175
color4 #657d3e
diff --git a/.config/nvim/lua/config/keymaps.lua b/.config/nvim/lua/config/keymaps.lua
index ee0d997..cdb105e 100644
--- a/.config/nvim/lua/config/keymaps.lua
+++ b/.config/nvim/lua/config/keymaps.lua
@@ -2,16 +2,5 @@
-- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua
-- Add any additional keymaps here
--- Override LazyVim's / : count 99 opens the floating terminal,
--- everything else stays native (bottom terminal at project root).
--- Both keys are mapped because terminals differ in which code Ctrl+/ sends.
-local function term_open()
- if vim.v.count == 99 then
- require("config.terminal").open_float()
- else
- Snacks.terminal.focus(nil, { cwd = LazyVim.root() })
- end
-end
-
-vim.keymap.set({ "n", "t" }, "", term_open, { desc = "Terminal (Root Dir) | 99 = float" })
-vim.keymap.set({ "n", "t" }, "", term_open, { desc = "Terminal (Root Dir) | 99 = float" })
+-- Terminal keymaps ( toggle with 99-count float, tt, ft)
+-- are registered by the snacks-terminal-ctl plugin (lua/plugins/terminal.lua).
diff --git a/.config/nvim/lua/config/terminal.lua b/.config/nvim/lua/config/terminal.lua
deleted file mode 100644
index 1a27d4f..0000000
--- a/.config/nvim/lua/config/terminal.lua
+++ /dev/null
@@ -1,145 +0,0 @@
--- Terminal helpers layered on top of the native LazyVim/Snacks terminal.
---
--- Native behaviour is kept intact and untouched:
--- / toggle a bottom terminal at the project root (supports a
--- count, e.g. 2 opens a *separate* terminal #2)
--- fT terminal in the current working directory
---
--- This module adds (actual key bindings are declared in lua/plugins/terminal.lua):
--- open_float() open/focus a *dedicated* floating terminal (close it with )
--- picker() list every live terminal so any contextual terminal can be
--- focused or restored even after its window was closed/hidden.
-local M = {}
-
--- The floating terminal. Tracked as an upvalue so the same key always re-focuses
--- the *same* float regardless of which directory the editor is in.
----@type snacks.win?
-local float
-
---- Open or focus the floating terminal, or hide it if already focused.
--- NOTE: currently unused; the binding calls open_float() instead so shell
--- tab-completion keeps working while the terminal is open. Kept around for a
--- future explicit open/close toggle.
-function M.toggle_float()
- -- Reuse the existing instance: hide if visible, re-show if hidden.
- if float and float:buf_valid() then
- if float:win_valid() then
- float:hide()
- else
- float:show()
- vim.cmd("startinsert")
- end
- return
- end
-
- -- First open: a high fixed count guarantees this terminal never collides with
- -- the count-keyed bottom terminals (1, 2, 3 ...), so it is always the *same*
- -- float for no matter the context.
- float = Snacks.terminal(nil, {
- count = 99,
- win = { position = "float", border = "rounded" },
- })
-
- -- Close it with a single keystroke from inside the shell: hides the
- -- window (buffer-local, so it only affects this floating terminal and never
- -- the bottom split, where shell tab-completion must keep working).
- if float and float.buf then
- vim.keymap.set("t", "tt", function()
- if float and float:win_valid() then
- float:hide()
- end
- end, { buffer = float.buf, silent = true, desc = "Hide floating terminal" })
- end
-end
-
---- Open or focus the floating terminal. This never hides the window, so
---- once the float is open the key falls through to the shell and stays available
---- for tab-completion. Close the floating terminal with while it is
---- visible (handled by Snacks' native terminal keymap).
-function M.open_float()
- if float and float:buf_valid() then
- if not float:win_valid() then
- float:show()
- end
- if float:win_valid() then
- vim.api.nvim_set_current_win(float.win)
- end
- vim.cmd("startinsert")
- return
- end
-
- -- First open: a high fixed count guarantees this terminal never collides with
- -- the count-keyed bottom terminals (1, 2, 3 ...), so it is always the *same*
- -- float for no matter the context.
- float = Snacks.terminal(nil, {
- count = 99,
- win = { position = "float", border = "rounded" },
- })
-end
-
---- List every live Snacks terminal in a picker. Restore/focus one with ,
---- kill one with .
-function M.picker()
- local terms = Snacks.terminal.list()
- if #terms == 0 then
- Snacks.notify.info("No open terminals")
- return
- end
-
- local items = {} ---@type snacks.picker.finder.Item[]
- for _, term in ipairs(terms) do
- local meta = vim.b[term.buf] and vim.b[term.buf].snacks_terminal or {}
- items[#items + 1] = {
- term = term,
- buf = term.buf,
- id = meta.id,
- cwd = meta.cwd or "?",
- cmd = meta.cmd or vim.o.shell,
- visible = term:win_valid(),
- text = ("#%s %s %s"):format(meta.id or "?", meta.cwd or "?", meta.cmd or vim.o.shell),
- }
- end
-
- Snacks.picker({
- title = "Terminals",
- items = items,
- format = function(item)
- local ret = {} ---@type snacks.picker.Highlight[]
- ret[#ret + 1] = {
- item.visible and "● " or "○ ",
- item.visible and "SnacksPickerSpecial" or "SnacksPickerComment",
- }
- ret[#ret + 1] = { ("#%-2s"):format(item.id or "?"), "Number" }
- ret[#ret + 1] = { " " .. vim.fn.fnamemodify(item.cwd, ":~"), "SnacksPickerPath" }
- ret[#ret + 1] = { " " .. vim.fn.fnamemodify(item.cmd, ":t"), "SnacksPickerComment" }
- return ret
- end,
- confirm = function(picker, item)
- picker:close()
- local term = item.term
- if not term:buf_valid() then
- Snacks.notify.warn("Terminal no longer exists")
- return
- end
- if term:win_valid() then
- vim.api.nvim_set_current_win(term.win)
- else
- term:show()
- vim.cmd("startinsert")
- end
- end,
- win = { input = { keys = { ["d"] = "term_delete" } } },
- actions = {
- term_delete = function(picker, item)
- local term = item.term
- picker:close()
- if term and term:buf_valid() then
- term:close()
- pcall(vim.api.nvim_buf_delete, term.buf, { force = true })
- end
- end,
- },
- })
-end
-
-return M
diff --git a/.config/nvim/lua/plugins/clangd-container.lua b/.config/nvim/lua/plugins/clangd-container.lua
new file mode 100644
index 0000000..c133fdc
--- /dev/null
+++ b/.config/nvim/lua/plugins/clangd-container.lua
@@ -0,0 +1,11 @@
+return {
+ {
+ "chodak166/clangd-container.nvim",
+ -- dir = vim.fn.expand("~/src/git/clangd-container.nvim"),
+ dependencies = { "p00f/clangd_extensions.nvim" },
+ opts = {},
+ keys = {
+ { "cC", "ClangdContainer", desc = "Clangd Container" },
+ },
+ },
+}
diff --git a/.config/nvim/lua/plugins/devcontainers.lua b/.config/nvim/lua/plugins/devcontainers.lua
new file mode 100644
index 0000000..3eedd0a
--- /dev/null
+++ b/.config/nvim/lua/plugins/devcontainers.lua
@@ -0,0 +1,13 @@
+return {
+ {
+ "https://codeberg.org/esensar/nvim-dev-container",
+ dependencies = "nvim-treesitter/nvim-treesitter",
+ config = function()
+ require("devcontainer").setup({
+ -- Your options go here
+ -- e.g., auto_start = true, icons = { ... }
+ container_runtime = docker,
+ })
+ end,
+ },
+}
diff --git a/.config/nvim/lua/plugins/terminal.lua b/.config/nvim/lua/plugins/terminal.lua
index 4ac7335..81e5bb7 100644
--- a/.config/nvim/lua/plugins/terminal.lua
+++ b/.config/nvim/lua/plugins/terminal.lua
@@ -1,23 +1,11 @@
-- Terminal UX layered on Snacks (replaces toggleterm).
--- Helpers live in lua/config/terminal.lua; keys are declared here so lazy.nvim
--- registers the which-key labels with the rest of the snacks spec.
+-- All keymaps (tt, ft, with 99-count float) are
+-- registered by the plugin's setup().
return {
- "folke/snacks.nvim",
- keys = {
- {
- "tt",
- function()
- require("config.terminal").open_float()
- end,
- desc = "Terminal (float)",
- mode = "n",
- },
- {
- "ft",
- function()
- require("config.terminal").picker()
- end,
- desc = "Terminals (list/restore)",
- },
- },
+ "chodak166/snacks-terminal-ctl.nvim",
+ -- dir = "~/src/git/snacks-terminal-ctl.nvim",
+ name = "snacks-terminal-ctl.nvim",
+ dependencies = { "folke/snacks.nvim" },
+ event = "VeryLazy",
+ opts = {},
}
diff --git a/.config/sway/config b/.config/sway/config
index 0748149..5c534e3 100644
--- a/.config/sway/config
+++ b/.config/sway/config
@@ -27,16 +27,16 @@ set $configDir ~/.config/sway
# Workspaces
#################################################################
-set $workspace1 1: >_
-set $workspace2 2: dev
-set $workspace3 3: www
-set $workspace4 4: files
-set $workspace5 5: e-mail
-set $workspace6 6: IM
-set $workspace7 7: video
-set $workspace8 8: workspace
-set $workspace9 9: workspace
-set $workspace10 10: Music
+set $workspace1 1: 1: >_
+set $workspace2 2: 2: dev
+set $workspace3 3: 3: www
+set $workspace4 4: 4: files
+set $workspace5 5: 5: e-mail
+set $workspace6 6: 6: IM
+set $workspace7 7: 7: video
+set $workspace8 8: 8: workspace
+set $workspace9 9: 9: workspace
+set $workspace10 10: 10: Music
set $workspace11 V: VM
# Switch to workspace
diff --git a/.config/yazi/keymap.toml b/.config/yazi/keymap.toml
index ae4495f..f957efa 100644
--- a/.config/yazi/keymap.toml
+++ b/.config/yazi/keymap.toml
@@ -54,3 +54,8 @@ on = ""
run = "plugin diff"
desc = "Diff the selected with the hovered file"
+[[mgr.prepend_keymap]]
+on = "p"
+run = "plugin paste-dialog"
+desc = "Paste with conflict dialog"
+
diff --git a/.config/yazi/package.toml b/.config/yazi/package.toml
index 21f35ee..cc824e9 100644
--- a/.config/yazi/package.toml
+++ b/.config/yazi/package.toml
@@ -58,6 +58,11 @@ use = "yazi-rs/plugins:jump-to-char"
rev = "598cdb6"
hash = "7a4b4237223aaa94e589d1c01a23542a"
+[[plugin.deps]]
+use = "chodak166/paste-dialog"
+rev = "645b32a"
+hash = "357d322e81ff7449c0249ae17b55aaa5"
+
[[flavor.deps]]
use = "Chromium-3-Oxide/everforest-medium"
rev = "e1ead7b"
diff --git a/.config/yazi/plugins/paste-dialog.lua b/.config/yazi/plugins/paste-dialog.lua
new file mode 100644
index 0000000..987b471
--- /dev/null
+++ b/.config/yazi/plugins/paste-dialog.lua
@@ -0,0 +1,135 @@
+local M = {}
+
+local function get_yanked_info()
+ return ya.sync(function()
+ local cwd = cx.active.current.cwd
+ local cut = cx.yanked.is_cut
+
+ local yanked = {}
+ for _, f in pairs(cx.yanked) do
+ yanked[#yanked + 1] = { url = f.url, name = tostring(f.url:name()) }
+ end
+
+ return cwd, cut, yanked
+ end)
+end
+
+local function rename_default(name)
+ local suffix = os.date("-%y%m%d")
+ local stem = name:match("^(.+)%..-$") or name
+ local ext = name:match("%.(.+)$") or ""
+ if ext ~= "" then
+ return stem .. suffix .. "." .. ext
+ else
+ return name .. suffix
+ end
+end
+
+function M:entry(_, job)
+ local cwd, cut, yanked = get_yanked_info()
+ if #yanked == 0 then
+ return
+ end
+
+ local follow = job.args.follow or false
+ local resolved = {}
+
+ -- Partition: check each yanked item for conflicts
+ local conflicts = {}
+ for _, item in ipairs(yanked) do
+ local dest = cwd:join(item.name)
+ local cha = fs.cha(dest)
+ if cha ~= nil then
+ conflicts[#conflicts + 1] = { url = item.url, dest = dest, name = item.name }
+ else
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(dest),
+ overwrite = false,
+ }
+ end
+ end
+
+ -- Process conflicts
+ local sync_all = false
+ for _, item in ipairs(conflicts) do
+ if sync_all then
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(item.dest),
+ overwrite = true,
+ }
+ else
+ local choice = ya.pick({
+ title = "Paste conflict: " .. item.name,
+ items = {
+ "Sync (merge/overwrite)",
+ "Sync all remaining",
+ "Rename",
+ "Skip",
+ "Cancel",
+ },
+ })
+
+ -- ya.pick returns 0-based index or nil
+ if choice == nil or choice == 4 then
+ -- Cancel: paste what we have so far, then abort
+ if #resolved > 0 then
+ ya.emit("paste_resolved", {
+ cut = cut,
+ follow = follow,
+ items = resolved,
+ })
+ end
+ return
+
+ elseif choice == 0 then
+ -- Sync current
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(item.dest),
+ overwrite = true,
+ }
+
+ elseif choice == 1 then
+ -- Sync all remaining
+ sync_all = true
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(item.dest),
+ overwrite = true,
+ }
+
+ elseif choice == 2 then
+ -- Rename
+ local default = rename_default(item.name)
+ local value, event = ya.input({
+ title = "New name",
+ value = default,
+ })
+ if event == 1 then
+ local new_dest = cwd:join(value)
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(new_dest),
+ overwrite = false,
+ }
+ end
+
+ elseif choice == 3 then
+ -- Skip: do nothing
+ end
+ end
+ end
+
+ -- Dispatch all resolved items
+ if #resolved > 0 then
+ ya.emit("paste_resolved", {
+ cut = cut,
+ follow = follow,
+ items = resolved,
+ })
+ end
+end
+
+return M
diff --git a/.config/yazi/plugins/paste-dialog.yazi/LICENSE b/.config/yazi/plugins/paste-dialog.yazi/LICENSE
new file mode 100644
index 0000000..f360370
--- /dev/null
+++ b/.config/yazi/plugins/paste-dialog.yazi/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 chodak166
+
+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.
diff --git a/.config/yazi/plugins/paste-dialog.yazi/README.md b/.config/yazi/plugins/paste-dialog.yazi/README.md
new file mode 100644
index 0000000..52af933
--- /dev/null
+++ b/.config/yazi/plugins/paste-dialog.yazi/README.md
@@ -0,0 +1,115 @@
+# paste-dialog.yazi
+
+A [yazi](https://github.com/sxyazi/yazi) plugin that shows an interactive
+conflict-resolution dialog when pasting files. Instead of silently appending
+`_1`, `_2` suffixes to conflicting names, you choose how to handle each
+conflict individually.
+
+| Option | Action | Description |
+|--------|--------|-------------|
+| **Merge** | merge / overwrite | Merge directory contents recursively; overwrite individual files. _(default — press Enter)_ |
+| **Merge all remaining** | merge / overwrite | Same as Merge, but applied to every remaining conflict without prompting again. |
+| **Replace** | replace | Delete the destination entirely, then copy fresh (removes files that exist only at the destination). |
+| **Rename** | rename | Prompt for a new name, pre-filled with `name-yymmdd`. If the new name also conflicts the dialog reappears with a different default (`name-2`, `name-3`, …). |
+| **Skip** | skip | Leave this item untouched. |
+| **Cancel** | abort | Paste any non-conflicting items already queued, then stop. _(Esc)_ |
+
+Non-conflicting items always paste silently — the dialog only appears when a
+conflict is detected.
+
+> ⚠️ **This plugin requires a modified version of yazi.**
+> See [Requirements](#requirements) below.
+
+---
+
+## Requirements
+
+This plugin depends on Rust-level changes to yazi that have **not** been merged
+into upstream:
+
+| Change | Why it's needed |
+|--------|----------------|
+| `paste_resolved` actor + parser | Per-item paste with explicit `from`/`to`/`overwrite`/`replace` — not possible with the existing `ya.emit("paste")`. |
+| `file_copy_one` / `file_cut_one` | Scheduler methods that accept individual source/destination URLs with a `replace` flag. |
+| `ya.pick({ title=, items= })` | Exposes the existing pick dialog to Lua plugins (was internal-only). |
+| `PickCfg::with_title()` | Lets `ya.pick()` override the dialog title. |
+
+Build yazi from the fork:
+
+```sh
+git clone https://github.com/chodak166/yazi.git
+cd yazi
+cargo build --release
+
+# Install the modified binaries on your PATH
+cp target/release/yazi target/release/ya ~/.local/bin/
+```
+
+---
+
+## Installation
+
+### Option A — install via `ya pkg` (recommended)
+
+```sh
+ya pkg add chodak166/paste-dialog.yazi
+```
+
+### Option B — manual install
+
+```sh
+# 1. Create the plugin directory
+mkdir -p ~/.config/yazi/plugins/paste-dialog.yazi
+
+# 2. Download main.lua into it
+curl -fsSL https://raw.githubusercontent.com/chodak166/paste-dialog.yazi/main/main.lua \
+ -o ~/.config/yazi/plugins/paste-dialog.yazi/main.lua
+```
+
+### Add the keybinding
+
+Add the following to `~/.config/yazi/keymap.toml` (the `prepend_keymap` keeps
+all default bindings intact):
+
+```toml
+[[mgr.prepend_keymap]]
+on = "p"
+run = "plugin paste-dialog"
+desc = "Paste with conflict dialog"
+```
+
+Restart yazi, then press p to paste with conflict resolution.
+
+---
+
+## Usage
+
+1. Yank files (y) or cut them (x) as usual.
+2. Navigate to the destination directory.
+3. Press p to paste.
+4. If there are conflicts a pick dialog appears for each one:
+ - Navigate with j/k or arrow keys, confirm with Enter.
+ - **Merge** — overwrites the destination file or merges directory contents.
+ - **Merge all remaining** — merge this and all remaining conflicts without prompting.
+ - **Replace** — deletes the destination entirely before copying (removes excess files).
+ - **Rename** — shows an input prompt with `name-yymmdd` pre-filled. If the new name also conflicts, the dialog reappears; choosing Rename again cycles the default to `name-2`, `name-3`, etc.
+ - **Skip** — leaves the destination untouched.
+ - **Cancel** (or Esc) — pastes any queued clean items, then aborts.
+
+---
+
+## Notes
+
+- **Merge** uses the scheduler's existing `force=true` behavior: new files are
+ added, existing files are overwritten, destination-only files are preserved.
+- **Replace** deletes the destination directory entirely before copying,
+ removing any files that exist only in the destination.
+- Deep conflicts within merged directories are resolved silently by
+ overwriting individual files.
+- **Cut + Skip** leaves the source file in place (it is not deleted).
+- Between the conflict pre-scan and the actual paste, `overwrite=false` items
+ fall back to `unique_file()` if a new conflict appears.
+
+## License
+
+MIT
diff --git a/.config/yazi/plugins/paste-dialog.yazi/main.lua b/.config/yazi/plugins/paste-dialog.yazi/main.lua
new file mode 100644
index 0000000..5b25bfd
--- /dev/null
+++ b/.config/yazi/plugins/paste-dialog.yazi/main.lua
@@ -0,0 +1,220 @@
+local M = {}
+
+local get_yanked_info = ya.sync(function()
+ local cwd = cx.active.current.cwd
+ local cut = cx.yanked.is_cut
+
+ local yanked = {}
+ for _, url in ipairs(cx.yanked:urls()) do
+ yanked[#yanked + 1] = { url = url, name = tostring(url.name) }
+ end
+
+ return { cwd = cwd, cut = cut, yanked = yanked }
+end)
+
+local function rename_default(name, attempt)
+ if attempt and attempt > 1 then
+ local suffix = string.format("-%d", attempt)
+ local stem = name:match("^(.+)%..-$") or name
+ local ext = name:match("%.(.+)$") or ""
+ if ext ~= "" then
+ return stem .. suffix .. "." .. ext
+ else
+ return name .. suffix
+ end
+ end
+ local suffix = os.date("-%y%m%d")
+ local stem = name:match("^(.+)%..-$") or name
+ local ext = name:match("%.(.+)$") or ""
+ if ext ~= "" then
+ return stem .. suffix .. "." .. ext
+ else
+ return name .. suffix
+ end
+end
+
+--Choices:
+-- 0: Merge — merge directory contents, overwrite individual files
+-- 1: Merge all — same, applied to all remaining conflicts
+-- 2: Replace — replace destination entirely (delete then copy)
+-- 3: Rename — prompt for a new name
+-- 4: Skip — skip this item
+-- 5: Cancel(nil) — abort
+local function pick_conflict(name)
+ return ya.pick({
+ title = "Paste conflict: " .. name,
+ items = {
+ "Merge",
+ "Merge all remaining",
+ "Replace",
+ "Rename",
+ "Skip",
+ "Cancel",
+ },
+ })
+end
+
+function M:entry(job)
+ local info = get_yanked_info()
+ local cwd, cut, yanked = info.cwd, info.cut, info.yanked
+
+ if #yanked == 0 then
+ return
+ end
+
+ local follow = job.args.follow or false
+ local resolved = {}
+
+ -- Partition: check each yanked item for conflicts
+ local conflicts = {}
+ for _, item in ipairs(yanked) do
+ local dest = cwd:join(item.name)
+ local cha = fs.cha(dest)
+ if cha ~= nil then
+ conflicts[#conflicts + 1] = { url = item.url, dest = dest, name = item.name }
+ else
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(dest),
+ overwrite = false,
+ replace = false,
+ }
+ end
+ end
+
+ -- Dispatch helper
+ local function dispatch(items)
+ if #items > 0 then
+ ya.emit("paste_resolved", {
+ cut = cut,
+ follow = follow,
+ items = items,
+ })
+ end
+ end
+
+ -- Process conflicts
+ local merge_all = false
+ for _, item in ipairs(conflicts) do
+ if merge_all then
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(item.dest),
+ overwrite = true,
+ replace = false,
+ }
+ else
+ local choice = pick_conflict(item.name)
+
+ if choice == nil or choice == 5 then
+ -- Cancel: paste what we have so far, then abort
+ dispatch(resolved)
+ return
+
+ elseif choice == 0 then
+ -- Merge current
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(item.dest),
+ overwrite = true,
+ replace = false,
+ }
+
+ elseif choice == 1 then
+ -- Merge all remaining
+ merge_all = true
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(item.dest),
+ overwrite = true,
+ replace = false,
+ }
+
+ elseif choice == 2 then
+ -- Replace
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(item.dest),
+ overwrite = true,
+ replace = true,
+ }
+
+ elseif choice == 3 then
+ -- Rename: loop until a non-conflicting name is chosen or cancelled
+ local attempt = 0
+ while true do
+ attempt = attempt + 1
+ local default = rename_default(item.name, attempt)
+ local value, event = ya.input({
+ title = "New name",
+ value = default,
+ pos = { "center", w = 60 },
+ })
+ if event ~= 1 then
+ -- User cancelled the input — skip this item
+ break
+ end
+
+ local new_dest = cwd:join(value)
+ if fs.cha(new_dest) == nil then
+ -- No conflict — add and continue
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(new_dest),
+ overwrite = false,
+ replace = false,
+ }
+ break
+ else
+ -- New name also conflicts — show the conflict dialog again
+ local sub_choice = pick_conflict(value)
+ if sub_choice == nil or sub_choice == 5 then
+ -- Cancel everything
+ dispatch(resolved)
+ return
+ elseif sub_choice == 0 then
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(new_dest),
+ overwrite = true,
+ replace = false,
+ }
+ break
+ elseif sub_choice == 1 then
+ merge_all = true
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(new_dest),
+ overwrite = true,
+ replace = false,
+ }
+ break
+ elseif sub_choice == 2 then
+ resolved[#resolved + 1] = {
+ from = tostring(item.url),
+ to = tostring(new_dest),
+ overwrite = true,
+ replace = true,
+ }
+ break
+ elseif sub_choice == 3 then
+ -- Rename again — increment attempt for different default
+ -- (loop continues)
+ elseif sub_choice == 4 then
+ -- Skip
+ break
+ end
+ end
+ end
+
+ elseif choice == 4 then
+ -- Skip: do nothing
+ end
+ end
+ end
+
+ -- Dispatch all resolved items
+ dispatch(resolved)
+end
+
+return M
diff --git a/.gitignore b/.gitignore
index dc42dd0..6f04d2c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@
.config/nvim/.env
.local/share/applications/mimeinfo.cache
.docker/config.json
+.crush
+
diff --git a/.zshrc b/.zshrc
index ed8a686..041d4d1 100644
--- a/.zshrc
+++ b/.zshrc
@@ -106,6 +106,10 @@ fi
# Initialize modules.
source ${ZIM_HOME}/init.zsh
+# Override bira prompt: user@host in gray instead of green
+PS1='╭─%B%(!.%F{red]}.%F{8})%n@%m %F{blue}%~${(e)git_info[prompt]}${VIRTUAL_ENV:+" %F{green}‹${VIRTUAL_ENV:t}›"}%f%b
+╰─%B%(!.#.$)%b '
+
# ------------------------------
# Post-init module configuration
# ------------------------------
@@ -164,10 +168,11 @@ if [[ "$TERM" == screen* ]]; then
fi
typeset -U path
-local custom_paths=(
+custom_paths=(
"$HOME/.cargo/bin"
"$HOME/.local/kitty.app/bin"
"$HOME/.local/bin"
+ "$HOME/go/bin"
)
for d in "${custom_paths[@]}"; do
@@ -185,6 +190,7 @@ alias gl="git log --graph --abbrev-commit --decorate --format=format:'%C(bold bl
alias git-config-tb='git config user.name "Łukasz Chodyła" && git config user.email "lukasz.chodyla@transbit.com.pl"'
alias git-config-ch='git config user.name "chodak166" && git config user.email "chodak166@op.pl"'
alias config='/usr/bin/git --git-dir=$HOME/.dotfiles.git/ --work-tree=$HOME'
+alias config-lazygit='lazygit --git-dir=$HOME/.dotfiles.git/ --work-tree=$HOME'
alias v='nvim'
alias se=sudoedit
alias trb-smb-mount='sudo mount -t cifs -o uid=`id -u chodylal` -o gid=`id -g chodylal` -o user=chodylal //trb-fs-p01/repozytorium/ /home/chodylal/smb'