Compare commits

13 Commits

Author SHA1 Message Date
73f620fe39 tweaks 2025-10-20 16:54:21 +03:00
e191034b63 theme 2025-10-20 16:52:01 +03:00
1c615589f2 tweaks 2025-10-20 16:52:01 +03:00
e3e22e5bf7 navigation-file: fix lint issues 2025-10-20 16:52:01 +03:00
44925ddd73 navigation-file: fix empty buffer 2025-10-20 16:52:01 +03:00
6ede4f1a7f navigation-file: use ripgrep 2025-10-20 16:52:01 +03:00
ca5c511a10 navigation-file: use fdfind 2025-10-20 16:52:01 +03:00
90c5d70a5a navigation-file 1 2025-10-20 16:52:01 +03:00
6c73a15f21 improve active cursor line 2025-10-20 16:52:01 +03:00
fabb214a0f format 2025-10-20 16:52:01 +03:00
9be8d154ca improve terminal buffers 2025-10-20 16:52:01 +03:00
ad7c791d23 add telescope 2025-10-20 16:52:01 +03:00
64a20b1292 clean nvim 2025-10-20 16:52:01 +03:00
74 changed files with 2886 additions and 1728 deletions

6
.gitmodules vendored
View File

@@ -1,6 +0,0 @@
[submodule "config/shared/nvim"]
path = config/shared/nvim
url = git@gitea.tomastm.com:tomas.mirchev/nvim-config.git
[submodule "config/shared/barg-parser"]
path = config/shared/barg-parser
url = git@gitea.tomastm.com:tomas.mirchev/barg-parser.git

153
config.json Normal file
View File

@@ -0,0 +1,153 @@
{
"template": {
"htop": {
"link": {
"from": "shared/htop",
"to": "~/.config/htop"
}
},
"bin": {
"link": {
"from": "shared/bin",
"to": "~/bin"
}
},
"vim": {
"link": {
"from": "shared/vim",
"to": "~/.vimrc"
},
"-post-link": "curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim && vim -es -u ~/.vimrc -i NONE -c 'PlugInstall' -c 'qa'"
},
"nvim": {
"link": {
"from": "shared/nvim",
"to": "~/.config/nvim/init.lua"
},
"post-link": "(grep -q 'alias vim=nvim' ~/.zshrc || echo 'alias vim=nvim' >> ~/.zshrc) || true"
},
"zsh": {
"link": {
"from": "shared/zsh",
"to": "~/.zshrc"
}
},
"tmux": {
"link": {
"from": "shared/tmux",
"to": "~/.tmux.conf"
}
},
"git": {
"link": {
"from": "shared/git",
"to": "~/.gitconfig"
}
},
"wezterm": {
"link": {
"from": "shared/wezterm",
"to": "~/.wezterm.lua"
}
},
"alacritty": {
"link": {
"from": "shared/alacritty",
"to": "~/.alacritty.toml"
}
},
"ghostty": {
"link": {
"from": "shared/ghostty",
"to": "~/.config/ghostty"
}
}
},
"environments": {
"macos": [
"zsh",
{
"package": "bin",
"link": {
"from": "macos/bin",
"to": "~/bin"
}
},
"tmux",
"nvim",
"git",
"ghostty",
"alacritty",
{
"package": "karabiner",
"link": {
"from": "macos/karabiner",
"to": "~/.config/karabiner"
}
},
{
"package": "linearmouse",
"link": {
"from": "macos/linearmouse",
"to": "~/.config/linearmouse"
}
},
{
"package": "rectangle",
"link-comment": "Needs manual import from config/macos/linearmouse"
}
],
"linux-vm": [
{
"package": "zsh",
"install": "sudo apt install -y zsh",
"post-link": "./scripts/linux-setup_zsh.sh"
},
{
"package": "tmux",
"link": {
"from": "linux-vm/tmux",
"to": "~/.tmux.conf"
},
"install": "sudo apt install -y tmux"
},
{
"package": "nvim",
"install": "bash -c 'wget -O nvim.deb https://gitea.tomastm.com/tomas.mirchev/neovim/releases/download/v0.10.0/nvim-linux-$(dpkg --print-architecture).deb && sudo dpkg -i nvim.deb && rm nvim.deb'"
},
{
"package": "git",
"install": "sudo apt install -y git"
},
{
"package": "htop",
"install": "sudo apt install -y htop"
},
"bin"
],
"linux-dev": [
{
"package": "zsh",
"install": "sudo apt install -y zsh",
"post-link": "./scripts/linux-setup_zsh.sh"
},
{
"package": "nvim",
"ignore-template": true,
"link": {
"from": "linux-dev/nvim",
"to": "~/.config/nvim"
},
"post-link": "nvim --headless '+Lazy! restore' +qa"
},
{
"package": "git",
"install": "sudo apt install -y git"
},
{
"package": "htop",
"install": "sudo apt install -y htop"
}
]
}
}

View File

@@ -0,0 +1 @@
return { globals = { 'vim' } }

View File

@@ -0,0 +1,14 @@
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"runtime": {
"version": "LuaJIT"
},
"workspace": {
"library": [
"lua",
"$VIMRUNTIME",
"${3rd}/luv/library"
],
"checkThirdParty": false
}
}

View File

@@ -0,0 +1,7 @@
column_width = 100
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferSingle"
call_parentheses = "Always"
line_endings = "Unix"

View File

@@ -0,0 +1,109 @@
#============================================================
# Neovim Command Reference (Core Commands)
#============================================================
#============================================================
# FILE & SESSION MANAGEMENT
#============================================================
:w (write) Save current buffer
:w <file> Write to <file> (does NOT rename buffer)
:sav (saveas) <file> Save to <file> and rename current buffer
:q (quit) Quit current window if no unsaved changes
:q! Force quit (discard changes)
:wq Write and quit current buffer
:wqa Write and quit all buffers
:qa Quit all windows
:qa! Quit all without saving
:e (edit) <file> Edit <file> in current window (new buffer)
:e! Revert buffer to last saved version (discard changes)
:enew Create new empty buffer
:r (read) <file> Read <file> into current buffer after cursor
:ter (terminal) Open terminal buffer
:clo (close) Close current window
#============================================================
# BUFFERS
#============================================================
:ls (buffers) List open buffers
:bn (bnext) Go to next buffer
:bp (bprev) Go to previous buffer
:b<num> Go to buffer by number
:b <file> Go to buffer by (partial) name
:bd (bdelete) [<num>] Delete current (or given) buffer
:bw (bwipeout) [<num>] Delete buffer and remove from memory
:bo (only) Close all windows except current
:e # Edit alternate (previous) buffer
:b# Switch to alternate buffer
:b% Re-edit current buffer (no-op)
:b$ Go to last buffer
#============================================================
# WINDOWS (SPLITS)
#============================================================
:sp (split) [<file>] Split horizontally (optionally open <file>)
:vsp (vsplit) [<file>] Split vertically (optionally open <file>)
:new Split with new empty buffer
:vnew Vertical split with new empty buffer
:close Close current window
:only Keep only current window open
#============================================================
# TABS
#============================================================
:tabnew [<file>] Open new tab (optionally edit <file>)
:tabn (tabnext) Go to next tab
:tabp (tabprev) Go to previous tab
:tabm (tabmove) <num> Move current tab to position <num>
:tabfirst Jump to first tab
:tablast Jump to last tab
:tabc (tabclose) Close current tab
:tabo (tabonly) Close all other tabs
:tabdo <cmd> Execute <cmd> in all tabs (e.g. :tabdo q)
#============================================================
# REGISTERS, MARKS & HISTORY
#============================================================
:reg (registers) Show register contents
:marks Show all marks
:ju (jumps) Show jump list
:changes Show change list
#============================================================
# SEARCH / GREP / QUICKFIX
#============================================================
:g/{pattern}/d Delete all lines matching {pattern}
:g!/{pattern}/d Delete all lines NOT matching {pattern}
:vim /{pattern}/ **/* Search for {pattern} recursively in all files
:cn (cnext) Jump to next quickfix entry
:cp (cprevious) Jump to previous quickfix entry
:cope (copen) Open quickfix window
:ccl (cclose) Close quickfix window
:cl (clist) List quickfix entries
#============================================================
# DIFF MODE
#============================================================
:diffthis Start diff mode for current window
:diffo (diffoff) Turn off diff mode
:diffu (diffupdate) Recalculate diff
:diffg (diffget) Get changes from other window
:diffpu (diffput) Send changes to other window
#============================================================
# NOTES & SYMBOLS
#============================================================
% Current buffer
# Alternate (last visited) buffer
$ Last buffer in list
+ Next buffer
- Previous buffer
" Most recently edited buffer (context dependent)

View File

@@ -0,0 +1,217 @@
TODO:
- wrap up invero theme in separate repo and proper colors?
- check plugins logins
- cache / create final result
- simplify coding: ts, lsp, lint, format (check other repos)
- how to download parsers and plugins alternative
- telescope alternative
- keymaps
- wrap up everything
```lua
--[[
Neovim Lua config: ways to set things
- vim.opt : preferred modern API for options (handles lists, cleaner syntax)
- vim.g : global variables (leader key, plugin settings, disable builtins, etc.)
- vim.o : global-only option (rarely needed directly)
- vim.wo : window-local option (applies to current window only, use in autocmds)
- vim.bo : buffer-local option (applies to current buffer only, use in autocmds)
- vim.env : set environment variables (like PATH, LANG)
- vim.fn : call Vimscript functions (e.g. vim.fn.getcwd())
- vim.cmd : run raw Vimscript/Ex commands (e.g. vim.cmd("colorscheme desert"))
- vim.api : low-level Neovim API (create autocmds, keymaps, buffer/window ops, etc.)
TL;DR -> use vim.opt + vim.g in options.lua for defaults.
Use vim.wo/vim.bo only in context-specific tweaks (autocmds).
Use vim.env, vim.fn, vim.cmd, vim.api as needed for scripting.
--]]
```
## check macos fileS: https://github.com/dsully/dotfiles/blob/main/.data/macos-defaults/globals.yaml
# Used pacakges:
- rockspaces Metadata files describing how to build and install a Lua package.
- luarocks Package manager for Lua modules. (optional)
- tree-sitter Parser generator. Not needed except for using CLI. (optional)
- fd-find (fd) Alternative to `find`. (optional)
- ripgrep (rg) Line-oriented search tool. (recommended)
- git Revision control system. (requirement)
- lazygit Terminal UI for git commands. (optional)
- fzf Command-line fuzzy finder.
- bat "cat" but with colors
- curl Command-line for transferring data specified with URL syntax.
- wget Utility for downloading files from the Web.
- make
- cc Collection of compilers.
- build-essential Meta-package that installs standard C/C++ libraries and headers.
These are needed to compile tree-sitter parsers. Run only on the first time.
cc (gcc, clang) C compiler. Usually it points to `clang` (on macos) or `gcc` (on linux).
g++ C++ compiler.
make Build automation tool from source code.
- unzip Extraction utility for archives compressed in .zip.
- ca-certificates Provides a set of trusted Certificate Authority (CA) certificates.
- openssh-client Tools for connecting to remote servers securely over SSH.
- libssl-dev Development libraries and headers for OpenSSL.
- sudo
- tree
- jq
- man-db
- python3
- volta Node manager
- ncurses ncurses-dev ncurses-libs ncurses-terminfo \
- check: https://github.com/glepnir/nvim/blob/main/Dockerfile
# Currently installed
- plenary.nvim
- lazy.nvim
- nvim-treesitter
- neovim/nvim-lspconfig
- williamboman/mason.nvim
- williamboman/mason-lspconfig.nvim
- j-hui/fidget.nvim
- hrsh7th/cmp-nvim-lsp
- b0o/schemastore.nvim
- windwp/nvim-ts-autotag # auto close,rename tags
- nvim-autopairs # auto pair chars
- stevearc/conform.nvim # formatter
- nvim-cmp # completion
- cmp-path
- cmp-nvim-lsp
- nvim-tree.lua # file explorer
- telescope.nvim
- telescope-fzf-native.nvim
- telescope-ui-select.nvim
- plenary.nvim
- harpoon # tags
# Notes:
- in lsp change tsserver to vtsls
# New package definition
- Plugin and Package managers
- folke/lazy.nvim
- mason-org/mason.nvim
- TS
- nvim-treesitter
- nvim-treesitter-textobjects
- LSP
- neovim/nvim-lspconfig
- nvim-ts-autotag tag elements (`</>`)
- windwp/nvim-autopairs auto pairs
- blink.cmp autocompletion
- stevearc/conform.nvim autoformat
- mini.ai `a/i` motions
- mini.pairs
- mini.surround
- mfussenegger/nvim-lint
- nvim-lspconfig
- fzf-lua (replace telescope)
- ? indent guides
- lukas-reineke/indent-blankline.nvim
- snacks.indent
- mini.indentscope
## Deps:
- SchemaStore.nvim
- mason-lspconfig.nvim
- mason.nvim
## Maybe:
- folke/ts-comments.nvim better comments
- grug-far.nvim find and replace
- markdown-preview.nvim side by side md (disabled in folke)
- toppair/peek.nvim another markdown preview?
- render-markdown.nvim inline viewer
- markview.nvim
- diffview.nvim
- octo.nvim edit and review GH issues and pr
- yanky.nvim better yank+put. has history
- inc-rename.nvim LSP renaming with visual feedback
- mini.basics defaults options
- mini.test run tests under cursor
- mini.diff inline diff
- mini.hipatters hilight patters and hex colors
- mini.move move chunks (like vscode)
- undo tree (find a plugin)
## AI help
- jackMort/ChatGPT.nvim
- MunifTanjim/nui.nvim (dep)
- nvim-lua/plenary.nvim (dep)
- nvim-telescope/telescope.nvim (dep)
- robitx/gp.nvim
- zbirenbaum/copilot.lua (folke)
- milanglacier/minuet-ai.nvim (folke)
## Options
```
opt.backup = true
opt.backupdir = vim.fn(stdpath("state") .. "/backup"
opt.mousescroll = "vert:1,hor:4"
opt.winborder = "rounded"
opt.undofile = true
-- lazy
rtp = {
disabled_plugins = { "gzip", "tarPlugin", "zipPlugin", "tohtml", "tutor" },
},
vim.keymap.set("n", "<C-c>", "ciw")
-- ts lsp
includeCompletionsWithSnippetText = true,
jsxAttributeCompletionStyle = "auto",
-- tree-sitter parsers naming:
https://github.com/nvim-treesitter/nvim-treesitter/blob/master/lua/nvim-treesitter/parsers.lua
```
folke cmd
```lua
-- show cursor line only in active window
vim.api.nvim_create_autocmd({ "InsertLeave", "WinEnter" }, {
callback = function()
if vim.w.auto_cursorline then
vim.wo.cursorline = true
vim.w.auto_cursorline = nil
end
end,
})
vim.api.nvim_create_autocmd({ "InsertEnter", "WinLeave" }, {
callback = function()
if vim.wo.cursorline then
vim.w.auto_cursorline = true
vim.wo.cursorline = false
end
end,
})
-- backups
vim.api.nvim_create_autocmd("BufWritePre", {
group = vim.api.nvim_create_augroup("better_backup", { clear = true }),
callback = function(event)
local file = vim.uv.fs_realpath(event.match) or event.match
local backup = vim.fn.fnamemodify(file, ":p:~:h")
backup = backup:gsub("[/\\]", "%%")
vim.go.backupext = backup
end,
})
```
Enable folding with TS:
```
vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
vim.opt.foldenable = false -- start with all folds open
```

View File

@@ -0,0 +1,119 @@
#============================================================
# NEOVIM KEYMAP REFERENCE (CORE & USEFUL)
#============================================================
#============================================================
# INSERT MODE (Ctrl + ...)
#============================================================
Ctrl + h Delete character before cursor
Ctrl + w Delete word before cursor
Ctrl + j Insert line break (newline) at cursor
Ctrl + t Indent current line one 'shiftwidth' to the right
Ctrl + d De-indent current line one 'shiftwidth' to the left
Ctrl + n Insert next auto-completion match
Ctrl + p Insert previous auto-completion match
Ctrl + r x Insert contents of register x
Ctrl + o {cmd} Temporarily enter Normal mode to execute {cmd}
Esc / Ctrl + c Exit insert mode and return to Normal mode
#============================================================
# NORMAL MODE — WINDOW & TAB MANAGEMENT
#============================================================
C-w s Split current window horizontally
C-w v Split current window vertically
C-w c Close current window
C-w q Quit current window (same as close but exit if last)
C-w w Cycle through open windows
C-w x Exchange window with next one
C-w = Equalize window sizes
C-w _ Maximize height of current window
C-w | Maximize width of current window
C-w h Move to window left
C-w j Move to window below
C-w k Move to window above
C-w l Move to window right
C-w H Move current window far left
C-w J Move current window to bottom
C-w K Move current window to top
C-w L Move current window far right
C-w t Move current split into a new tab
gt Go to next tab
gT Go to previous tab
<n>gt Go to tab number <n>
#============================================================
# NORMAL MODE — TAGS, JUMPS & MOTIONS
#============================================================
Ctrl + ] Jump to tag under cursor
gd Go to local declaration
gD Go to global declaration
{ Jump backward one paragraph/block
} Jump forward one paragraph/block
; Repeat last motion forward
, Repeat last motion backward
Ctrl + e Scroll window down (cursor stays put)
Ctrl + y Scroll window up (cursor stays put)
H Move cursor to top of screen
M Move cursor to middle of screen
L Move cursor to bottom of screen
#============================================================
# NORMAL MODE — TEXT OBJECTS
#============================================================
aw "A word" — select word + following space
ab "A block" — select around ()
aB "A Block" — select around {}
at "A tag" — select around XML/HTML tag
ib "Inner block" — inside ()
iB "Inner Block" — inside {}
it "Inner tag" — inside tag (no delimiters)
#============================================================
# NORMAL MODE — DIFF / CHANGES
#============================================================
do Obtain (get) changes from other window
dp Put (send) changes to other window
#============================================================
# REGISTERS & CLIPBOARD
#============================================================
"xy Yank into register x
"xp Paste contents of register x
"+y Yank into system clipboard
"+p Paste from system clipboard
#--- Common Registers ---
"0 Last yank
" Unnamed register (last delete or yank)
"% Current file name
"# Alternate file name
"* X11 primary selection clipboard
"+ X11 clipboard register
"/ Last search pattern
": Last command-line command
". Last inserted text
"- Last small (less than a line) delete
"= Expression register (evaluate expression)
"_ Black hole register (discard output)
#============================================================
# TIPS & NOTES
#============================================================
- Ctrl + o in Insert mode is a powerful way to run one Normal-mode command temporarily.
- Use “aw”, “iw”, “ab”, “ib”, etc. with operators (e.g., daw, yib) for precise text manipulation.
- The system clipboard is “+” (Windows/macOS/Linux), but some X11 systems also use “*”.
- When in diff mode, do and dp are complementary: “get” vs. “put” changes.

View File

@@ -0,0 +1,94 @@
-- Window Creation/Closing
Ctrl-w s - Split window horizontally
Ctrl-w v - Split window vertically
Ctrl-w n - Create new window horizontally with empty buffer
Ctrl-w c - Close current window
Ctrl-w o - Close all windows except current one
-- Window Navigation
Ctrl-h - Move to window on the left
Ctrl-j - Move to window below
Ctrl-k - Move to window above
Ctrl-l - Move to window on the right
-- Window Moving/Rearranging
Ctrl-w H - Move current window to far left
Ctrl-w J - Move current window to bottom
Ctrl-w K - Move current window to top
Ctrl-w L - Move current window to far right
-- Window Resizing
Ctrl-w = - Make all windows equal size
Ctrl-w _ - Maximize height of current window
Ctrl-w | - Maximize width of current window
Ctrl-w > - Increase width by 5 column
Ctrl-w < - Decrease width by 5 column
Ctrl-w + - Increase height by 5 row
Ctrl-w - - Decrease height by 5 row
-- Window Special Commands
Ctrl-w T - Move current window to new tab
Ctrl-w } - Preview definition in new window
Ctrl-w z - Close preview window
-- Tab
<Leader>t] :tabnext - Go to next tab
<Leader>t[ :tabprevious - Go to previous tab
<Leader>tn :tabnew - Create a new tab
<Leader>tc :tabclose - Close current tab
<Leader>to :tabonly - Close all other tabs
<Leader>{n} :{n}gt - Go to tab {n}
-- Buffer
-- note: mainly using the telescope one
<Leader>space telescope.buffers - open buffers with telescope. there can navigate and delete
<Leader>bl :ls - List all buffers
<Leader>bd :bdelete - Delete current buffer
<Leader>bn :bnext - Go to next buffer
<Leader>bp :bprevious - Go to previous buffer
<Leader>b{n} :buffer {n} - Go to buffer {n}
<Leader>bb :b<Space> - Start buffer selection
<Leader>bo :bufdo bd|1bd - Delete all other buffers
-- Telescope
<Leader>ff telescope.find_files - Search Files
<Leader>fg telescope.live_grep - Search by Grep
<Leader>fb telescope.buffers - Search Buffers
<Leader>fh telescope.help_tags - Search Help
<Leader>fp telescope.projects - Search Projects
<Leader>fm telescope.marks - Search Marks
<Leader>fc telescope.commands - Search Commands
<Leader>fk telescope.keymaps - Search Keymaps
<Leader>fs telescope.git_status - Search Git Status
<Leader>fw telescope.grep_string - Search current Word
<Leader>fd telescope.diagnostics - Search Diagnostics
<Leader>fr telescope.lsp_references - Search References
-- Neo-tree
<Leader>e :NvimTree toggle - Explorer Toggle
<Leader>E :NvimTree focus - Explorer Focus
-- Harpoon
<Leader>h harpoon_ui.toggle_menu - Harpoon Menu
<Leader>m harpoon_mark.add_file - Mark File
<Leader>1 harpoon_ui.nav_file(1) - Harpoon File 1
<Leader>2 harpoon_ui.nav_file(2) - Harpoon File 2
<Leader>3 harpoon_ui.nav_file(3) - Harpoon File 3
<Leader>4 harpoon_ui.nav_file(4) - Harpoon File 4
<Leader>hn harpoon_ui.nav_next - Harpoon Next
<Leader>hp harpoon_ui.nav_prev - Harpoon Previous
-- Terminal
<Leader>tet :terminal cd %:h - Terminal in This dir
<Leader>ter :terminal - Terminal Regular
<Leader>tec :!cd %:h && - Terminal Command
<Esc> <C-\><C-n> - Terminal Normal Mode
<C-w> <C-\><C-n><C-w> - Terminal Window Command
-- LSP
gd vim.lsp.buf.definition - Goto Definition
gr vim.lsp.buf.references - Goto References
K vim.lsp.buf.hover - Hover Documentation
<Leader>rn vim.lsp.buf.rename - Rename
<Leader>ca vim.lsp.buf.code_action - Code Action
<Leader>f vim.lsp.buf.format - Format

View File

@@ -0,0 +1,28 @@
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not (vim.uv or vim.loop).fs_stat(lazypath) then
local lazyrepo = 'https://github.com/folke/lazy.nvim.git'
local out =
vim.fn.system({ 'git', 'clone', '--filter=blob:none', '--branch=stable', lazyrepo, lazypath })
if vim.v.shell_error ~= 0 then
vim.api.nvim_echo({
{ 'Failed to clone lazy.nvim:\n', 'ErrorMsg' },
{ out, 'WarningMsg' },
{ '\nPress any key to exit...' },
}, true, {})
vim.fn.getchar()
os.exit(1)
end
end
vim.opt.rtp:prepend(lazypath)
require('config.options')
require('config.keymaps')
require('config.autocmds')
require('config.clipboard')
require('config.terminal')
require('custom.navigation')
require('lazy').setup({
spec = { { import = 'plugins' } },
change_detection = { notify = false },
rocks = { enabled = false },
})

View File

@@ -0,0 +1,12 @@
{
"conform.nvim": { "branch": "master", "commit": "fbcb4fa7f34bfea9be702ffff481a8e336ebf6ed" },
"fzf-lua": { "branch": "main", "commit": "58ebb27333bd12cb497f27b7da07a677116bc0ef" },
"lazy.nvim": { "branch": "main", "commit": "1ea3c4085785f460fb0e46d2fe1ee895f5f9e7c1" },
"mason.nvim": { "branch": "main", "commit": "ad7146aa61dcaeb54fa900144d768f040090bff0" },
"nvim-autopairs": { "branch": "master", "commit": "7a2c97cccd60abc559344042fefb1d5a85b3e33b" },
"nvim-lint": { "branch": "master", "commit": "9da1fb942dd0668d5182f9c8dee801b9c190e2bb" },
"nvim-tree.lua": { "branch": "master", "commit": "321bc61580fd066b76861c32de3319c3a6d089e7" },
"nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" },
"nvim-ts-autotag": { "branch": "main", "commit": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc" },
"rose-pine": { "branch": "main", "commit": "72a04c4065345b51b56aed4859ea1d884f734097" }
}

View File

@@ -0,0 +1,8 @@
return {
cmd = { "vscode-json-language-server", "--stdio" },
filetypes = { "json", "jsonc" },
init_options = {
provideFormatter = true,
},
root_markers = { ".git" },
}

View File

@@ -0,0 +1,14 @@
return {
cmd = { "lua-language-server" },
filetypes = { "lua" },
root_markers = {
".luarc.json",
".luarc.jsonc",
".luacheckrc",
".stylua.toml",
"stylua.toml",
"selene.toml",
"selene.yml",
".git",
},
}

View File

@@ -0,0 +1,49 @@
-- Automatically create a scratch buffer if Neovim starts with no files
vim.api.nvim_create_autocmd('VimEnter', {
callback = function()
-- Only trigger if no file arguments are passed
if vim.fn.argc() == 0 then
vim.cmd('enew')
vim.bo.buftype = 'nofile'
vim.bo.bufhidden = 'wipe'
vim.bo.swapfile = false
end
end,
})
-- Highlight when yanking (copying) text
vim.api.nvim_create_autocmd('TextYankPost', {
callback = function()
vim.highlight.on_yank()
end,
})
-- Disable comment continuation only when using 'o'/'O', but keep it for <Enter>
vim.api.nvim_create_autocmd('FileType', {
pattern = '*',
callback = function()
vim.opt_local.formatoptions:remove('o')
end,
})
-- Show cursor line only in active window
vim.api.nvim_create_autocmd({ 'WinEnter', 'InsertLeave' }, {
callback = function()
if vim.w.auto_cursorline then
vim.wo.cursorline = true
vim.w.auto_cursorline = nil
end
end,
})
vim.api.nvim_create_autocmd({ 'WinLeave', 'InsertEnter' }, {
callback = function()
if vim.bo.filetype == 'NvimTree' then
return
end
if vim.wo.cursorline then
vim.w.auto_cursorline = true
vim.wo.cursorline = false
end
end,
})

View File

@@ -0,0 +1,25 @@
if vim.env.CONTAINER then
vim.g.clipboard = {
name = 'osc52',
copy = {
['+'] = require('vim.ui.clipboard.osc52').copy('+'),
['*'] = require('vim.ui.clipboard.osc52').copy('*'),
},
paste = {
['+'] = require('vim.ui.clipboard.osc52').paste('+'),
['*'] = require('vim.ui.clipboard.osc52').paste('*'),
},
}
end
vim.schedule(function()
vim.opt.clipboard = 'unnamedplus'
end)
-- TEMP: Check if it helps with edge cases
vim.api.nvim_create_user_command('FixClipboard', function()
vim.cmd('lua require("vim.ui.clipboard.osc52")')
vim.schedule(function()
vim.notify('Clipboard provider reloaded (OSC52)')
end)
end, {})

View File

@@ -0,0 +1,54 @@
local map = vim.keymap.set
map('n', '<leader>q', vim.diagnostic.setloclist)
map({ 'i', 'c' }, 'jk', '<Esc>')
map('n', '<Esc>', '<cmd>nohlsearch<CR>')
-- Prevent overriding the register
map('n', 'x', '"_x')
-- Window Navigation
map('n', '<C-h>', '<C-w>h')
map('n', '<C-l>', '<C-w>l')
map('n', '<C-j>', '<C-w>j')
map('n', '<C-k>', '<C-w>k')
-- Tab management
map('n', '<Leader>tn', ':tabnew<CR>')
map('n', '<Leader>tc', ':tabclose<CR>')
map('n', '<Leader>tl', ':tabnext<CR>')
map('n', '<Leader>th', ':tabprevious<CR>')
map('n', '<Leader>tm.', ':tabmove +1<CR>')
map('n', '<Leader>tm,', ':tabmove -1<CR>')
for i = 1, 9 do
map('n', string.format('<Leader>%d', i), string.format('%dgt', i))
end
-- Buffer Management
-- map('n', '<Leader>bl', ':ls<CR>')
-- map('n', '<Leader>bd', ':bdelete<CR>')
-- map('n', ']b', ':bnext<CR>')
-- map('n', '[b', ':bprevious<CR>')
-- map('n', '<Leader>bb', ':b<Space>')
-- map('n', '<Leader>bo', ':bufdo bd|1bd<CR>')
-- Terminal
map('n', '<leader>tt', ':TermDefault<CR>')
map('n', '<leader>tr', ':TermRelative<CR>')
map('n', '<leader>ts', ':TermSplit<CR>')
map('n', '<leader>tv', ':TermVSplit<CR>')
-- Terminal mode mappings
local tn = '<C-\\><C-n>'
map('t', '<Esc>', tn)
map('t', 'jk', tn)
map('t', '<C-w>', tn .. '<C-w>')
map('t', '<C-h>', '<cmd>wincmd h<CR>')
map('t', '<C-j>', '<cmd>wincmd j<CR>')
map('t', '<C-k>', '<cmd>wincmd k<CR>')
map('t', '<C-l>', '<cmd>wincmd l<CR>')
-- File explorer
vim.keymap.set('n', '<leader>e', '<cmd>NvimTreeToggle<CR>')
vim.keymap.set('n', '<leader>E', '<cmd>NvimTreeOpen<CR>')

View File

@@ -0,0 +1,89 @@
-- Map Leader
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
-- Disable built-in plugins
vim.loader.enable()
vim.g.loaded_gzip = 1
vim.g.loaded_tar = 1
vim.g.loaded_tarPlugin = 1
vim.g.loaded_zip = 1
vim.g.loaded_zipPlugin = 1
vim.g.loaded_getscript = 1
vim.g.loaded_getscriptPlugin = 1
vim.g.loaded_vimball = 1
vim.g.loaded_vimballPlugin = 1
vim.g.loaded_matchit = 1
vim.g.loaded_2html_plugin = 1
vim.g.loaded_rrhelper = 1
vim.g.loaded_netrw = 1 -- use nvim-tree instead
vim.g.loaded_netrwPlugin = 1
-- UI
vim.g.health = { style = 'float' }
vim.g.have_nerd_font = true
vim.opt.termguicolors = false
vim.opt.textwidth = 100
vim.opt.colorcolumn = '+0'
vim.opt.signcolumn = 'no'
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.cursorline = true
vim.opt.winborder = 'rounded'
vim.opt.guicursor = 'n-v-i-c:block'
vim.opt.ruler = false
vim.opt.laststatus = 3
vim.opt.statusline = '── %f %h%w%m%r %= [%l,%c-%L] ──'
vim.opt.fillchars = {
stl = '',
stlnc = '',
horiz = '',
horizdown = '',
horizup = '',
vert = '',
vertleft = '',
vertright = '',
verthoriz = '',
}
-- Wrap
vim.opt.wrap = false
vim.opt.linebreak = true
vim.opt.breakindent = true
-- Indent
vim.opt.shiftwidth = 2 -- Number of spaces to use for (auto)indent
vim.opt.tabstop = 2 -- Number of spaces that a <Tab> in file counts for
vim.opt.softtabstop = 2 -- Number of spaces when pressing <Tab> in insert mode
vim.opt.expandtab = true -- Use spaces instead of literal tab characters
vim.opt.autoindent = true -- Copy indent from the current line when starting a new one
vim.opt.smartindent = true -- Automatically inserts indents in code blocks (for C-like languages)
-- Scroll and mouse
vim.opt.scrolloff = 10
vim.opt.sidescrolloff = 5
vim.opt.mousescroll = 'hor:1,ver:5'
vim.opt.mouse = 'a' -- Enable mouse support
-- Search
vim.opt.ignorecase = true
vim.opt.smartcase = true -- Override ignorecase if search contains upper case chars
vim.opt.inccommand = 'split' -- Live substitution preview
vim.opt.completeopt = { 'menu,menuone,noselect' }
-- Splits
vim.opt.splitright = true
vim.opt.splitbelow = true
-- Persistence
vim.opt.undofile = true
vim.opt.swapfile = false
-- Tweaks
vim.opt.updatetime = 1000
vim.opt.timeout = true
vim.opt.ttimeout = true
vim.opt.timeoutlen = 500
vim.opt.ttimeoutlen = 10

View File

@@ -0,0 +1,62 @@
local term_group = vim.api.nvim_create_augroup('custom-term-open', { clear = true })
vim.api.nvim_create_autocmd('TermOpen', {
group = term_group,
callback = function()
vim.opt_local.number = false
vim.opt_local.relativenumber = false
vim.opt_local.scrolloff = 0
vim.bo.filetype = 'terminal'
vim.cmd.startinsert()
end,
})
-- Close all terminal buffers before quitting
vim.api.nvim_create_autocmd('QuitPre', {
group = vim.api.nvim_create_augroup('shoutoff_terminals', { clear = true }),
callback = function()
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == 'terminal' then
vim.api.nvim_buf_delete(buf, { force = true })
end
end
end,
})
-- Insert when re-entering a terminal window (after switching back)
vim.api.nvim_create_autocmd('BufEnter', {
group = term_group,
pattern = 'term://*',
callback = function()
if vim.bo.buftype == 'terminal' and vim.fn.mode() ~= 'i' then
vim.cmd.startinsert()
end
end,
})
local function open_default()
vim.cmd('terminal')
end
local function open_relative()
local shell = vim.o.shell or 'zsh'
local dir = vim.fn.expand('%:p:h')
vim.cmd(string.format('edit term://%s//%s', dir, shell))
end
local function open_split()
vim.cmd('new')
vim.cmd('wincmd J')
vim.api.nvim_win_set_height(0, 12)
vim.wo.winfixheight = true
vim.cmd('term')
end
local function open_vertical()
vim.cmd('vsplit')
vim.cmd('term')
end
vim.api.nvim_create_user_command('TermDefault', open_default, {})
vim.api.nvim_create_user_command('TermRelative', open_relative, {})
vim.api.nvim_create_user_command('TermSplit', open_split, {})
vim.api.nvim_create_user_command('TermVSplit', open_vertical, {})

View File

@@ -0,0 +1,323 @@
-- Minimal fuzzy finder + content search for Neovim 0.11+
-- Optional: `fdfind` or `fd` for file listing, and `rg` (ripgrep) for text search.
local Fuzzy = {}
--------------------------------------------------------------------
-- 🧩 Helpers
--------------------------------------------------------------------
-- Collect all files (try fdfind/fd first, then globpath)
local function get_file_list()
local handle = io.popen('fdfind --type f 2>/dev/null || fd --type f 2>/dev/null')
if handle then
local result = handle:read('*a')
handle:close()
if result and result ~= '' then
return vim.split(result, '\n', { trimempty = true })
end
end
return vim.fn.globpath('.', '**/*', false, true)
end
-- Create floating input + result windows
local function open_float(prompt)
local input_buf = vim.api.nvim_create_buf(false, true)
local result_buf = vim.api.nvim_create_buf(false, true)
-- mark both buffers as scratch/unlisted
for _, b in ipairs({ input_buf, result_buf }) do
vim.bo[b].bufhidden = 'wipe'
vim.bo[b].buflisted = false
vim.bo[b].swapfile = false
end
vim.bo[input_buf].buftype = 'prompt'
vim.bo[result_buf].buftype = 'nofile'
local width = math.floor(vim.o.columns * 0.7)
local height = 20
local row = math.floor((vim.o.lines - height) / 2)
local col = math.floor((vim.o.columns - width) / 2)
local input_win = vim.api.nvim_open_win(input_buf, true, {
relative = 'editor',
row = row,
col = col,
width = width,
height = 1,
style = 'minimal',
border = 'rounded',
})
vim.fn.prompt_setprompt(input_buf, prompt)
local result_win = vim.api.nvim_open_win(result_buf, false, {
relative = 'editor',
row = row + 2,
col = col,
width = width,
height = height - 2,
style = 'minimal',
border = 'single',
})
return input_buf, result_buf, input_win, result_win
end
--------------------------------------------------------------------
-- 🔵 Highlight current selection
--------------------------------------------------------------------
function Fuzzy:highlight_selection()
if not self.result_buf then
return
end
if not self.ns_id then
self.ns_id = vim.api.nvim_create_namespace('FuzzyHighlight')
end
vim.api.nvim_buf_clear_namespace(self.result_buf, self.ns_id, 0, -1)
if self.matches and self.matches[self.cursor] then
local rel_cursor = self.cursor - (self.scroll or 0)
if rel_cursor >= 1 and rel_cursor <= self.page_size then
vim.api.nvim_buf_set_extmark(self.result_buf, self.ns_id, rel_cursor - 1, 0, {
end_line = rel_cursor,
hl_group = 'Visual',
hl_eol = true,
})
end
end
end
--------------------------------------------------------------------
-- 🔴 Close all floating windows
--------------------------------------------------------------------
function Fuzzy.close()
local wins = { Fuzzy.input_win, Fuzzy.result_win }
for _, win in ipairs(wins) do
if win and vim.api.nvim_win_is_valid(win) then
vim.api.nvim_win_close(win, true)
end
end
Fuzzy.active = false
end
--------------------------------------------------------------------
-- 🟢 File finder
--------------------------------------------------------------------
function Fuzzy.open()
if Fuzzy.active then
Fuzzy.close()
end
Fuzzy.active = true
Fuzzy.files = get_file_list()
Fuzzy.matches = Fuzzy.files
Fuzzy.cursor = 1
Fuzzy.scroll = 0
Fuzzy.page_size = 50
Fuzzy.input_buf, Fuzzy.result_buf, Fuzzy.input_win, Fuzzy.result_win = open_float('Search: ')
local function render_results()
local total = #Fuzzy.matches
if total == 0 then
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, { '-- no matches --' })
return
end
local start_idx = Fuzzy.scroll + 1
local end_idx = math.min(start_idx + Fuzzy.page_size - 1, total)
local display = {}
for i = start_idx, end_idx do
display[#display + 1] = Fuzzy.matches[i]
end
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, display)
Fuzzy:highlight_selection()
end
local function update_results(text)
if text == '' then
Fuzzy.matches = Fuzzy.files
else
Fuzzy.matches = vim.fn.matchfuzzy(Fuzzy.files, text)
end
Fuzzy.cursor, Fuzzy.scroll = 1, 0
render_results()
end
vim.api.nvim_create_autocmd({ 'TextChangedI', 'TextChangedP' }, {
buffer = Fuzzy.input_buf,
callback = function()
local text = vim.fn.getline('.'):gsub('^Search:%s*', '')
update_results(text)
end,
})
vim.keymap.set('i', '<C-n>', function()
if Fuzzy.cursor < #Fuzzy.matches then
Fuzzy.cursor = Fuzzy.cursor + 1
if Fuzzy.cursor > Fuzzy.scroll + Fuzzy.page_size then
Fuzzy.scroll = Fuzzy.scroll + 1
end
render_results()
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<C-p>', function()
if Fuzzy.cursor > 1 then
Fuzzy.cursor = Fuzzy.cursor - 1
if Fuzzy.cursor <= Fuzzy.scroll then
Fuzzy.scroll = math.max(Fuzzy.scroll - 1, 0)
end
render_results()
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<CR>', function()
local choice = Fuzzy.matches[Fuzzy.cursor]
if choice then
Fuzzy.close()
vim.cmd.edit(vim.fn.fnameescape(choice))
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<Esc>', Fuzzy.close, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<C-c>', Fuzzy.close, { buffer = Fuzzy.input_buf })
vim.keymap.set('n', '<Esc>', Fuzzy.close, { buffer = Fuzzy.input_buf })
vim.keymap.set('n', 'q', Fuzzy.close, { buffer = Fuzzy.input_buf })
vim.cmd.startinsert()
end
--------------------------------------------------------------------
-- 🟣 Ripgrep-based content search (scrolling + match highlighting)
--------------------------------------------------------------------
function Fuzzy.open_grep()
if Fuzzy.active then
Fuzzy.close()
end
Fuzzy.active = true
Fuzzy.input_buf, Fuzzy.result_buf, Fuzzy.input_win, Fuzzy.result_win = open_float('Grep: ')
Fuzzy.matches, Fuzzy.cursor, Fuzzy.scroll = {}, 1, 0
Fuzzy.page_size = 50
Fuzzy.ns_id = vim.api.nvim_create_namespace('FuzzyHighlight')
local function render_results(query)
local total = #Fuzzy.matches
if total == 0 then
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, { '-- no matches --' })
return
end
local start_idx = Fuzzy.scroll + 1
local end_idx = math.min(start_idx + Fuzzy.page_size - 1, total)
local display = {}
for i = start_idx, end_idx do
display[#display + 1] = Fuzzy.matches[i]
end
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, display)
vim.api.nvim_buf_clear_namespace(Fuzzy.result_buf, Fuzzy.ns_id, 0, -1)
-- highlight selection
local rel_cursor = math.min(Fuzzy.cursor - Fuzzy.scroll, #display)
vim.api.nvim_buf_set_extmark(Fuzzy.result_buf, Fuzzy.ns_id, rel_cursor - 1, 0, {
end_line = rel_cursor,
hl_group = 'Visual',
hl_eol = true,
})
-- highlight query matches
if query and query ~= '' then
local pattern = vim.pesc(query)
for i, line in ipairs(display) do
for s, e in line:gmatch('()' .. pattern .. '()') do
vim.api.nvim_buf_set_extmark(Fuzzy.result_buf, Fuzzy.ns_id, i - 1, s - 1, {
end_col = e - 1,
hl_group = 'Search',
})
end
end
end
end
local function run_grep(query)
if query == '' then
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, { '-- type to search --' })
return
end
local handle = io.popen('rg --vimgrep --hidden --smart-case ' .. vim.fn.shellescape(query))
if not handle then
return
end
local result = handle:read('*a')
handle:close()
Fuzzy.matches = vim.split(result, '\n', { trimempty = true })
Fuzzy.cursor, Fuzzy.scroll = 1, 0
render_results(query)
end
vim.api.nvim_create_autocmd({ 'TextChangedI', 'TextChangedP' }, {
buffer = Fuzzy.input_buf,
callback = function()
local text = vim.fn.getline('.'):gsub('^Grep:%s*', '')
run_grep(text)
end,
})
vim.keymap.set('i', '<C-n>', function()
if Fuzzy.cursor < #Fuzzy.matches then
Fuzzy.cursor = Fuzzy.cursor + 1
if Fuzzy.cursor > Fuzzy.scroll + Fuzzy.page_size then
Fuzzy.scroll = Fuzzy.scroll + 1
end
local query = vim.fn.getline('.'):gsub('^Grep:%s*', '')
render_results(query)
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<C-p>', function()
if Fuzzy.cursor > 1 then
Fuzzy.cursor = Fuzzy.cursor - 1
if Fuzzy.cursor <= Fuzzy.scroll then
Fuzzy.scroll = math.max(Fuzzy.scroll - 1, 0)
end
local query = vim.fn.getline('.'):gsub('^Grep:%s*', '')
render_results(query)
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<CR>', function()
local line = Fuzzy.matches[Fuzzy.cursor]
if line then
local parts = vim.split(line, ':')
local file, lnum = parts[1], tonumber(parts[2]) or 1
Fuzzy.close()
vim.cmd.edit(vim.fn.fnameescape(file))
vim.api.nvim_win_set_cursor(0, { lnum, 0 })
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<Esc>', function()
Fuzzy.close()
end, { buffer = Fuzzy.input_buf })
vim.cmd.startinsert()
end
--------------------------------------------------------------------
-- 🧩 Commands & Keymaps
--------------------------------------------------------------------
vim.api.nvim_create_user_command('FuzzyLive', function()
Fuzzy.open()
end, {})
vim.api.nvim_create_user_command('FuzzyGrep', function()
Fuzzy.open_grep()
end, {})
vim.keymap.set('n', '<leader>f', function()
vim.cmd.FuzzyLive()
end, { desc = 'Open fuzzy file finder' })
vim.keymap.set('n', '<leader>g', function()
vim.cmd.FuzzyGrep()
end, { desc = 'Search file contents with ripgrep' })
return Fuzzy

View File

@@ -0,0 +1,26 @@
return {
'triimdev/invero.nvim',
lazy = false,
priority = 1000,
dev = true,
config = function()
vim.api.nvim_create_user_command('ReloadInvero', function()
require('invero').invalidate_cache()
vim.cmd('Lazy reload invero.nvim')
end, {})
require('invero').setup({
highlights = function(c, tool)
c.bg_float = tool(152)
return {
WinSeparator = { fg = c.outline, bg = c.base },
StatusLine = { fg = c.outline, bg = c.base },
StatusLineNC = { fg = c.text, bg = c.base, bold = true },
}
end,
})
vim.o.background = 'light'
vim.cmd.colorscheme('invero')
end,
}

View File

@@ -0,0 +1,148 @@
local function my_on_attach(bufnr)
local api = require('nvim-tree.api')
local opts = { buffer = bufnr }
-- basics: copy/cut/paste/create/rename/remove
vim.keymap.set('n', 'c', api.fs.copy.node, opts)
vim.keymap.set('n', 'x', api.fs.cut, opts)
vim.keymap.set('n', 'p', api.fs.paste, opts)
vim.keymap.set('n', 'a', api.fs.create, opts)
vim.keymap.set('n', 'r', api.fs.rename, opts)
vim.keymap.set('n', 'R', api.fs.rename_basename, opts)
vim.keymap.set('n', 'd', api.fs.remove, opts)
-- bulk mark and delete/move
vim.keymap.set('n', 's', api.marks.toggle, opts)
vim.keymap.set('n', 'S', api.marks.clear, opts)
vim.keymap.set('n', 'bd', api.marks.bulk.delete, opts)
vim.keymap.set('n', 'bm', api.marks.bulk.move, opts)
-- copy filename/path
vim.keymap.set('n', 'y', api.fs.copy.filename, opts)
vim.keymap.set('n', 'Y', api.fs.copy.relative_path, opts)
vim.keymap.set('n', 'gy', api.fs.copy.absolute_path, opts)
vim.keymap.set('n', 'ge', api.fs.copy.basename, opts)
-- expand/collapse
vim.keymap.set('n', 'e', api.tree.expand_all, opts)
vim.keymap.set('n', 'E', api.tree.collapse_all, opts)
-- filter
vim.keymap.set('n', 'f', api.live_filter.start, opts)
vim.keymap.set('n', 'F', api.live_filter.clear, opts)
-- navigate
vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts)
vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts)
vim.keymap.set('n', 'P', api.node.navigate.parent, opts)
-- open
vim.keymap.set('n', '<CR>', api.node.open.edit, opts)
vim.keymap.set('n', 'o', api.node.open.edit, opts)
vim.keymap.set('n', 'O', api.node.open.no_window_picker, opts)
-- miscellaneous
vim.keymap.set('n', 'K', api.node.show_info_popup, opts)
vim.keymap.set('n', 'U', api.tree.reload, opts)
end
return {
'nvim-tree/nvim-tree.lua',
version = '*',
dev = true,
opts = {
on_attach = my_on_attach,
view = { signcolumn = 'no' },
actions = { file_popup = { open_win_config = { border = 'rounded' } } },
renderer = {
root_folder_label = false,
-- root_folder_label = function(path)
-- return '-- ' .. vim.fn.fnamemodify(path, ':t') .. ' --'
-- end,
special_files = {},
highlight_hidden = 'all',
highlight_clipboard = 'all',
indent_markers = {
enable = true,
inline_arrows = false,
icons = { corner = '', none = '', bottom = ' ' },
},
icons = {
bookmarks_placement = 'after',
git_placement = 'after',
show = {
file = false,
folder = false,
folder_arrow = false, -- KEEP FALSE
git = true,
modified = false,
hidden = false,
diagnostics = false,
bookmarks = true,
},
glyphs = {
-- default = '•',
default = ' ',
symlink = '',
bookmark = '󰆤',
modified = '',
hidden = '󰜌',
folder = {
arrow_closed = '',
arrow_open = '',
default = '',
open = '',
empty = '',
empty_open = '',
symlink = '',
symlink_open = '',
},
git = {
unstaged = '', -- '✗',
staged = '',
unmerged = '',
renamed = '',
untracked = '',
deleted = '', -- '󰧧',
ignored = '',
},
},
},
},
hijack_cursor = true,
prefer_startup_root = true,
update_focused_file = {
enable = true,
update_root = { enable = true, ignore_list = {} },
exclude = false,
},
modified = { enable = true, show_on_dirs = true, show_on_open_dirs = true },
filters = {
enable = true,
git_ignored = true,
dotfiles = false,
git_clean = false,
no_buffer = false,
no_bookmark = false,
custom = {},
exclude = {},
},
filesystem_watchers = {
enable = true,
debounce_delay = 50,
ignore_dirs = {
'/.git',
'/.DS_Store',
'/build',
'/dist',
'/public',
'/node_modules',
'/target',
},
},
},
}

View File

@@ -0,0 +1,127 @@
vim.keymap.set('n', '<leader>d', vim.diagnostic.open_float, { noremap = true, silent = true })
vim.diagnostic.config({
update_in_insert = false,
virtual_text = {
prefix = '', -- remove annoying ▎ etc
format = function(diagnostic)
if diagnostic.source then
return string.format('[%s] %s', diagnostic.source, diagnostic.message)
end
return diagnostic.message
end,
},
float = {
border = 'rounded',
source = true, -- show source in floating window too
},
severity_sort = true,
})
vim.lsp.enable({ 'lua_ls' })
vim.lsp.enable({ 'json_ls' })
return {
{ 'mason-org/mason.nvim', config = true },
{ 'windwp/nvim-ts-autotag', config = true },
{ 'windwp/nvim-autopairs', event = 'InsertEnter', config = true },
-- { 'saghen/blink.cmp', version = '1.*' },
{
'nvim-treesitter/nvim-treesitter',
build = ':TSUpdate',
main = 'nvim-treesitter.configs',
opts = {
highlight = { enable = true },
incremental_selection = { enable = true },
textobjects = { enable = true },
ensure_installed = {
-- Documentation
'vim',
'vimdoc',
'markdown',
'markdown_inline',
-- Data
'gitcommit',
'gitignore',
'dockerfile',
'diff',
'json',
'jsonc',
-- Scripting
'bash',
'lua',
'sql',
-- Programming
'c',
'cpp',
'go',
'rust',
'python',
-- Web
'html',
'css',
'javascript',
'typescript',
'tsx',
},
},
},
{
'mfussenegger/nvim-lint',
event = { 'BufReadPre', 'BufNewFile' },
opts = {
linters_by_ft = {
lua = { 'luacheck' },
python = { 'ruff' },
javascript = { 'eslint_d' },
},
},
config = function(_, opts)
local lint = require('lint')
lint.linters_by_ft = opts.linters_by_ft
vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, {
group = vim.api.nvim_create_augroup('lint_autocmd', { clear = true }),
callback = function()
lint.try_lint()
end,
})
end,
},
{
'stevearc/conform.nvim',
event = { 'BufWritePre' },
opts = {
-- Automatically format on save
format_on_save = {
timeout_ms = 500,
lsp_format = 'fallback', -- Use LSP when no formatter is configured
},
-- Formatters per filetype
default_format_opts = { stop_after_first = true },
formatters_by_ft = {
lua = { 'stylua' },
sh = { 'shfmt' },
swift = { 'swift_format' },
python = { 'isort', 'black' },
javascript = { 'prettierd', 'prettier' },
javascriptreact = { 'prettierd', 'prettier' },
typescript = { 'prettierd', 'prettier' },
typescriptreact = { 'prettierd', 'prettier' },
},
},
config = function(_, opts)
require('conform').setup(opts)
-- Create a command to format manually
vim.api.nvim_create_user_command('Format', function()
require('conform').format({
async = true,
lsp_format = 'fallback',
})
end, { desc = 'Format current buffer' })
end,
},
}

View File

@@ -20,16 +20,14 @@ set -g mouse on
set -g set-titles on set -g set-titles on
set -g set-titles-string "#S" set -g set-titles-string "#S"
# set -g remain-on-exit on
set -gw pane-base-index 1 # pane index set -gw pane-base-index 1 # pane index
##### Appearance ##### ##### Appearance #####
set -g status-style fg=black,bg=default set -g status-style fg=black,bg=default
set -g window-status-current-style fg=blue,bold set -g window-status-current-style fg=blue,bold
set -g message-style fg=blue,bg=default set -g message-style fg=blue,bg=default
set -g status-left "#[fg=blue,bold][#{s/^dev-//:#{session_name}}] " set -g status-left "#[fg=blue,bold][#S] "
set -g status-right " #{?DF_IMAGE,#{DF_IMAGE} | ,}#{?DF_NAMESPACE,#{DF_NAMESPACE},#H}@#{?DF_PLATFORM,#{DF_PLATFORM},local}" set -g status-right "host:#H | machine:#{?TARGET_MACHINE,#{TARGET_MACHINE},local}"
set -g status-left-length 50 set -g status-left-length 50
set -g status-right-length 50 set -g status-right-length 50
set -g pane-active-border-style fg=blue set -g pane-active-border-style fg=blue
@@ -44,9 +42,6 @@ bind -r j select-pane -D
bind -r k select-pane -U bind -r k select-pane -U
bind -r l select-pane -R bind -r l select-pane -R
# Last window instead of session
bind ';' last-window
unbind '"' unbind '"'
unbind "%" unbind "%"
unbind s unbind s
@@ -63,9 +58,3 @@ bind c confirm-before -p "kill-pane \#P? (y/n)" kill-pane
##### Misc ##### ##### Misc #####
bind r source-file ~/.tmux.conf \; display "Reloaded!" bind r source-file ~/.tmux.conf \; display "Reloaded!"
unbind d
bind e detach
bind d command-prompt -I "flow " 'run-shell "/home/tomas/bin/dev-tmux-wrapper.sh %1 --from #{session_name}"'

View File

@@ -1,78 +0,0 @@
[env]
# TERM = "xterm-256color"
[font]
size = 14
normal = { family = "SF Mono", style = "Regular" }
bold = { family = "SF Mono", style = "Bold" }
italic = { family = "SF Mono", style = "Regular Italic" }
bold_italic = { family = "SF Mono", style = "Bold Italic" }
# normal = { family = "Maple Mono", style = "Regular" }
# bold = { family = "Maple Mono", style = "Bold" }
# italic = { family = "Maple Mono", style = "Italic" }
# bold_italic = { family = "Maple Mono", style = "Bold Italic" }
# offset = { x = -1, y = 0 }
[window]
padding = { x = 2, y = 0 }
dynamic_padding = true
# resize_increments = true
[keyboard]
bindings = [
# Create new window
{ action = "SpawnNewInstance", key = "N", mods = "Command" },
# Jump back one word
{ key = "Left", mods = "Alt", chars = "\u001bb" },
# Jump forward one word
{ key = "Right", mods = "Alt", chars = "\u001bf" },
# Move to start of line
{ key = "Left", mods = "Command", chars = "\u0001" },
# Move to end of line
{ key = "Right", mods = "Command", chars = "\u0005" },
# Delete backwards
{ key = "Back", mods = "Alt", chars = "\u001B\u007F" }, # word
{ key = "Back", mods = "Command", chars = "\u0015" }, # line
# Delete forwards
{ key = "Delete", mods = "Alt", chars = "\u001Bd" }, # word
{ key = "Delete", mods = "Command", chars = "\u000B" } # line
]
[scrolling]
multiplier = 1
[general]
live_config_reload = true
[colors.primary]
background = "#eeeeee"
foreground = "#444444"
[colors.cursor]
text = "#eeeeee"
cursor = "#005fff"
[colors.selection]
text = "#434343"
background = "#e0e0e0"
[colors.normal]
black = "#000000"
red = "#aa3731"
green = "#448c27"
yellow = "#cb9000"
blue = "#325cc0"
magenta = "#7a3e9d"
cyan = "#0083b2"
white = "#bbbbbb"
[colors.bright]
black = "#000000"
red = "#aa3731"
green = "#448c27"
yellow = "#cb9000"
blue = "#325cc0"
magenta = "#7a3e9d"
cyan = "#0083b2"
white = "#bbbbbb"

View File

@@ -1,27 +0,0 @@
[colors.primary]
background = '#F7F7F7'
foreground = '#434343'
[colors.cursor]
text = '#F7F7F7'
cursor = '#434343'
[colors.normal]
black = '#000000'
red = '#AA3731'
green = '#448C27'
yellow = '#CB9000'
blue = '#325CC0'
magenta = '#7A3E9D'
cyan = '#0083B2'
white = '#BBBBBB'
[colors.bright]
black = '#777777'
red = '#F05050'
green = '#60CB00'
yellow = '#FFBC5D'
blue = '#007ACC'
magenta = '#E64CE6'
cyan = '#00AACB'
white = '#FFFFFF'

135
config/macos/bin/con Executable file
View File

@@ -0,0 +1,135 @@
#!/usr/bin/env bash
set -euo pipefail
ATTACH_TMUX=1
DRY_RUN=0
TMUX_SESSION_DEFAULT="default"
df_platform=""
df_namespace=""
df_user=""
ssh_identity=""
ssh_host=""
ssh_args=()
usage() {
local prog
prog=$(basename "$0")
echo "Usage: $prog <platform> [user@]namespace [--no-tmux|-t] [--dry-run|-n] [-- <ssh args...>]" >&2
echo
echo "Examples:"
echo " $prog orb namespace"
echo " $prog utm user@namespace --no-tmux"
echo " $prog core user@namespace --dry-run -- -v -p 2222"
exit 1
}
parse_args() {
if [[ $# -lt 2 ]]; then
usage
fi
df_platform="$1"
local user_namespace_arg="$2"
shift 2
# Extract df_user and df_namespace
if [[ "$user_namespace_arg" == *@* ]]; then
df_user="${user_namespace_arg%@*}"
df_namespace="${user_namespace_arg#*@}"
else
df_user="$USER"
df_namespace="$user_namespace_arg"
fi
# Parse remaining flags and ssh args
while [[ $# -gt 0 ]]; do
case "$1" in
-t|--no-tmux)
ATTACH_TMUX=0
shift
;;
-n|--dry-run)
DRY_RUN=1
shift
;;
--)
shift
ssh_args+=("$@")
break
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
}
resolve_host() {
case "$df_platform" in
orb)
# orb-stack handles user@namespace internally
ssh_host="${df_namespace}@orb"
;;
utm)
ssh_host="${df_namespace}.utm.local"
ssh_identity="$HOME/.ssh/id_ed25519_internal"
;;
core)
ssh_host="${df_namespace}.core.lan"
ssh_identity="$HOME/.ssh/id_ed25519_internal"
;;
ec2)
ssh_host="${df_namespace}.ec2.internal"
;;
hetzner)
ssh_host="${df_namespace}.hetzner.test"
;;
*)
echo "Error: unknown platform '$df_platform'" >&2
exit 1
;;
esac
}
build_ssh_cmd() {
local cmd=(ssh -tt)
if [[ -n "$ssh_identity" ]]; then
cmd+=(-i "$ssh_identity" -o IdentitiesOnly=yes)
fi
if [[ ${#ssh_args[@]} -gt 0 ]]; then
cmd+=("${ssh_args[@]}")
fi
cmd+=("${df_user}@${ssh_host}")
if [[ $ATTACH_TMUX -eq 1 ]]; then
cmd+=("tmux" "new-session" "-As" "$TMUX_SESSION_DEFAULT"
"-e" "DF_NAMESPACE=$df_namespace"
"-e" "DF_PLATFORM=$df_platform")
fi
echo "${cmd[@]}"
}
main() {
parse_args "$@"
resolve_host
ssh_cmd=($(build_ssh_cmd))
if [[ $DRY_RUN -eq 1 ]]; then
echo "Dry run command:"
printf '%q ' "${ssh_cmd[@]}"
echo
exit 0
fi
exec "${ssh_cmd[@]}"
}
main "$@"

23
config/macos/bin/sync_theme Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
# URL="https://raw.githubusercontent.com/triimdev/invero.nvim/refs/heads/main/extras/ghostty/invero_day"
# THEME_DIR="$HOME/.config/ghostty/themes"
# THEME_NAME="Invero Day"
URL="https://raw.githubusercontent.com/triimdev/invero.nvim/refs/heads/main/extras/wezterm/invero_day.toml"
THEME_DIR="$HOME/.config/wezterm/colors"
THEME_NAME="Invero Day.toml"
THEME_PATH="${THEME_DIR}/${THEME_NAME}"
mkdir -p "$THEME_DIR"
if curl -fsSL -o "$THEME_PATH" "$URL"; then
echo "Theme downloaded to $THEME_PATH"
else
echo "Failed to download theme."
exit 1
fi

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
file=/tmp/vm-switch.txt
# Ensure the file exists
touch "$file"
echo "Listening on $file ..."
tail -n0 -F "$file" | while read vm; do
[ -n "$vm" ] && echo "Switch requested: $vm" && ~/bin/work "$vm" &
done

3
config/macos/bin/vmlist-sync Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
orbctl list > /tmp/vmlist.txt

10
config/macos/bin/work Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
# Usage: work <vm>
vm="$1"
if [ -z "$vm" ]; then
echo "Usage: work <vm>"
exit 1
fi
exec vm "${vm}-orb"

View File

@@ -1,13 +0,0 @@
#!/bin/bash
options=(
order=above
width=2.0
hidpi=on
active_color=0xff2b2b2b
inactive_color=0xff2b2b2b
# inactive_color=0x00000000
whitelist="wezterm-gui"
)
borders "${options[@]}"

View File

@@ -1,33 +0,0 @@
#term = xterm-256color
theme = Invero Day
# Font
font-family = "Maple Mono"
font-size = 13
font-thicken = true
font-thicken-strength = 120
font-feature = -liga, -dlig, -calt
adjust-underline-thickness = 1
adjust-strikethrough-thickness = 1
adjust-overline-thickness = 1
adjust-box-thickness = 1
adjust-cell-width = -7%
adjust-cell-height = -2
# Cursor
cursor-style = block
cursor-style-blink = false
mouse-hide-while-typing = true
shell-integration-features = ssh-terminfo,ssh-env,no-cursor
# Window
window-height = 80
window-width = 128
window-padding-x = 4
window-padding-y = 0
window-padding-color = extend
macos-titlebar-style = native
macos-icon = custom
window-inherit-working-directory = false

View File

@@ -1,25 +1,21 @@
brew "bash" tap "homebrew/bundle"
tap "homebrew/services"
brew "dnsmasq", restart_service: :changed brew "dnsmasq", restart_service: :changed
brew "tmux" brew "neovim"
cask "brave-browser" cask "daisydisk"
cask "bruno"
cask "dbeaver-community"
cask "discord" cask "discord"
cask "firefox" cask "firefox"
cask "font-maple-mono"
cask "font-maple-mono-nf"
cask "ghostty" cask "ghostty"
cask "google-chrome" cask "google-chrome"
cask "karabiner-elements" cask "karabiner-elements"
cask "linearmouse" cask "linearmouse"
cask "macfuse" cask "obsidian"
cask "orbstack"
cask "proton-drive" cask "proton-drive"
cask "protonvpn" cask "protonvpn"
cask "rectangle" cask "rectangle"
cask "slack" cask "slack"
cask "sol" cask "sol"
cask "spotify" cask "spotify"
cask "sublime-text" cask "utm"
cask "utm@beta" cask "visual-studio-code"
cask "zoom" cask "zoom"

View File

@@ -0,0 +1,20 @@
{
"global": { "show_in_menu_bar": false },
"profiles": [
{
"devices": [
{
"identifiers": { "is_keyboard": true },
"simple_modifications": [
{
"from": { "key_code": "non_us_backslash" },
"to": [{ "key_code": "grave_accent_and_tilde" }]
}
]
}
],
"name": "Default profile",
"selected": true
}
]
}

View File

@@ -0,0 +1,44 @@
{
"global": { "show_in_menu_bar": false },
"profiles": [
{
"devices": [
{
"identifiers": { "is_keyboard": true },
"simple_modifications": [
{
"from": { "key_code": "non_us_backslash" },
"to": [{ "key_code": "grave_accent_and_tilde" }]
}
]
},
{
"identifiers": {
"is_keyboard": true,
"product_id": 49164,
"vendor_id": 7276
},
"simple_modifications": [
{
"from": { "key_code": "left_command" },
"to": [{ "key_code": "left_option" }]
},
{
"from": { "key_code": "left_option" },
"to": [{ "key_code": "left_command" }]
}
]
}
],
"name": "Default profile",
"selected": true,
"simple_modifications": [
{
"from": { "key_code": "caps_lock" },
"to": [{ "key_code": "left_control" }]
}
],
"virtual_hid_keyboard": { "keyboard_type_v2": "ansi" }
}
]
}

View File

@@ -0,0 +1,43 @@
{
"profiles": [
{
"devices": [
{
"identifiers": { "is_keyboard": true },
"simple_modifications": [
{
"from": { "key_code": "non_us_backslash" },
"to": [{ "key_code": "grave_accent_and_tilde" }]
}
]
},
{
"identifiers": {
"is_keyboard": true,
"product_id": 49164,
"vendor_id": 7276
},
"simple_modifications": [
{
"from": { "key_code": "left_command" },
"to": [{ "key_code": "left_option" }]
},
{
"from": { "key_code": "left_option" },
"to": [{ "key_code": "left_command" }]
}
]
}
],
"name": "Default profile",
"selected": true,
"simple_modifications": [
{
"from": { "key_code": "caps_lock" },
"to": [{ "key_code": "left_control" }]
}
],
"virtual_hid_keyboard": { "keyboard_type_v2": "ansi" }
}
]
}

View File

@@ -0,0 +1,44 @@
{
"global": { "show_in_menu_bar": false },
"profiles": [
{
"devices": [
{
"identifiers": { "is_keyboard": true },
"simple_modifications": [
{
"from": { "key_code": "non_us_backslash" },
"to": [{ "key_code": "grave_accent_and_tilde" }]
}
]
},
{
"identifiers": {
"is_keyboard": true,
"product_id": 49164,
"vendor_id": 7276
},
"simple_modifications": [
{
"from": { "key_code": "left_command" },
"to": [{ "key_code": "left_option" }]
},
{
"from": { "key_code": "left_option" },
"to": [{ "key_code": "left_command" }]
}
]
}
],
"name": "Default profile",
"selected": true,
"simple_modifications": [
{
"from": { "key_code": "caps_lock" },
"to": [{ "key_code": "left_control" }]
}
],
"virtual_hid_keyboard": { "keyboard_type_v2": "ansi" }
}
]
}

View File

@@ -1,15 +0,0 @@
{
"profiles": [
{
"name": "Default profile",
"selected": true,
"simple_modifications": [
{
"from": { "key_code": "caps_lock" },
"to": [{ "key_code": "left_control" }]
}
],
"virtual_hid_keyboard": { "keyboard_type_v2": "iso" }
}
]
}

View File

@@ -4,20 +4,38 @@
{ {
"devices": [ "devices": [
{ {
"identifiers": { "identifiers": { "is_keyboard": true },
"is_keyboard": true, "simple_modifications": [
"product_id": 50475, {
"vendor_id": 1133 "from": { "key_code": "non_us_backslash" },
}, "to": [{ "key_code": "grave_accent_and_tilde" }]
"ignore_vendor_events": true }
]
}, },
{ {
"identifiers": { "identifiers": {
"is_keyboard": true, "is_keyboard": true,
"product_id": 50504, "product_id": 49164,
"vendor_id": 1133 "vendor_id": 7276
}, },
"ignore_vendor_events": true "simple_modifications": [
{
"from": { "key_code": "left_command" },
"to": [{ "key_code": "left_option" }]
},
{
"from": { "key_code": "left_option" },
"to": [{ "key_code": "left_command" }]
},
{
"from": { "key_code": "escape" },
"to": [{ "key_code": "grave_accent_and_tilde" }]
},
{
"from": { "key_code": "grave_accent_and_tilde" },
"to": [{ "key_code": "escape" }]
}
]
} }
], ],
"name": "Default profile", "name": "Default profile",
@@ -28,7 +46,7 @@
"to": [{ "key_code": "left_control" }] "to": [{ "key_code": "left_control" }]
} }
], ],
"virtual_hid_keyboard": { "keyboard_type_v2": "iso" } "virtual_hid_keyboard": { "keyboard_type_v2": "ansi" }
} }
] ]
} }

View File

@@ -1,54 +0,0 @@
# ~/.config/kitty/choose_tab.py
from kitty.boss import get_boss
from kittens.tui.handler import Handler
from kittens.tui.loop import Loop
class TabPicker(Handler):
def __init__(self):
super().__init__()
boss = get_boss()
win = boss.active_window
self.osw = win.os_window if win else None
self.tabs = list(self.osw.tabs) if self.osw else []
self.index = 0
def draw(self, screen):
screen.clear()
if not self.tabs:
screen.write_line("No tabs. Esc to exit.")
else:
screen.write_line("Choose a tab (↑/↓ Enter Esc)")
for i, t in enumerate(self.tabs):
mark = "" if t is self.osw.active_tab else " "
sel = ">" if i == self.index else " "
title = t.title or f"Tab {i+1}"
screen.write_line(f"{sel} {mark} {title}")
screen.refresh()
def on_key(self, event):
if not self.tabs:
if event.key in ("escape", "enter"):
self.quit_loop()
return
k = event.key
if k in ("up", "k"):
self.index = (self.index - 1) % len(self.tabs)
elif k in ("down", "j"):
self.index = (self.index + 1) % len(self.tabs)
elif k == "enter":
self.osw.set_active_tab(self.tabs[self.index])
self.quit_loop()
elif k == "escape":
self.quit_loop()
self.refresh()
def main(args):
# Correct signature for older Kitty: pass the class name and a title string
Loop(TabPicker, "choose_tab").run()
def handle_result(args, answer, target_window_id, boss):
pass

View File

@@ -1,35 +0,0 @@
# vim:ft=kitty
background #eeeeee
foreground #444444
cursor #005fff
cursor_text_color #eeeeee
selection_background #dadada
selection_foreground #444444
url_color #005fff
# Tabs
active_tab_background #005fff
active_tab_foreground #eeeeee
inactive_tab_background #dadada
inactive_tab_foreground #9e9e9e
# normal
color0 #444444
color1 #ff0000
color2 #00af5f
color3 #d75f00
color4 #005fff
color5 #5f5f87
color6 #afd7ff
color7 #eeeeee
# bright
color8 #444444
color9 #ff0000
color10 #00af5f
color11 #d75f00
color12 #005fff
color13 #5f5f87
color14 #afd7ff
color15 #eeeeee

Binary file not shown.

View File

@@ -1,73 +0,0 @@
include invero.conf
# term xterm-256color
enable_audio_bell no
cursor_shape block
wheel_scroll_multiplier 1.0
touch_scroll_multiplier 1.0
wheel_scroll_min_lines 1
shell_integration no-cursor
cursor_blink_interval 0
remember_window_position yes
remember_window_size yes
# Font
font_family Maple Mono
font_size 13.0
# disable_ligatures always
# undercurl_style thick-sparse
modify_font cell_width 94%
modify_font cell_height -2px
# modify_font baseline 2px
# modify_font underline_thickness 180%
# modify_font underline_position 2px
# modify_font strikethrough_positon 2px
text_composition_strategy legacy
# underline_exclusion 0
placement_strategy top
window_margin_width 0 0
window_padding_width 0 4
# modify_font cell_height -1
# modify_font cell_width 90%
# Navigation / editing
# Make Option act as Alt on macOS
macos_option_as_alt yes
# Use explicit bytes (no ambiguity), not \x1bb etc.
map opt+left send_text all \x1b\x62
map opt+right send_text all \x1b\x66
map cmd+left send_text all \x01
map cmd+right send_text all \x05
map opt+backspace send_text all \x1b\x7f
map cmd+backspace send_text all \x15
map opt+delete send_text all \x1b\x64
map cmd+delete send_text all \x0b
# New window / tab
map cmd+n new_os_window
map cmd+t new_tab
map cmd+1 goto_tab 1
map cmd+2 goto_tab 2
map cmd+3 goto_tab 3
map cmd+4 goto_tab 4
map cmd+5 goto_tab 5
map cmd+6 goto_tab 6
map cmd+7 goto_tab 7
map cmd+8 goto_tab 8
map cmd+9 goto_tab 9
# BEGIN_KITTY_FONTS
# font_family family="JetBrains Mono"
bold_font auto
italic_font auto
bold_italic_font auto
# END_KITTY_FONTS

Binary file not shown.

Binary file not shown.

View File

@@ -1,36 +0,0 @@
[colors]
background = "#eeeeee"
foreground = "#444444"
cursor_bg = "#005fff"
cursor_border = "#9e9e9e"
cursor_fg = "#eeeeee"
selection_bg = "#dadada"
selection_fg = "#444444"
split = "#005fff"
compose_cursor = "#d75f00"
scrollbar_thumb = "#9e9e9e"
copy_mode_active_highlight_bg = { Color = "#dadada" }
copy_mode_active_highlight_fg = { Color = "#d75f00" }
copy_mode_inactive_highlight_bg = { Color = "#eeeeee" }
copy_mode_inactive_highlight_fg = { Color = "#d75f00" }
ansi = ["#444444", "#ff0000", "#00af5f", "#d75f00", "#005fff", "#5f5f87", "#afd7ff", "#eeeeee"]
brights = ["#444444", "#ff0000", "#00af5f", "#d75f00", "#005fff", "#5f5f87", "#afd7ff", "#eeeeee"]
[colors.tab_bar]
inactive_tab_edge = "#ff0000"
background = "#444444"
[colors.tab_bar.active_tab]
fg_color = "#eeeeee"
bg_color = "#444444"
intensity = "Bold"
[colors.tab_bar.inactive_tab]
fg_color = "#9e9e9e"
bg_color = "#444444"
[colors.tab_bar.inactive_tab_hover]
fg_color = "#dadada"
bg_color = "#444444"

View File

@@ -1,72 +0,0 @@
local wezterm = require("wezterm")
local config = wezterm.config_builder()
local act = wezterm.action
-- General
config.term = "wezterm"
config.color_scheme = "Invero Day"
config.use_ime = false
-- Font
config.font = wezterm.font({ family = "Maple Mono NF", weight = "Medium" })
config.font_size = 13
config.harfbuzz_features = { "calt=0", "clig=0", "liga=0" } -- disables alternates and ligatures
config.underline_position = -4
config.underline_thickness = 3
-- Appearance
config.bold_brightens_ansi_colors = false
config.window_padding = { left = "0.5cell", right = "0.5cell", top = 6, bottom = 0 }
config.window_content_alignment = { horizontal = "Center", vertical = "Top" }
config.cell_width = 0.9
config.line_height = 0.9
-- Tabs
config.use_fancy_tab_bar = false
config.show_new_tab_button_in_tab_bar = false
config.hide_tab_bar_if_only_one_tab = true
-- Events
wezterm.on("toggle-tabbar", function(window, _)
local overrides = window:get_config_overrides() or {}
if overrides.enable_tab_bar == false then
wezterm.log_info("tab bar shown")
overrides.enable_tab_bar = true
else
wezterm.log_info("tab bar hidden")
overrides.enable_tab_bar = false
end
window:set_config_overrides(overrides)
end)
-- Keybindings
config.keys = {
{ mods = "OPT", key = "LeftArrow", action = act.SendString("\x1bb") }, -- Jump back one word
{ mods = "OPT", key = "RightArrow", action = act.SendString("\x1bf") }, -- Jump forward one word
{ mods = "CMD", key = "LeftArrow", action = act.SendString("\x01") }, -- Move to start of line
{ mods = "CMD", key = "RightArrow", action = act.SendString("\x05") }, -- Move to end of line
{ mods = "OPT", key = "Backspace", action = act.SendString("\x1b\x7f") }, -- Delete previous word
{ mods = "CMD", key = "Backspace", action = act.SendString("\x15") }, -- Delete previous line
{ mods = "OPT", key = "Delete", action = act.SendString("\x1bd") }, -- Delete next word
{ mods = "CMD", key = "Delete", action = act.SendString("\x0b") }, -- Delete next line
{ mods = "CMD", key = "n", action = act.SpawnWindow }, -- New window
{ mods = "CMD", key = "t", action = act.SpawnCommandInNewTab({ cwd = wezterm.home_dir }) }, -- New tab
{ mods = "SUPER|SHIFT", key = "LeftArrow", action = act({ MoveTabRelative = -1 }) }, -- Move tab left
{ mods = "SUPER|SHIFT", key = "RightArrow", action = act({ MoveTabRelative = 1 }) }, -- Move tab right
{ mods = "SUPER|SHIFT", key = "b", action = act.EmitEvent("toggle-tabbar") },
{ mods = "SUPER|SHIFT", key = "o", action = wezterm.action.ShowTabNavigator },
{
mods = "SUPER|SHIFT",
key = "r",
action = wezterm.action.PromptInputLine({
description = "Enter new tab title",
action = wezterm.action_callback(function(window, pane, line)
if line then
window:active_tab():set_title(line)
end
end),
}),
},
}
return config

View File

@@ -1,85 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 -c COMMENT_SYMBOL [-e EXCLUDE_PATTERN]... TARGET"
echo " -c Comment symbol (e.g., '#' or '//')"
echo " -e Exclude pattern (can be specified multiple times)"
echo " TARGET File or directory to process"
exit 1
}
comment_sym=""
excludes=()
while getopts "c:e:h" opt; do
case $opt in
c) comment_sym="$OPTARG" ;;
e) excludes+=("$OPTARG") ;;
h) usage ;;
*) usage ;;
esac
done
shift $((OPTIND - 1))
[[ $# -ne 1 ]] && usage
[[ -z "$comment_sym" ]] && usage
target="$(realpath "$1")"
base_dir="$(pwd)"
should_exclude() {
local path="$1"
for pattern in "${excludes[@]}"; do
if [[ "$path" == *"$pattern"* ]]; then
return 0
fi
done
return 1
}
process_file() {
local file="$1"
local rel_path="${file#"$base_dir"/}"
should_exclude "$rel_path" && return
local path_comment="$comment_sym path: $rel_path"
# Read first two lines
local line1 line2
IFS= read -r line1 <"$file" 2>/dev/null || line1=""
IFS= read -r line2 < <(tail -n +2 "$file") 2>/dev/null || line2=""
# Check if path comment exists in first or second line
[[ "$line1" == *"path: "* ]] && return
[[ "$line2" == *"path: "* ]] && return
# Insert after shebang if present, otherwise at top
if [[ "$line1" =~ ^#! ]]; then
{
echo "$line1"
echo "$path_comment"
tail -n +2 "$file"
} >"$file.tmp"
else
{
echo "$path_comment"
cat "$file"
} >"$file.tmp"
fi
mv "$file.tmp" "$file"
}
if [[ -f "$target" ]]; then
process_file "$target"
elif [[ -d "$target" ]]; then
while IFS= read -r -d '' file; do
process_file "$file"
done < <(find "$target" -type f -print0)
else
echo "Error: $target is not a file or directory" >&2
exit 1
fi

40
config/shared/alacritty Normal file
View File

@@ -0,0 +1,40 @@
live_config_reload = true
[env]
TERM = "xterm-256color"
[font]
normal = { family = "SF Mono", style = "Regular" }
size = 12
offset = { x = 0, y = 0 }
[window]
decorations_theme_variant = "Dark"
padding = { x = 4, y = 0 }
dynamic_padding = false
resize_increments = true
[keyboard]
bindings = [
# Create new window
{ action = "SpawnNewInstance", key = "N", mods = "Command" },
# Jump back one word
{ key = "Left", mods = "Alt", chars = "\u001bb" },
# Jump forward one word
{ key = "Right", mods = "Alt", chars = "\u001bf" },
# Move to start of line
{ key = "Left", mods = "Command", chars = "\u0001" },
# Move to end of line
{ key = "Right", mods = "Command", chars = "\u0005" },
# Delete backwards
{ key = "Back", mods = "Alt", chars = "\u001B\u007F" }, # word
{ key = "Back", mods = "Command", chars = "\u0015" }, # line
# Delete forwards
{ key = "Delete", mods = "Alt", chars = "\u001Bd" }, # word
{ key = "Delete", mods = "Command", chars = "\u000B" } # line
]
[scrolling]
multiplier = 1

97
config/shared/bin/colortest Executable file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env bash
# Test black and white
echo "=== Black and White ==="
printf "Normal text\n"
printf "\e[1mBold text\e[0m\n"
printf "\e[7mReverse text\e[0m\n\n"
# Test 4-bit ANSI (16 colors)
echo "=== 4-bit ANSI Colors (16 colors) ==="
echo "Foreground colors:"
for i in {30..37}; do
printf "\e[${i}m\\e[${i}m\e[0m "
done
echo -e "\n"
echo "Background colors:"
for i in {40..47}; do
printf "\e[${i}m\\e[${i}m\e[0m "
done
echo -e "\n"
echo "Bright foreground colors:"
for i in {90..97}; do
printf "\e[${i}m\\e[${i}m\e[0m "
done
echo -e "\n"
echo "Bright background colors:"
for i in {100..107}; do
printf "\e[${i}m\\e[${i}m\e[0m "
done
echo -e "\n\n"
# Test 8-bit ANSI (256 colors)
echo "=== 8-bit ANSI Colors (256 colors) ==="
echo "16 System Colors:"
for i in {0..15}; do
printf "\e[48;5;${i}m \e[0m"
if [ $((($i + 1) % 8)) == 0 ]; then
echo
fi
done
echo
echo "216 RGB Colors:"
for i in {16..231}; do
printf "\e[48;5;${i}m \e[0m"
if [ $((($i - 15) % 36)) == 0 ]; then
echo
fi
done
echo
echo "24 Grayscale Colors:"
for i in {232..255}; do
printf "\e[48;5;${i}m \e[0m"
if [ $((($i - 231) % 12)) == 0 ]; then
echo
fi
done
echo -e "\n"
# Test 24-bit true color
echo "=== 24-bit True Color (16.7 million colors) ==="
echo "RGB Color Gradient:"
awk 'BEGIN{
s="/\\";
for (colnum = 0; colnum<77; colnum++) {
r = 255-(colnum*255/76);
g = (colnum*510/76);
b = (colnum*255/76);
if (g>255) g = 510-g;
printf "\033[48;2;%d;%d;%dm", r,g,b;
printf "\033[38;2;%d;%d;%dm", 255-r,255-g,255-b;
printf "%s\033[0m", substr(s,colnum%2+1,1);
}
printf "\n";
}'
echo "RGB Color Bars:"
for r in 0 127 255; do
for g in 0 127 255; do
for b in 0 127 255; do
printf "\e[48;2;${r};${g};${b}m \e[0m"
done
printf " "
done
echo
done
echo
# Print terminal information
echo "=== Terminal Information ==="
echo "TERM: $TERM"
echo "COLORTERM: $COLORTERM"
echo "Reported colors (tput colors): $(tput colors)"

18
config/shared/bin/detect_keys Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/zsh
echo "Press any key combination. Press Ctrl+C to exit."
while true; do
result=""
escape_sequence=""
read -sk 1 key
if [[ $key == $'\x1b' ]]; then
escape_sequence+="^["
while read -sk 1 -t 0.01 next_key; do
escape_sequence+="$next_key"
done
result="$escape_sequence"
else
result="$key"
fi
echo -E "Key: $result"
done

327
config/shared/bin/dev Executable file
View File

@@ -0,0 +1,327 @@
#!/usr/bin/env bash
set -euo pipefail
source './parse_image_ref.sh'
REGISTRY="registry.tomastm.com"
REGISTRY_ABBR="tm0"
PROJECT_DIR="$HOME/projects"
PROJECT_ABBR="p"
usage() {
cat <<'EOF'
Usage: dev <command> [options] <name>
Commands:
create -i, --image <image> -p, --project <path> <name>
exec <name> [-- <cmd>...]
connect <name>
list
info <name>
stop [--kill] <name>
rm [--force|-f] <name>
Notes:
- 'exec' treats the LAST argument as <name>; everything before it is the command to run.
- If already inside tmux, 'connect' switches to the session; otherwise it attaches.
- New tmux panes/windows created in a session always run inside the container.
- within tmux that need <name>: info, stop, rm, restore, connect
EOF
exit 1
}
fail() {
printf 'Error: %s\n' "$*" >&2
exit 1
}
resolve_path() {
local path="$1"
if command -v realpath >/dev/null 2>&1; then
realpath "$path"
else
echo "$(cd "$(dirname "$path")" && pwd)/$(basename "$path")"
fi
}
docker_container_exists() {
local name="$1"
docker container ls -a --format '{{.Names}}' | grep -Fqx "$name"
}
docker_container_running() {
local name="$1"
docker container ls --format '{{.Names}}' | grep -Fqx "$name"
}
docker_image_present() {
local ref="$1"
docker image inspect "$ref" >/dev/null 2>&1
}
cmd_create() {
local image_arg="" project_arg=""
while [[ $# -gt 0 ]]; do
case "$1" in
-i | --image)
[[ $# -ge 2 ]] || fail "Missing value for $1"
image_arg="$2"
shift 2
;;
-p | --project)
[[ $# -ge 2 ]] || fail "Missing value for $1"
project_arg="$2"
shift 2
;;
-*) usage ;;
*) break ;;
esac
done
# Check args
local name_arg="${1:-}"
if [[ -z "$name_arg" || -z "$image_arg" || -z "$project_arg" ]]; then
fail "Missing arguments"
fi
# Check container name
local cname="dev-$name_arg"
if docker_container_exists "$cname"; then
fail "Container already exists: "$cname" (from name "$name_arg")"
fi
# Check project path
local project_path
project_path="$(resolve_path "$project_arg")"
if [[ ! -d "$project_path" ]]; then
fail "Invalid project path: $project_path"
fi
# Check image
IFS=' ' read -r image_ref image_repo image_tag image_label <<<"$(parse_image_ref "$image_arg")"
if ! docker_image_present "$image_ref"; then
fail $'Image not found locally.\nTry:\n\t- docker pull '"$image_ref"
fi
# Run (= create and start container)
cmd=(
docker run -d
--name "$cname"
--label dev=true
--network host
--init # run tini as PID 1 to handle signals & reap zombies for cleaner container shutdown
-v "$project_path:/workspace"
-v /var/run/docker.sock:/var/run/docker.sock
)
[[ -d "$HOME/.ssh" ]] && cmd+=(-v "$HOME/.ssh:$CONTAINER_HOME/.ssh:ro")
[[ -f "$HOME/.npmrc" ]] && cmd+=(-v "$HOME/.npmrc:$CONTAINER_HOME/.npmrc:ro")
[[ -d "$HOME/.npm" ]] && cmd+=(-v "$HOME/.npm:$CONTAINER_HOME/.npm")
docker_gid="$(getent group docker | cut -d: -f3 || true)"
[[ -n "$docker_gid" ]] && cmd+=(--group-add "$docker_gid")
cmd+=("$image_ref" sleep infinity)
"${cmd[@]}"
echo "$cname"
}
cmd_exec() {
# usage: exec <name> [-- <cmd>...]
local name="$1"
[[ -n "$name" ]] || fail "Missing project name"
shift
local cname="dev-$name"
if ! docker_container_running "$cname"; then
fail "Container $cname not running"
fi
if [[ "$1" == "--" ]]; then
shift
local args=("$@")
if [[ -t 1 ]]; then
docker exec -it "$cname" "${args[@]}"
else
docker exec "$cname" "${args[@]}"
fi
return
fi
# No command provided -> open a shell
docker exec -it "$cname" zsh -l ||
docker exec -it "$cname" bash -l ||
docker exec -it "$cname" sh
}
cmd_connect() {
# usage: connect [--from] <name>
local from_name=""
while [[ $# -gt 0 ]]; do
case "$1" in
-f | --from)
[[ $# -ge 2 ]] || fail "Missing value for $1"
from_name="$2"
shift 2
;;
-*) usage ;;
*) break ;;
esac
done
local name="${1:from_name}"
[[ -n "$name" ]] || fail "Missing project name"
local cname="dev-$name"
if ! docker_container_exists "$cname"; then
fail "Container does not exist: ${cname}. Run: dev create ..."
fi
if ! docker_container_running "$cname"; then
docker start "$cname" >/dev/null
fi
if ! command -v tmux >/dev/null 2>&1; then
echo "tmux not found; falling back to direct exec"
exec "$0" exec "$name"
fi
local image_ref
image_ref="$(docker container inspect "$cname" --format '{{ .Config.Image }}')"
IFS=' ' read -r _image_ref image_repo image_tag image_label <<<"$(parse_image_ref "$image_ref")"
local tname="dev:$name"
if ! tmux has-session -t "$tname" 2>/dev/null; then
tmux new-session -ds "$tname" -e "DEV_IMAGE=$image_label" "$0 exec \"$name\""
tmux set-option -t "$tname" default-command "$0 exec \"$name\""
fi
if [[ -n "${TMUX-}" ]]; then
tmux switch-client -t "$tname"
else
tmux attach -t "$tname"
fi
}
shorten_project_path() {
local project="$1"
# Case 1: path is under PROJECT_DIR
if [[ "$project" == "$PROJECT_DIR"* ]]; then
project="~/$PROJECT_ABBR${project#$PROJECT_DIR}"
# Case 2: path is under HOME (but not PROJECT_DIR)
elif [[ "$project" == "$HOME"* ]]; then
project="~${project#$HOME}"
fi
echo "$project"
}
cmd_list() {
{
echo "NAME|IMAGE|PROJECT|STATUS"
docker ps -a --filter "label=dev=true" \
--format '{{.Label "dev.name"}}|{{.Image}}|{{.Label "dev.project_path"}}|{{.Status}}'
} | while IFS='|' read -r fname image project status; do
# Shorten registry prefix
image="${image/$REGISTRY\//$REGISTRY_ABBR/}"
# Shorten project path
project="$(shorten_project_path "$project")"
echo "$fname|$image|$project|$status"
done | column -t -s '|'
}
cmd_stop() {
local kill_flag=0
while [[ $# -gt 0 ]]; do
case "$1" in
--kill)
kill_flag=1
shift
;;
-*) usage ;;
*) break ;;
esac
done
local name="${1:-}"
[[ -n "$name" ]] || fail "Missing project name"
local cname="dev-$name"
docker_container_exists "$cname" || fail "Container $cname does not exist"
if ((kill_flag)); then
echo "Killing container $cname..."
docker kill "$cname"
else
echo "Stopping container $cname..."
docker stop "$cname"
fi
}
cmd_rm() {
local force_flag=0
while [[ $# -gt 0 ]]; do
case "$1" in
--force | -f)
force_flag=1
shift
;;
-*) usage ;;
*) break ;;
esac
done
local name="${1:-}"
[[ -n "$name" ]] || fail "Missing project name"
local cname="dev-$name"
docker_container_exists "$cname" || fail "Container $cname does not exist"
if ((force_flag)); then
echo "Removing container $cname (force)..."
docker rm -f "$cname"
else
echo "Removing container $cname..."
docker rm "$cname"
fi
}
cmd_respawn() {
local name="${1:-}"
[[ -n "$name" ]] || fail "Missing project name"
local cname="dev-$name"
panes=$(tmux list-panes -t "$cname" -s -F "#{session_name}:#{window_index}.#{pane_index}")
for pane in $panes; do
echo "Respawning $pane..."
tmux respawn-pane -t "$pane"
done
}
cmd_test() {
echo "Script dev is working fine!"
}
main() {
local cmd="${1:-}"
shift || true
case "$cmd" in
create) cmd_create "$@" ;;
connect) cmd_connect "$@" ;;
exec) cmd_exec "$@" ;;
list) cmd_list ;;
stop) cmd_stop "$@" ;;
rm) cmd_rm "$@" ;;
respawn) cmd_respawn "$@" ;;
test) cmd_test "$@" ;;
*) usage ;;
esac
}
main "$@"

34
config/shared/bin/dev-temp Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
set -e
REGISTRY="registry.tomastm.com"
DEFAULT_IMAGE="base-debian"
usage() {
echo "Usage: $0 -i <image>"
exit 1
}
# Parse arguments
while getopts ":i:" opt; do
case ${opt} in
i )
IMAGE="${OPTARG}"
;;
\? )
usage
;;
esac
done
IMAGE="${IMAGE:-$DEFAULT_IMAGE}"
FULL_IMAGE_NAME="${REGISTRY}/${IMAGE}"
docker run --rm -it \
--network host \
-v "$HOME/.ssh:/home/dev/.ssh" \
-v "$PWD:/workspace" \
--init \
--entrypoint /bin/zsh \
"$FULL_IMAGE_NAME"

View File

@@ -1,12 +0,0 @@
#!/bin/bash
/home/tomas/bin/flow "$@" 2>&1
exit_code=$?
if [ $exit_code -ne 0 ]; then
echo ""
echo "Command: $*"
echo "Failed: exit $exit_code"
fi
exit $exit_code

View File

@@ -1,613 +0,0 @@
#!/usr/bin/env bash
set -e
source "$HOME/.local/bin/barg"
# shellcheck disable=SC2034
SPEC=(
"command;flow;DevFlow CLI - Manage instances and development containers"
"note;Use 'flow <command> --help' for command-specific options"
"command;enter;Connect to a development instance via SSH"
"note;Target format: [user@]namespace@platform (e.g., 'personal@orb' or 'root@personal@orb')"
"argument;user,u;type:option;help:SSH user (overrides user in target)"
"argument;namespace,n;type:option;help:Instance namespace (overrides namespace in target)"
"argument;platform,p;type:option;help:Platform name (overrides platform in target)"
"argument;session,s;type:option;default:default;help:Development session name (default: 'default')"
"argument;no-tmux;type:flag;dest:no_tmux;default:false;help:Skip tmux attachment on connection"
"argument;dry-run,d;type:flag;dest:dry_run;default:false;help:Show SSH command without executing"
"argument;target,t;required;help:Target instance in format [user@]namespace@platform"
"argument;ssh-args;type:rest;dest:ssh_args;help:Additional SSH arguments (after --)"
"end"
"command;sync;Git tools"
"command;check;Check all projects status"
"end"
"end"
"command;dotfiles;Manage repository dotfiles and git submodules"
"command;init;Initialize and set up all submodules"
"note;Equivalent to: git submodule update --init --recursive"
"end"
"command;pull;Update all submodules to latest remote commits"
"note;Equivalent to: git submodule update --remote --recursive"
"end"
"command;urls;Synchronize submodule URLs"
"note;Equivalent to: git submodule sync --recursive"
"end"
"command;reset;Reset submodules to the recorded commits"
"note;Equivalent to: git submodule update --init --recursive --force"
"end"
"command;status;Show current submodule status"
"note;Equivalent to: git submodule status --recursive"
"end"
"command;all;Run URLs sync, initialization, and remote update in one step"
"note;Equivalent to: git submodule sync --recursive && git submodule update --init --recursive && git submodule update --remote --recursive"
"end"
"end"
"command;create;Create and start a new development container"
"argument;image,i;required;type:option;help:Container image to use (with optional tag)"
"argument;project,p;type:option;help:Path to local project directory"
"argument;name;required;help:Container name"
"end"
"command;exec;Execute a command or open a shell in a container"
"argument;name;required;help:Container name"
"argument;cmd;type:rest;help:Command to execute inside container (after --)"
"end"
"command;connect;Attach or switch to the containers tmux session"
"note;When already inside tmux, switches to the target session instead of reattaching."
"note;New tmux panes or windows in the session automatically start inside the container."
"argument;from,f;type:option;dest:name;help:Optional source container name"
"argument;name;required;help:Target container name"
"end"
"command;list;Display all development containers and their status"
"end"
"command;stop;Stop or kill a running development container"
"argument;from;type:option;dest:name;help:Optional source container name"
"argument;kill;type:flag;help:Use kill instead of graceful stop"
"argument;name;required;help:Target container name"
"end"
"command;remove,rm;Remove a development container"
"argument;from;type:option;dest:name;help:Optional source container name"
"argument;force,f;type:flag;help:Force removal of container"
"argument;name;required;help:Target container name"
"end"
"command;respawn;Restart all tmux panes for a development session"
"argument;from;type:option;dest:name;help:Optional source container name"
"argument;name;required;help:Session or container name"
"end"
"command;test;Verify that the dev script is functioning"
"argument;from;type:option;dest:name;help:Optional source container name"
"argument;name;help:Target container name"
"end"
"end"
)
DEFAULT_REGISTRY="registry.tomastm.com"
DEFAULT_TAG="latest"
PROJECT_DIR="$HOME/projects"
PROJECT_ABBR="p"
CONTAINER_HOME="/home/dev"
fail() {
printf 'Error: %b\n' "$*" >&2
exit 1
}
resolve_path() {
local path="${1:-$(dirname "${BASH_SOURCE[0]}")}"
if command -v realpath >/dev/null 2>&1; then
realpath "$path"
else
echo "$(cd "$(dirname "$path")" && pwd)/$(basename "$path")"
fi
}
# shellcheck disable=SC2178,SC2128
parse_image_ref() {
local input="$1"
local image_ref registry repo tag label
if [[ $input == */* ]]; then
local prefix="${input%%/*}"
if [[ "$prefix" == "docker" ]]; then
input="docker.io/library/${input#*/}"
elif [[ "$prefix" == "tm0" ]]; then
input="${DEFAULT_REGISTRY}/${input#*/}"
fi
registry="${input%%/*}"
input=${input#*/}
else
registry="$DEFAULT_REGISTRY"
fi
if [[ "${input##*/}" == *:* ]]; then
tag="${input##*:}"
input="${input%:*}"
else
tag="$DEFAULT_TAG"
fi
repo="${registry}/${input}"
repo="${repo#*/}"
image_ref="${registry}/${repo}:${tag}"
label="${registry%.*}"
label="${label##*.}/${repo##*/}"
echo "$image_ref $repo $tag $label"
}
# shellcheck disable=SC2154,SC2155
docker_container_exists() {
local cname="$(get_cname)"
docker container ls -a --format '{{.Names}}' | grep -Fqx "$cname"
}
# shellcheck disable=SC2154,SC2155
docker_container_running() {
local cname="$(get_cname)"
docker container ls --format '{{.Names}}' | grep -Fqx "$cname"
}
docker_image_present() {
local ref="$1"
docker image inspect "$ref" >/dev/null 2>&1
}
# shellcheck disable=SC2154,SC2155
get_cname() {
printf "%s" "dev-${name_arg#dev-}"
}
cmd() {
barg_usage
}
cmd_dotfiles_init() {
echo "[dotfiles] Initializing submodules..."
git submodule update --init --recursive
}
cmd_dotfiles_pull() {
echo "[dotfiles] Updating submodules to latest remote commits..."
git submodule update --remote --recursive
}
cmd_dotfiles_urls() {
echo "[dotfiles] Syncing submodule URLs..."
git submodule sync --recursive
}
cmd_dotfiles_reset() {
echo "[dotfiles] Resetting submodules to recorded commits..."
git submodule update --init --recursive --force
}
cmd_dotfiles_status() {
echo "[dotfiles] Submodule status:"
git submodule status --recursive
}
cmd_dotfiles_all() {
echo "[dotfiles] Syncing URLs..."
git submodule sync --recursive
echo "[dotfiles] Initializing submodules..."
git submodule update --init --recursive
echo "[dotfiles] Updating submodules to latest remote commits..."
git submodule update --remote --recursive
}
# shellcheck disable=SC2154,SC2155
cmd_enter() {
# VARS: user_arg, namespace_arg, platform_arg, target_arg, session_arg, no_tmux_arg, dry_run_arg, ssh_args_arg
# Do not run inside instance
if [[ -n "$DF_NAMESPACE" && -n "$DF_PLATFORM" ]]; then
fail "It is not recommended to run this command inside an instance.\nCurrently inside: $(tput bold)${DF_NAMESPACE}@${DF_PLATFORM}$(tput sgr0)"
fi
local -A CONFIG_HOST=(
[orb.host]="<namespace>@orb"
[utm.host]="<namespace>.utm.local"
[core.host]="<namespace>.core.lan"
)
local df_platform=""
local df_namespace=""
local df_user=""
# Parse target: get user, namespace, platform
if [[ "$target_arg" == *@* ]]; then
df_platform="${target_arg##*@}"
target_arg="${target_arg%@*}"
fi
if [[ "$target_arg" == *@* ]]; then
df_namespace="${target_arg##*@}"
df_user="${target_arg%@*}"
else
df_namespace="${target_arg}"
df_user="${USER}"
fi
if [[ -n "$platform_arg" ]]; then
df_platform="$platform_arg"
fi
if [[ -n "$namespace_arg" ]]; then
df_namespace="$namespace_arg"
fi
if [[ -n "$user_arg" ]]; then
df_user="$user_arg"
fi
# Resolve host, identity (maybe check what would the host be in order to use .ssh/config)
local host_config="${CONFIG_HOST[${df_platform}.host]}"
local ssh_host="${host_config//<namespace>/$df_namespace}"
if [[ -z "$ssh_host" ]]; then
fail "Invalid platform: ${df_platform}"
fi
# Build ssh cmd: ssh + identity + tmux + envs
local ssh_cmd=(ssh -tt "${df_user}@${ssh_host}")
if [[ "$no_tmux_arg" == "false" ]]; then
# TODO: instead of tmux,maybe use "flow" in order to attach to dev container too
ssh_cmd+=("tmux" "new-session" "-As" "$session_arg"
"-e" "DF_NAMESPACE=$df_namespace"
"-e" "DF_PLATFORM=$df_platform")
fi
# Run or dryrun?
if [[ "$dry_run_arg" == "true" ]]; then
echo "Dry run command:"
printf '%q ' "${ssh_cmd[@]}"
echo
exit 0
fi
exec "${ssh_cmd[@]}"
}
# shellcheck disable=SC2154,SC2155
cmd_sync_check() {
local base_dir="$HOME/projects"
local -a needs_action=()
local -a not_git=()
for repo in "$base_dir"/*; do
[ -d "$repo" ] || continue
local git_dir="$repo/.git"
if [ ! -d "$git_dir" ]; then
not_git+=("$(basename "$repo")")
continue
fi
echo "=== $(basename "$repo") ==="
cd "$repo" || continue
local action_required=0
git fetch --all --quiet || true
local branch
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "HEAD")
# --- Uncommitted or untracked changes ---
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "Uncommitted changes:"
git status --short
action_required=1
elif [ -n "$(git ls-files --others --exclude-standard)" ]; then
echo "Untracked files:"
git ls-files --others --exclude-standard
action_required=1
else
echo "No uncommitted or untracked changes."
fi
# --- Unpushed commits on current branch ---
if git rev-parse --abbrev-ref "${branch}@{u}" >/dev/null 2>&1; then
local unpushed
unpushed=$(git rev-list --oneline "${branch}@{u}..${branch}")
if [ -n "$unpushed" ]; then
echo "Unpushed commits on ${branch}:"
echo "$unpushed"
action_required=1
else
echo "No unpushed commits on ${branch}."
fi
else
echo "No upstream set for ${branch}."
action_required=1
fi
# --- Unpushed branches ---
local unpushed_branches=()
while IFS= read -r b; do
if git rev-parse --abbrev-ref "${b}@{u}" >/dev/null 2>&1; then
local ahead
ahead=$(git rev-list --count "${b}@{u}..${b}")
if [ "$ahead" -gt 0 ]; then
unpushed_branches+=("$b ($ahead ahead)")
fi
else
unpushed_branches+=("$b (no upstream)")
fi
done < <(git for-each-ref --format='%(refname:short)' refs/heads)
if [ "${#unpushed_branches[@]}" -gt 0 ]; then
echo "Unpushed branches:"
printf ' %s\n' "${unpushed_branches[@]}"
action_required=1
else
echo "No unpushed branches."
fi
echo
((action_required)) && needs_action+=("$(basename "$repo")")
done
echo "=== SUMMARY ==="
if [ "${#needs_action[@]}" -gt 0 ]; then
echo "Projects needing action:"
printf ' %s\n' "${needs_action[@]}" | sort -u
else
echo "All repositories clean and synced."
fi
if [ "${#not_git[@]}" -gt 0 ]; then
echo
echo "Directories without Git repositories:"
printf ' %s\n' "${not_git[@]}" | sort -u
fi
}
# shellcheck disable=SC2154,SC2155
cmd_create() {
# VARS: name_arg, image_arg, project_arg
# Check if container name already exists
local cname="$(get_cname)"
if docker_container_exists "$cname"; then
printf -v msg 'Container already exists: "%s" (from name "%s")' "$cname" "$name_arg"
fail "$msg"
fi
# Check if project path is valid
local project_path
project_path="$(resolve_path "$project_arg")"
if [[ ! -d "$project_path" ]]; then
fail "Invalid project path: $project_path"
fi
# Check image
IFS=' ' read -r image_ref _ _ _ <<<"$(parse_image_ref "$image_arg")"
if ! docker_image_present "$image_ref"; then
printf -v msg 'Image not found locally.\nTry:\n\t- docker pull %s' "$image_ref"
fail "$msg"
fi
# Run (= create and start container)
cmd=(
docker run -d
--name "$cname"
--label dev=true
--label "dev.name=$name_arg"
--label "dev.project_path=$project_path"
--label "dev.image_ref=$image_ref"
--network host
--init # run tini as PID 1 to handle signals & reap zombies for cleaner container shutdown
-v "$project_path:/workspace"
-v /var/run/docker.sock:/var/run/docker.sock
)
[[ -d "$HOME/.ssh" ]] && cmd+=(-v "$HOME/.ssh:$CONTAINER_HOME/.ssh:ro")
[[ -f "$HOME/.npmrc" ]] && cmd+=(-v "$HOME/.npmrc:$CONTAINER_HOME/.npmrc:ro")
[[ -d "$HOME/.npm" ]] && cmd+=(-v "$HOME/.npm:$CONTAINER_HOME/.npm")
docker_gid="$(getent group docker | cut -d: -f3 || true)"
[[ -n "$docker_gid" ]] && cmd+=(--group-add "$docker_gid")
cmd+=("$image_ref" sleep infinity)
"${cmd[@]}"
printf "Created and started container: %s" "$cname"
}
# shellcheck disable=SC2154,SC2155
cmd_connect() {
# VARS: name_arg
local cname="$(get_cname)"
if ! docker_container_exists "$cname"; then
fail "Container does not exist: ${cname}. Run: dev create ..."
fi
if ! docker_container_running "$cname"; then
docker start "$cname" >/dev/null
fi
if ! command -v tmux >/dev/null 2>&1; then
echo "tmux not found; falling back to direct exec"
exec "$0" exec "$cname"
fi
local image_ref
image_ref="$(docker container inspect "$cname" --format '{{ .Config.Image }}')"
IFS=' ' read -r _image_ref _ _ image_label <<<"$(parse_image_ref "$image_ref")"
if ! tmux has-session -t "$cname" 2>/dev/null; then
tmux new-session -ds "$cname" \
-e "DF_IMAGE=$image_label" \
-e "DF_NAMESPACE=$DF_NAMESPACE" \
-e "DF_PLATFORM=$DF_PLATFORM" \
"$0 exec \"$name_arg\""
tmux set-option -t "$cname" default-command "$0 exec \"$name_arg\""
fi
if [[ -n "${TMUX-}" ]]; then
tmux switch-client -t "$cname"
else
tmux attach -t "$cname"
fi
}
# shellcheck disable=SC2154,SC2155
cmd_exec() {
# VARS: name_arg, cmd_arg
local cname="$(get_cname)"
if ! docker_container_running "$cname"; then
fail "Container $cname not running"
fi
if [[ -n "$cmd_arg" ]]; then
if [[ -t 0 ]]; then
docker exec -it "$cname" "${cmd_arg}"
else
docker exec "$cname" "${cmd_arg}"
fi
return
fi
# No command provided -> open a shell
docker exec --detach-keys "ctrl-q,ctrl-p" -it "$cname" zsh -l ||
docker exec --detach-keys "ctrl-q,ctrl-p" -it "$cname" bash -l ||
docker exec --detach-keys "ctrl-q,ctrl-p" -it "$cname" sh
}
shorten_project_path() {
local project=$1
local home=${HOME%/}
local projdir=${PROJECT_DIR%/}
# Case 1: under PROJECT_DIR
if [[ -n ${projdir} && $project == "$projdir"/* ]]; then
# shellcheck disable=SC2088
project="~/$PROJECT_ABBR${project#"$projdir"}"
# Case 2: equals HOME
elif [[ $project == "$home" ]]; then
project="~"
# Case 3: under HOME (but not PROJECT_DIR)
elif [[ $project == "$home"/* ]]; then
project="~${project#"$home"}"
fi
printf '%s\n' "$project"
}
# shellcheck disable=SC2154,SC2155
cmd_list() {
# VARS:
{
echo "NAME|IMAGE|PROJECT|STATUS"
docker ps -a --filter "label=dev=true" \
--format '{{.Label "dev.name"}}|{{.Image}}|{{.Label "dev.project_path"}}|{{.Status}}'
} | while IFS='|' read -r fname image project status; do
# Shorten registry prefix
image="${image/$REGISTRY\//$REGISTRY_ABBR/}"
# Shorten project path
project="$(shorten_project_path "$project")"
echo "$fname|$image|$project|$status"
done | column -t -s '|'
}
tmux_fallback_to_default_if_in_session() {
# If inside tmux and current session matches the given one,
# switch to or create 'default' before proceeding.
local target_session="$1"
[[ -z "${TMUX-}" ]] && return 0 # not in tmux, nothing to do
local current_session
current_session="$(tmux display-message -p '#S')"
if [[ "$current_session" == "$target_session" ]]; then
if ! tmux has-session -t default 2>/dev/null; then
tmux new-session -ds default
fi
tmux switch-client -t default
fi
}
# shellcheck disable=SC2154,SC2155
cmd_stop() {
# VARS: kill_arg name_arg
local cname
cname="$(get_cname)"
docker_container_exists "$cname" || fail "Container $cname does not exist"
if [[ "$kill_arg" == "true" ]]; then
echo "Killing container $cname..."
docker kill "$cname"
else
echo "Stopping container $cname..."
docker stop "$cname"
fi
tmux_fallback_to_default_if_in_session "$cname"
}
# shellcheck disable=SC2154,SC2155
cmd_remove() {
# VARS: force_arg name_arg
local cname
cname="$(get_cname)"
docker_container_exists "$cname" || fail "Container $cname does not exist"
if [[ "$force_arg" == "true" ]]; then
echo "Removing container $cname (force)..."
docker rm -f "$cname"
else
echo "Removing container $cname..."
docker rm "$cname"
fi
tmux_fallback_to_default_if_in_session "$cname"
}
# shellcheck disable=SC2154,SC2155
cmd_respawn() {
# VARS: name_arg
local cname
cname="$(get_cname)"
panes=$(tmux list-panes -t "$cname" -s -F "#{session_name}:#{window_index}.#{pane_index}")
for pane in $panes; do
echo "Respawning $pane..."
tmux respawn-pane -t "$pane"
done
}
# shellcheck disable=SC2154,SC2155
cmd_test() {
# VARS: name_arg
echo "Script dev is working fine!"
if [[ -n "$name_arg" ]]; then
get_cname
fi
echo
}
barg_run SPEC[@] "$@"

View File

@@ -1,39 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
declare -A THEME=(
["ghostty.url"]="https://raw.githubusercontent.com/triimdev/invero.nvim/refs/heads/main/extras/ghostty/invero_day"
["ghostty.dir"]="$HOME/.config/ghostty/themes"
["ghostty.name"]="Invero Day"
["wezterm.url"]="https://raw.githubusercontent.com/triimdev/invero.nvim/refs/heads/main/extras/wezterm/invero_day.toml"
["wezterm.dir"]="$HOME/.config/wezterm/colors"
["wezterm.name"]="Invero Day.toml"
)
theme="${1:-}"
if [[ -z "$theme" ]]; then
echo "Usage: $0 <theme>"
echo "Available themes: $(printf '%s\n' "${!THEME[@]}" | cut -d. -f1 | sort -u | tr '\n' ' ')"
exit 1
fi
if [[ -z "${THEME[$theme.url]+x}" ]]; then
echo "Unknown theme '$theme'. Available: $(printf '%s\n' "${!THEME[@]}" | cut -d. -f1 | sort -u | tr '\n' ' ')"
exit 1
fi
url="${THEME[$theme.url]}"
dir="${THEME[$theme.dir]}"
name="${THEME[$theme.name]}"
path="${dir}/${name}"
mkdir -p "$dir"
if curl -fsSL -o "$path" "$url"; then
echo "Theme downloaded to $path"
else
echo "Failed to download theme for '$theme'."
exit 1
fi

View File

@@ -1,48 +0,0 @@
#!/usr/bin/env bash
echo
awk 'BEGIN{
s="/\\/\\/\\/\\/\\"; s=s s s s s s s s;
for (colnum = 0; colnum<77; colnum++) {
r = 255-(colnum*255/76);
g = (colnum*510/76);
b = (colnum*255/76);
if (g>255) g = 510-g;
printf "\033[48;2;%d;%d;%dm", r,g,b;
printf "\033[38;2;%d;%d;%dm", 255-r,255-g,255-b;
printf "%s\033[0m", substr(s,colnum+1,1);
}
printf "\n";
}'
# --- Environment diagnostics -------------------------------------------------
echo
echo "──────────────────────────────"
echo " Environment and Tmux Details "
echo "──────────────────────────────"
echo "TERM: ${TERM}"
echo "COLORTERM: ${COLORTERM:-undefined}"
echo
if command -v tmux >/dev/null && tmux info &>/dev/null; then
echo "Tmux RGB/Tc capabilities:"
tmux info | grep -E "RGB|Tc" || echo "(none found)"
echo
echo "Tmux server terminal options:"
tmux show-options -s | grep terminal || echo "(none found)"
else
echo "Tmux not running or unavailable."
fi
# --- Underline capability test -----------------------------------------------
echo
echo "Underline styles test:"
printf '\x1b[58:2::255:0:0m' # red underline color
printf '\x1b[4:1msingle ' # single underline
printf '\x1b[4:2mdouble ' # double underline
printf '\x1b[4:3mcurly ' # curly underline
printf '\x1b[4:4mdotted ' # dotted underline
printf '\x1b[4:5mdashed ' # dashed underline
printf '\x1b[0m\n'
echo

View File

@@ -0,0 +1,16 @@
font=monospace:size=10
pad=4x0
[key-bindings]
# scrollback-up-page=Shift+Page_Up Shift+KP_Page_Up
# scrollback-up-half-page=none
# scrollback-up-line=none
# scrollback-down-page=Shift+Page_Down Shift+KP_Page_Down
# scrollback-down-half-page=none
# scrollback-down-line=none
# scrollback-home=none
# scrollback-end=none
clipboard-copy=Control+c XF86Copy
clipboard-paste=Control+v XF86Paste
[text-bindings]
\x03=Mod4+c

View File

@@ -0,0 +1,22 @@
term = xterm-256color
theme = Invero Day
# Font
font-family = "Maple Mono NF"
font-size = 13
#font-thicken = true
adjust-cell-width = -7%
adjust-cell-height = -2
# Cursor
cursor-style = block
cursor-style-blink = false
mouse-hide-while-typing = true
shell-integration-features = no-cursor
# Window
window-padding-x = 4
window-padding-y = 0
window-padding-color = extend
macos-titlebar-style = native
macos-icon = custom

View File

@@ -1,24 +1,10 @@
[init]
defaultBranch = main
[user] [user]
name = Tomas Mirchev name = Tomas Mirchev
email = contact@tomastm.com email = contact@tomastm.com
[core]
editor = nvim
excludesfile = ~/.gitignore
[init]
defaultBranch = main
[pull] [pull]
rebase = true rebase = true
[push] [core]
default = current editor = nvim
autoSetupRemote = true
[remote]
pushDefault = origin
[alias]
amend = commit --amend --no-edit
rename = branch -m
st = status
unstage = reset HEAD
last = log -1 HEAD
tags = tag -l
undo = reset --mixed HEAD~1

View File

@@ -1,21 +0,0 @@
.DS_Store
*.swp
*.swo
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.env
.env.*
build/
dist/
build/
tmp/
temp/
logs/
*.log
.cache/
coverage/
.devflow/
.dev-flow/

161
config/shared/nvim Normal file
View File

@@ -0,0 +1,161 @@
-- Helper function for key mappings
local function map(mode, lhs, rhs, opts)
local options = { silent = true, noremap = true }
if opts then
options = vim.tbl_extend("force", options, opts)
end
if type(mode) == "table" then
for _, m in ipairs(mode) do
vim.keymap.set(m, lhs, rhs, options)
end
else
vim.keymap.set(mode, lhs, rhs, options)
end
end
-- Mode-specific mapping functions
local function nmap(lhs, rhs, opts) map("n", lhs, rhs, opts) end
local function imap(lhs, rhs, opts) map("i", lhs, rhs, opts) end
local function vmap(lhs, rhs, opts) map("v", lhs, rhs, opts) end
local function tmap(lhs, rhs, opts) map("t", lhs, rhs, opts) end
vim.opt.signcolumn = "no"
-- Map Leader
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- Use Nerd Font
vim.g.have_nerd_font = true
-- Add vertical line
-- vim.opt.colorcolumn = "100"
-- Enable TrueColor
vim.opt.termguicolors = true
-- Disable Neovim background
vim.api.nvim_set_hl(0, "Normal", { bg = "none" })
vim.api.nvim_set_hl(0, "NormalFloat", { bg = "none" })
-- Scroll lines/columns
vim.opt.mousescroll = "hor:1,ver:1"
-- Set indentation preferences
vim.opt.expandtab = true -- Convert tabs to spaces
vim.opt.shiftwidth = 2 -- Number of spaces for auto-indent
vim.opt.tabstop = 2 -- Number of spaces a tab counts for
vim.opt.softtabstop = 2 -- Number of spaces a tab counts for when editing
vim.opt.autoindent = true -- Copy indent from current line when starting new line
vim.opt.smartindent = true -- Do smart autoindenting when starting a new line
-- Disable line wrapping
vim.opt.wrap = false
-- Enable break indent
vim.opt.breakindent = true
-- Make line numbers default
vim.opt.number = true
vim.opt.relativenumber = true
-- Enable mouse mode, can be useful for resizing splits for example
vim.opt.mouse = "a"
-- Full path on status line
vim.opt.statusline = "%F%m%r%h%w%=%l,%c %P"
-- Sync clipboard between OS and Neovim
vim.schedule(function()
vim.opt.clipboard = "unnamedplus"
end)
-- Save undo history
vim.opt.undofile = true
-- Case-insensitive searching UNLESS \C or one or more capital letters in the search term
vim.opt.ignorecase = true
vim.opt.smartcase = true
-- Decrease update time
vim.opt.updatetime = 250
-- Decrease mapped sequence wait time
-- Displays which-key popup sooner
vim.opt.timeoutlen = 300
-- Configure how new splits should be opened
vim.opt.splitright = true
vim.opt.splitbelow = true
-- Sets how neovim will display certain whitespace characters in the editor.
vim.opt.list = true
vim.opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" }
-- Preview substitutions live, as you type
vim.opt.inccommand = "split"
-- Show which line your cursor is on
vim.opt.cursorline = true
-- Minimal number of screen lines to keep above and below the cursor
vim.opt.scrolloff = 10
-- Highlight when yanking (copying) text
vim.api.nvim_create_autocmd("TextYankPost", {
callback = function()
vim.highlight.on_yank()
end,
})
-- Keymaps
nmap("<leader>q", vim.diagnostic.setloclist, { desc = "Open diagnostic [Q]uickfix list" })
imap("jk", "<Esc>", { desc = "Exit insert mode with jk" })
nmap("<Esc>", "<cmd>nohlsearch<CR>", { desc = "Clear highlights" })
-- Prevent "x" from overriding the register
nmap("x", '"_x')
-- Window Navigation
nmap("<C-h>", "<C-w>h", { desc = "Move focus to the left window" })
nmap("<C-l>", "<C-w>l", { desc = "Move focus to the right window" })
nmap("<C-j>", "<C-w>j", { desc = "Move focus to the lower window" })
nmap("<C-k>", "<C-w>k", { desc = "Move focus to the upper window" })
-- Tab management
nmap("<Leader>tn", ":tabnew<CR>", { desc = "[T]ab [N]ew" })
nmap("<Leader>tc", ":tabclose<CR>", { desc = "[T]ab [C]lose" })
nmap("<Leader>to", ":tabonly<CR>", { desc = "[T]ab [O]nly" })
nmap("<Leader>tl", ":tabnext<CR>", { desc = "[T]ab Next" })
nmap("<Leader>th", ":tabprevious<CR>", { desc = "[T]ab Previous" })
nmap("<Leader>tm.", ":tabmove +1<CR>", { desc = "[T]ab [M]ove Right" })
nmap("<Leader>tm,", ":tabmove -1<CR>", { desc = "[T]ab [M]ove Left" })
for i = 1, 9 do
nmap(string.format("<Leader>%d", i), string.format("%dgt", i), { desc = string.format("[T]ab %d", i) })
end
-- Buffer Management
nmap("<Leader>bl", ":ls<CR>", { desc = "[B]uffer [L]ist" })
nmap("<Leader>bd", ":bdelete<CR>", { desc = "[B]uffer [D]elete" })
nmap("]b", ":bnext<CR>", { desc = "[B]uffer [N]ext" })
nmap("[b", ":bprevious<CR>", { desc = "[B]uffer [P]revious" })
nmap("<Leader>bb", ":b<Space>", { desc = "[B]uffer Select" })
nmap("<Leader>bo", ":bufdo bd|1bd<CR>", { desc = "[B]uffer Delete Others" })
-- Terminal
nmap("<Leader>tet", function()
vim.cmd("terminal")
vim.cmd("startinsert")
end, { desc = "[T]erminal" })
nmap("<leader>ter", function()
local buf_dir = vim.fn.expand("%:p:h")
vim.cmd("edit term://" .. buf_dir .. "//zsh")
vim.cmd("startinsert")
end, { desc = "[T]erminal [R]elative" })
tmap("<Esc>", "<C-\\><C-n>", { desc = "Terminal Normal Mode" })
tmap("jk", "<C-\\><C-n>", { desc = "Terminal Normal Mode" })
tmap("<C-w>", "<C-\\><C-n><C-w>", { desc = "Terminal Window Command" })

View File

@@ -0,0 +1,106 @@
-- wezterm.lua configuration file
local wezterm = require 'wezterm'
-- This table will hold the configuration.
local config = {}
-- In newer versions of wezterm, use the config_builder which will
-- help provide clearer error messages
if wezterm.config_builder then
config = wezterm.config_builder()
end
-- Environment variables
config.term="xterm-256color"
config.set_environment_variables = {
TERM = "xterm-256color",
}
-- Font configuration
config.font = wezterm.font('JetBrainsMono Nerd Font', {weight = 'Bold'})
-- config.freetype_render_target = "HorizontalLcd"
-- config.freetype_load_flags = 'NO_HINTING'
-- config.freetype_load_target = "Light"
config.bold_brightens_ansi_colors = false
local act = wezterm.action
config.font_size = 14
-- Alacritty's offset translates to cell_width and line_height in wezterm
-- Since your offset is 0, we're keeping default values
-- Window configuration
config.window_padding = {
left = 4,
right = 4,
top = 0,
bottom = 0,
}
-- config.window_decorations = "RESIZE|TITLE|MACOS_USE_BACKGROUND_COLOR_AS_TITLEBAR_COLOR|MACOS_FORCE_ENABLE_SHADOW" -- Similar to decorations_theme_variant = "Dark"
config.window_decorations = "TITLE|RESIZE"
config.use_resize_increments = false
-- Wezterm doesn't have direct equivalents for dynamic_padding and resize_increments
-- but we can set related options
-- Keyboard bindings
config.keys = {
{key="LeftArrow", mods="SUPER|SHIFT", action=wezterm.action{MoveTabRelative=-1}},
{key="RightArrow", mods="SUPER|SHIFT", action=wezterm.action{MoveTabRelative=1}},
-- Create new window
{
key = 'n',
mods = 'CMD',
action = wezterm.action.SpawnWindow,
},
-- Jump back one word (Alt+Left)
{
key = 'LeftArrow',
mods = 'ALT',
action = wezterm.action.SendString('\x1bb'),
},
-- Jump forward one word (Alt+Right)
{
key = 'RightArrow',
mods = 'ALT',
action = wezterm.action.SendString('\x1bf'),
},
-- Move to start of line (Cmd+Left)
{
key = 'LeftArrow',
mods = 'CMD',
action = wezterm.action.SendString('\x01'),
},
-- Move to end of line (Cmd+Right)
{
key = 'RightArrow',
mods = 'CMD',
action = wezterm.action.SendString('\x05'),
},
-- Delete backwards word (Alt+Backspace)
{
key = 'Backspace',
mods = 'ALT',
action = wezterm.action.SendString('\x1b\x7f'),
},
-- Delete backwards line (Cmd+Backspace)
{
key = 'Backspace',
mods = 'CMD',
action = wezterm.action.SendString('\x15'),
},
-- Delete forwards word (Alt+Delete)
{
key = 'Delete',
mods = 'ALT',
action = wezterm.action.SendString('\x1bd'),
},
-- Delete forwards line (Cmd+Delete)
{
key = 'Delete',
mods = 'CMD',
action = wezterm.action.SendString('\x0b'),
},
}
return config

View File

@@ -1,16 +1,14 @@
export PATH="$PATH:$HOME/.local/bin:$HOME/bin" export PATH="$PATH:$HOME/bin"
export LANG=en_US.UTF-8 export LANG=en_US.UTF-8
export LC_CTYPE=en_US.UTF-8 export LC_CTYPE=en_US.UTF-8
export LC_COLLATE=C export LC_COLLATE=C
# eval "$(dircolors)"; echo "$LS_COLORS" KEYTIMEOUT=1
export LS_COLORS='rs=0:di=01;34:ln=01;33:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=00:tw=30;42:ow=34;42:st=37;44:ex=01;32'
HISTFILE=$HOME/.zsh_history HISTFILE=$HOME/.zsh_history
HISTSIZE=10000 HISTSIZE=10000
SAVEHIST=10000 SAVEHIST=10000
setopt auto_cd interactive_comments prompt_subst share_history setopt auto_cd interactive_comments prompt_subst
setopt append_history hist_ignore_dups hist_ignore_all_dups hist_reduce_blanks setopt append_history hist_ignore_dups hist_ignore_all_dups hist_reduce_blanks
autoload -Uz compinit autoload -Uz compinit
@@ -36,22 +34,9 @@ bindkey '^[[B' down-line-or-beginning-search
bindkey '^[OB' down-line-or-beginning-search bindkey '^[OB' down-line-or-beginning-search
bindkey '^U' backward-kill-line bindkey '^U' backward-kill-line
if command -v nvim >/dev/null 2>&1; then # alias ls='ls --color=auto --group-directories-first'
alias vim='nvim' alias ls='ls --color=auto'
fi
case "$OSTYPE" in
linux*) alias ls='ls --color=auto --group-directories-first' ;;
darwin*) alias ls='ls --color=auto' ;;
esac
alias ll='ls -lF' alias ll='ls -lF'
alias lla='ll -a' alias lla='ll -a'
alias ld='ls -ld */' alias ld='ls -ld */'
alias vim=nvim
alias ga='git add'
alias gcm='git commit -m'
alias gp='git push'
alias gst='git status'
alias gd='git diff --patience --color-moved=dimmed-zebra --word-diff=plain --function-context --ignore-space-change -U3'
alias glg='git log --oneline --graph --decorate --all'

View File

@@ -10,7 +10,7 @@ import shutil
DOTFILES_DIR = Path(__file__).parent DOTFILES_DIR = Path(__file__).parent
SETUPS_DIR = DOTFILES_DIR / "setups" SETUPS_DIR = DOTFILES_DIR / "setups"
CONFIG_DIR = DOTFILES_DIR / "config" CONFIG_DIR = DOTFILES_DIR / "config"
CONFIG_PATH = DOTFILES_DIR / "manifest.json" CONFIG_PATH = DOTFILES_DIR / "config.json"
def load_config(): def load_config():
if not CONFIG_PATH.exists(): if not CONFIG_PATH.exists():
@@ -63,8 +63,8 @@ def get_environment_packages(config, env, search_package=None):
if not isinstance(link_from, str) or not isinstance(link_to, str): if not isinstance(link_from, str) or not isinstance(link_to, str):
raise ValueError("`link` should follow the structure: `{ from: str, to: str }`") raise ValueError("`link` should follow the structure: `{ from: str, to: str }`")
# if len(link_from.split("/")) != 2: if len(link_from.split("/")) != 2:
# raise ValueError("`link.from` should be '<env>/<package>'") raise ValueError("`link.from` should be '<env>/<package>'")
package["link"] = { package["link"] = {
"from": Path(CONFIG_DIR / link_from).expanduser(), "from": Path(CONFIG_DIR / link_from).expanduser(),

View File

@@ -1,191 +0,0 @@
{
"template": {
"bin": {
"link": {
"from": "shared/bin",
"to": "~/bin"
}
},
"barg": {
"link": {
"from": "shared/barg-parser/barg",
"to": "~/.local/bin/barg"
}
},
"addpaths": {
"link": {
"from": "shared/addpaths",
"to": "~/.local/bin/addpaths"
}
},
"htop": {
"link": {
"from": "shared/htop",
"to": "~/.config/htop"
}
},
"git": {
"link": {
"from": "shared/git",
"to": "~/.gitconfig"
}
},
"gitignore": {
"link": {
"from": "shared/gitignore",
"to": "~/.gitignore"
}
},
"zsh": {
"link": {
"from": "shared/zsh",
"to": "~/.zshrc"
}
},
"tmux": {
"link": {
"from": "shared/tmux",
"to": "~/.tmux.conf"
}
},
"nvim": {
"link": {
"from": "shared/nvim",
"to": "~/.config/nvim"
}
}
},
"environments": {
"linux": [
{
"package": "window-tagger",
"link": {
"from": "linux/kwin_window-tagger",
"to": "~/.config/window-tagger"
}
}
],
"macos": [
"git",
"gitignore",
"zsh",
"tmux",
"nvim",
"bin",
"barg",
{
"package": "sol",
"link": {
"from": "macos/sol",
"to": "~/.config/sol"
}
},
{
"package": "borders",
"link": {
"from": "macos/borders",
"to": "~/.config/borders"
}
},
{
"package": "karabiner",
"link": {
"from": "macos/karabiner",
"to": "~/.config/karabiner"
}
},
{
"package": "linearmouse",
"link": {
"from": "macos/linearmouse",
"to": "~/.config/linearmouse"
}
},
{
"package": "rectangle",
"link-comment": "Needs manual import from config/macos/linearmouse"
},
{
"package": "wezterm",
"link": {
"from": "macos/wezterm",
"to": "~/.config/wezterm"
}
},
{
"package": "alacritty",
"link": {
"from": "macos/alacritty",
"to": "~/.config/alacritty"
}
},
{
"package": "ghostty",
"link": {
"from": "macos/ghostty",
"to": "~/.config/ghostty"
}
},
{
"package": "kitty",
"link": {
"from": "macos/kitty",
"to": "~/.config/kitty"
}
}
],
"linux-vm": [
"bin",
"barg",
"addpaths",
"gitignore",
{
"package": "htop",
"install": "sudo apt install -y htop"
},
{
"package": "git",
"install": "sudo apt install -y git"
},
{
"package": "zsh",
"install": "sudo apt install -y zsh",
"post-link": "./scripts/linux-setup_zsh.sh"
},
{
"package": "tmux",
"install": "sudo apt install -y tmux"
},
{
"package": "nvim",
"post-install": "echo 'Neovim needs setup'"
}
],
"container": [
"bin",
"barg",
"gitignore",
{
"package": "htop",
"install": "sudo apt install -y htop"
},
{
"package": "git",
"install": "sudo apt install -y git"
},
{
"package": "zsh",
"install": "sudo apt install -y zsh",
"post-link": "./scripts/linux-setup_zsh.sh"
},
{
"package": "tmux",
"install": "sudo apt install -y tmux"
},
{
"package": "nvim",
"post-install": "echo 'Neovim needs setup'"
}
]
}
}

View File

@@ -1,196 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# Close any open System Preferences panes, to prevent them from overriding
# settings were about to change
osascript -e 'tell application "System Preferences" to quit'
# Ask for the administrator password upfront
sudo -v
# Keep-alive: update existing `sudo` time stamp until `.macos` has finished
while true; do
sudo -n true
sleep 60
kill -0 "$$" || exit
done 2>/dev/null &
# Save to disk (not to iCloud) by default
defaults write NSGlobalDomain NSDocumentSaveNewDocumentsToCloud -bool false
# Disable the “Are you sure you want to open this application?” dialog
defaults write com.apple.LaunchServices LSQuarantine -bool false
# Disable Typing features
defaults write NSGlobalDomain NSAutomaticCapitalizationEnabled -bool false
defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false
defaults write NSGlobalDomain NSAutomaticPeriodSubstitutionEnabled -bool false
defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false
# Disable press-and-hold for keys in favor of key repeat
defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false
defaults write NSGlobalDomain KeyRepeat -int 2
defaults write NSGlobalDomain InitialKeyRepeat -int 15
defaults write NSGlobalDomain AppleLanguages -array "en" "es" "bg"
defaults write NSGlobalDomain AppleLocale -string "en_US@rg=eszzzz"
## Finder
# Screenshots/captures
defaults write com.apple.screencapture location -string "${HOME}/Pictures/Screenshots"
defaults write com.apple.screencapture style -string "display"
defaults write com.apple.screencapture target -string "file"
defaults write com.apple.screencapture video -int 1
# Finder
# Interface elements
defaults write com.apple.finder ShowPathbar -bool true
defaults write com.apple.finder ShowStatusBar -bool true
defaults write com.apple.finder ShowSidebar -bool true
defaults write com.apple.finder ShowRecentTags -bool false
# View and sorting
defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv"
defaults write com.apple.finder FXPreferredSearchViewStyle -string "Nlsv"
defaults write com.apple.finder _FXSortFoldersFirst -bool true
defaults write com.apple.finder FXPreferredGroupBy -string "None"
defaults write com.apple.finder FXDefaultSearchScope -string "SCcf"
# Behavior
defaults write com.apple.finder NewWindowTarget -string "PfHm"
defaults write com.apple.finder FXOpenFoldersInTabs -bool true
defaults write com.apple.finder FXRemoveOldTrashItems -bool false
defaults write com.apple.finder FXShowAllExtensions -bool true
defaults write com.apple.finder FXEnableExtensionChangeWarning -bool true
defaults write com.apple.finder FXRemoveICloudDriveWarning -bool true
defaults write com.apple.finder FXWarnBeforeEmptyingTrash -bool true
# Desktop icons (none)
defaults write com.apple.finder ShowHardDrivesOnDesktop -bool false
defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool false
defaults write com.apple.finder ShowRemovableMediaOnDesktop -bool false
defaults write com.apple.finder ShowConnectedServersOnDesktop -bool false
# Tags
defaults write com.apple.finder FavoriteTagNames -array
# iCloud
defaults write com.apple.finder FXICloudDriveEnabled -bool false
# Finder: show all filename extensions
defaults write NSGlobalDomain AppleShowAllExtensions -bool true
# Avoid creating .DS_Store files on network or USB volumes
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
defaults write com.apple.desktopservices DSDontWriteUSBStores -bool true
## Dock
#!/bin/bash
set -euo pipefail
# Reset preferences
# rm -f ~/Library/Preferences/com.apple.dock.plist
# Reset Dock layout
defaults write com.apple.dock persistent-apps -array
defaults write com.apple.dock persistent-others -array
# Basic Dock preferences
defaults write com.apple.dock autohide -bool true
defaults write com.apple.dock autohide-delay -float 0
defaults write com.apple.dock autohide-time-modifier -float 0.4
defaults write com.apple.dock enterMissionControlByTopWindowDrag -bool false
defaults write com.apple.dock expose-group-apps -bool true
defaults write com.apple.dock mineffect -string "scale"
defaults write com.apple.dock minimize-to-application -bool false
defaults write com.apple.dock orientation -string "bottom"
defaults write com.apple.dock show-process-indicators -bool false
defaults write com.apple.dock show-recents -bool false
defaults write com.apple.dock showAppExposeGestureEnabled -bool true
defaults write com.apple.dock showDesktopGestureEnabled -bool false
defaults write com.apple.dock showLaunchpadGestureEnabled -bool false
defaults write com.apple.dock tilesize -int 38
# Add Brave Browser
defaults write com.apple.dock persistent-apps -array-add \
"<dict>
<key>tile-data</key>
<dict>
<key>file-data</key>
<dict>
<key>_CFURLString</key>
<string>/Applications/Brave Browser.app</string>
<key>_CFURLStringType</key>
<integer>0</integer>
</dict>
</dict>
<key>tile-type</key>
<string>file-tile</string>
</dict>"
# Add Ghostty
defaults write com.apple.dock persistent-apps -array-add \
"<dict>
<key>tile-data</key>
<dict>
<key>file-data</key>
<dict>
<key>_CFURLString</key>
<string>/Applications/Ghostty.app</string>
<key>_CFURLStringType</key>
<integer>0</integer>
</dict>
</dict>
<key>tile-type</key>
<string>file-tile</string>
</dict>"
# Add Screenshots directory (display as folder, show as grid)
defaults write com.apple.dock persistent-others -array-add \
"<dict>
<key>tile-data</key>
<dict>
<key>displayas</key>
<integer>1</integer>
<key>showas</key>
<integer>2</integer>
<key>file-data</key>
<dict>
<key>_CFURLString</key>
<string>/Users/tomas/Pictures/Screenshots</string>
<key>_CFURLStringType</key>
<integer>0</integer>
</dict>
</dict>
<key>tile-type</key>
<string>directory-tile</string>
</dict>"
# Add Downloads directory (display as folder, show as grid)
defaults write com.apple.dock persistent-others -array-add \
"<dict>
<key>tile-data</key>
<dict>
<key>displayas</key>
<integer>1</integer>
<key>showas</key>
<integer>2</integer>
<key>file-data</key>
<dict>
<key>_CFURLString</key>
<string>/Users/tomas/Downloads</string>
<key>_CFURLStringType</key>
<integer>0</integer>
</dict>
</dict>
<key>tile-type</key>
<string>directory-tile</string>
</dict>"
# Apply changes
killall Finder &>/dev/null
killall Dock &>/dev/null
echo "Setup complete."