Compare commits
39 Commits
73f620fe39
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 540b18e6e8 | |||
| 49300923f7 | |||
| 5008a3384a | |||
| 74e779ff54 | |||
| 5972c3c5df | |||
| 2fdf72d746 | |||
| f8390f006d | |||
| 0c2b2875ed | |||
| 0ab2aa869c | |||
| 42b634c19b | |||
| ad2e33db35 | |||
| 35a9e08a7e | |||
| 4d895b2c52 | |||
| 9db467735f | |||
| 7b72fa6796 | |||
| 13ddf830c9 | |||
| f4ce2ef3c3 | |||
| 27ec787416 | |||
| f1b0fd94fb | |||
| 866a25a66d | |||
| 34b6439521 | |||
| 60834ccae1 | |||
| 78ea031fd6 | |||
| ed51e48bb4 | |||
| 799b186e9f | |||
| 3b4e2621da | |||
| c8a4741d94 | |||
| 0d394dd577 | |||
| 13530beaaf | |||
| 458847c4af | |||
| 7aaf25ce85 | |||
| fe553b1c3f | |||
| aa8ce447c1 | |||
| 14585bca9e | |||
| 05bdb4abdc | |||
| ec50d3f12f | |||
| c958a0ab9d | |||
| d08998a0ca | |||
| f1b3dbb9c3 |
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[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
153
config.json
@@ -1,153 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
return { globals = { 'vim' } }
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||
"runtime": {
|
||||
"version": "LuaJIT"
|
||||
},
|
||||
"workspace": {
|
||||
"library": [
|
||||
"lua",
|
||||
"$VIMRUNTIME",
|
||||
"${3rd}/luv/library"
|
||||
],
|
||||
"checkThirdParty": false
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
column_width = 100
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
quote_style = "AutoPreferSingle"
|
||||
call_parentheses = "Always"
|
||||
line_endings = "Unix"
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
#============================================================
|
||||
# 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)
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
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
|
||||
```
|
||||
@@ -1,119 +0,0 @@
|
||||
#============================================================
|
||||
# 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.
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
-- 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
|
||||
@@ -1,28 +0,0 @@
|
||||
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 },
|
||||
})
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"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" }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
return {
|
||||
cmd = { "vscode-json-language-server", "--stdio" },
|
||||
filetypes = { "json", "jsonc" },
|
||||
init_options = {
|
||||
provideFormatter = true,
|
||||
},
|
||||
root_markers = { ".git" },
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
return {
|
||||
cmd = { "lua-language-server" },
|
||||
filetypes = { "lua" },
|
||||
root_markers = {
|
||||
".luarc.json",
|
||||
".luarc.jsonc",
|
||||
".luacheckrc",
|
||||
".stylua.toml",
|
||||
"stylua.toml",
|
||||
"selene.toml",
|
||||
"selene.yml",
|
||||
".git",
|
||||
},
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
-- 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,
|
||||
})
|
||||
@@ -1,25 +0,0 @@
|
||||
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, {})
|
||||
@@ -1,54 +0,0 @@
|
||||
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>')
|
||||
@@ -1,89 +0,0 @@
|
||||
-- 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
|
||||
@@ -1,62 +0,0 @@
|
||||
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, {})
|
||||
@@ -1,323 +0,0 @@
|
||||
-- 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
|
||||
@@ -1,26 +0,0 @@
|
||||
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,
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
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',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
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,
|
||||
},
|
||||
}
|
||||
78
config/macos/alacritty/alacritty.toml
Normal file
78
config/macos/alacritty/alacritty.toml
Normal file
@@ -0,0 +1,78 @@
|
||||
[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"
|
||||
27
config/macos/alacritty/themes/alabaster.toml
Normal file
27
config/macos/alacritty/themes/alabaster.toml
Normal file
@@ -0,0 +1,27 @@
|
||||
[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'
|
||||
@@ -1,135 +0,0 @@
|
||||
#!/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 "$@"
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/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
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/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
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
orbctl list > /tmp/vmlist.txt
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Usage: work <vm>
|
||||
vm="$1"
|
||||
if [ -z "$vm" ]; then
|
||||
echo "Usage: work <vm>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec vm "${vm}-orb"
|
||||
|
||||
13
config/macos/borders/bordersrc
Executable file
13
config/macos/borders/bordersrc
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
options=(
|
||||
order=above
|
||||
width=2.0
|
||||
hidpi=on
|
||||
active_color=0xff2b2b2b
|
||||
inactive_color=0xff2b2b2b
|
||||
# inactive_color=0x00000000
|
||||
whitelist="wezterm-gui"
|
||||
)
|
||||
|
||||
borders "${options[@]}"
|
||||
33
config/macos/ghostty/config
Normal file
33
config/macos/ghostty/config
Normal file
@@ -0,0 +1,33 @@
|
||||
#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
|
||||
@@ -1,21 +1,25 @@
|
||||
tap "homebrew/bundle"
|
||||
tap "homebrew/services"
|
||||
brew "bash"
|
||||
brew "dnsmasq", restart_service: :changed
|
||||
brew "neovim"
|
||||
cask "daisydisk"
|
||||
brew "tmux"
|
||||
cask "brave-browser"
|
||||
cask "bruno"
|
||||
cask "dbeaver-community"
|
||||
cask "discord"
|
||||
cask "firefox"
|
||||
cask "font-maple-mono"
|
||||
cask "font-maple-mono-nf"
|
||||
cask "ghostty"
|
||||
cask "google-chrome"
|
||||
cask "karabiner-elements"
|
||||
cask "linearmouse"
|
||||
cask "obsidian"
|
||||
cask "macfuse"
|
||||
cask "orbstack"
|
||||
cask "proton-drive"
|
||||
cask "protonvpn"
|
||||
cask "rectangle"
|
||||
cask "slack"
|
||||
cask "sol"
|
||||
cask "spotify"
|
||||
cask "utm"
|
||||
cask "visual-studio-code"
|
||||
cask "sublime-text"
|
||||
cask "utm@beta"
|
||||
cask "zoom"
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"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" }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"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" }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"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" }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"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" }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -4,38 +4,20 @@
|
||||
{
|
||||
"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": 50475,
|
||||
"vendor_id": 1133
|
||||
},
|
||||
"ignore_vendor_events": true
|
||||
},
|
||||
{
|
||||
"identifiers": {
|
||||
"is_keyboard": true,
|
||||
"product_id": 49164,
|
||||
"vendor_id": 7276
|
||||
"product_id": 50504,
|
||||
"vendor_id": 1133
|
||||
},
|
||||
"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" }]
|
||||
}
|
||||
]
|
||||
"ignore_vendor_events": true
|
||||
}
|
||||
],
|
||||
"name": "Default profile",
|
||||
@@ -46,7 +28,7 @@
|
||||
"to": [{ "key_code": "left_control" }]
|
||||
}
|
||||
],
|
||||
"virtual_hid_keyboard": { "keyboard_type_v2": "ansi" }
|
||||
"virtual_hid_keyboard": { "keyboard_type_v2": "iso" }
|
||||
}
|
||||
]
|
||||
}
|
||||
54
config/macos/kitty/choose_tab.py
Normal file
54
config/macos/kitty/choose_tab.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# ~/.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
|
||||
|
||||
35
config/macos/kitty/invero.conf
Normal file
35
config/macos/kitty/invero.conf
Normal file
@@ -0,0 +1,35 @@
|
||||
# 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
|
||||
BIN
config/macos/kitty/kitty.app.icns
Normal file
BIN
config/macos/kitty/kitty.app.icns
Normal file
Binary file not shown.
73
config/macos/kitty/kitty.conf
Normal file
73
config/macos/kitty/kitty.conf
Normal file
@@ -0,0 +1,73 @@
|
||||
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
|
||||
BIN
config/macos/rectangle/com.knollsoft.Rectangle.plist
Normal file
BIN
config/macos/rectangle/com.knollsoft.Rectangle.plist
Normal file
Binary file not shown.
BIN
config/macos/sol/mmkv.default
Executable file
BIN
config/macos/sol/mmkv.default
Executable file
Binary file not shown.
BIN
config/macos/sol/mmkv.default.crc
Executable file
BIN
config/macos/sol/mmkv.default.crc
Executable file
Binary file not shown.
36
config/macos/wezterm/colors/Invero Day.toml
Normal file
36
config/macos/wezterm/colors/Invero Day.toml
Normal file
@@ -0,0 +1,36 @@
|
||||
[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"
|
||||
72
config/macos/wezterm/wezterm.lua
Normal file
72
config/macos/wezterm/wezterm.lua
Normal file
@@ -0,0 +1,72 @@
|
||||
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
|
||||
85
config/shared/addpaths
Executable file
85
config/shared/addpaths
Executable file
@@ -0,0 +1,85 @@
|
||||
#!/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
|
||||
@@ -1,40 +0,0 @@
|
||||
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
|
||||
1
config/shared/barg-parser
Submodule
1
config/shared/barg-parser
Submodule
Submodule config/shared/barg-parser added at d0344b6c56
@@ -1,97 +0,0 @@
|
||||
#!/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)"
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/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
|
||||
@@ -1,327 +0,0 @@
|
||||
#!/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 "$@"
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/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"
|
||||
12
config/shared/bin/dev-tmux-wrapper.sh
Executable file
12
config/shared/bin/dev-tmux-wrapper.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/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
|
||||
613
config/shared/bin/flow
Executable file
613
config/shared/bin/flow
Executable file
@@ -0,0 +1,613 @@
|
||||
#!/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 container’s 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[@] "$@"
|
||||
39
config/shared/bin/sync-theme
Executable file
39
config/shared/bin/sync-theme
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/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
|
||||
48
config/shared/bin/test-true-color
Executable file
48
config/shared/bin/test-true-color
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/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
|
||||
@@ -1,16 +0,0 @@
|
||||
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
|
||||
@@ -1,22 +0,0 @@
|
||||
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
|
||||
@@ -1,10 +1,24 @@
|
||||
[init]
|
||||
defaultBranch = main
|
||||
[user]
|
||||
name = Tomas Mirchev
|
||||
email = contact@tomastm.com
|
||||
[pull]
|
||||
rebase = true
|
||||
name = Tomas Mirchev
|
||||
email = contact@tomastm.com
|
||||
[core]
|
||||
editor = nvim
|
||||
editor = nvim
|
||||
excludesfile = ~/.gitignore
|
||||
[init]
|
||||
defaultBranch = main
|
||||
[pull]
|
||||
rebase = true
|
||||
[push]
|
||||
default = current
|
||||
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
|
||||
|
||||
|
||||
21
config/shared/gitignore
Normal file
21
config/shared/gitignore
Normal file
@@ -0,0 +1,21 @@
|
||||
.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/
|
||||
@@ -1,161 +0,0 @@
|
||||
-- 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" })
|
||||
1
config/shared/nvim
Submodule
1
config/shared/nvim
Submodule
Submodule config/shared/nvim added at b84e46bda1
@@ -20,14 +20,16 @@ set -g mouse on
|
||||
set -g set-titles on
|
||||
set -g set-titles-string "#S"
|
||||
|
||||
# set -g remain-on-exit on
|
||||
|
||||
set -gw pane-base-index 1 # pane index
|
||||
|
||||
##### Appearance #####
|
||||
set -g status-style fg=black,bg=default
|
||||
set -g window-status-current-style fg=blue,bold
|
||||
set -g message-style fg=blue,bg=default
|
||||
set -g status-left "#[fg=blue,bold][#S] "
|
||||
set -g status-right "host:#H | machine:#{?TARGET_MACHINE,#{TARGET_MACHINE},local}"
|
||||
set -g status-left "#[fg=blue,bold][#{s/^dev-//:#{session_name}}] "
|
||||
set -g status-right " #{?DF_IMAGE,#{DF_IMAGE} | ,}#{?DF_NAMESPACE,#{DF_NAMESPACE},#H}@#{?DF_PLATFORM,#{DF_PLATFORM},local}"
|
||||
set -g status-left-length 50
|
||||
set -g status-right-length 50
|
||||
set -g pane-active-border-style fg=blue
|
||||
@@ -42,6 +44,9 @@ bind -r j select-pane -D
|
||||
bind -r k select-pane -U
|
||||
bind -r l select-pane -R
|
||||
|
||||
# Last window instead of session
|
||||
bind ';' last-window
|
||||
|
||||
unbind '"'
|
||||
unbind "%"
|
||||
unbind s
|
||||
@@ -58,3 +63,9 @@ bind c confirm-before -p "kill-pane \#P? (y/n)" kill-pane
|
||||
##### Misc #####
|
||||
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}"'
|
||||
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
-- 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
|
||||
@@ -1,14 +1,16 @@
|
||||
export PATH="$PATH:$HOME/bin"
|
||||
export PATH="$PATH:$HOME/.local/bin:$HOME/bin"
|
||||
export LANG=en_US.UTF-8
|
||||
export LC_CTYPE=en_US.UTF-8
|
||||
export LC_COLLATE=C
|
||||
|
||||
KEYTIMEOUT=1
|
||||
# eval "$(dircolors)"; echo "$LS_COLORS"
|
||||
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
|
||||
HISTSIZE=10000
|
||||
SAVEHIST=10000
|
||||
|
||||
setopt auto_cd interactive_comments prompt_subst
|
||||
setopt auto_cd interactive_comments prompt_subst share_history
|
||||
setopt append_history hist_ignore_dups hist_ignore_all_dups hist_reduce_blanks
|
||||
|
||||
autoload -Uz compinit
|
||||
@@ -34,9 +36,22 @@ bindkey '^[[B' down-line-or-beginning-search
|
||||
bindkey '^[OB' down-line-or-beginning-search
|
||||
bindkey '^U' backward-kill-line
|
||||
|
||||
# alias ls='ls --color=auto --group-directories-first'
|
||||
alias ls='ls --color=auto'
|
||||
if command -v nvim >/dev/null 2>&1; then
|
||||
alias vim='nvim'
|
||||
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 lla='ll -a'
|
||||
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'
|
||||
|
||||
@@ -10,7 +10,7 @@ import shutil
|
||||
DOTFILES_DIR = Path(__file__).parent
|
||||
SETUPS_DIR = DOTFILES_DIR / "setups"
|
||||
CONFIG_DIR = DOTFILES_DIR / "config"
|
||||
CONFIG_PATH = DOTFILES_DIR / "config.json"
|
||||
CONFIG_PATH = DOTFILES_DIR / "manifest.json"
|
||||
|
||||
def load_config():
|
||||
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):
|
||||
raise ValueError("`link` should follow the structure: `{ from: str, to: str }`")
|
||||
|
||||
if len(link_from.split("/")) != 2:
|
||||
raise ValueError("`link.from` should be '<env>/<package>'")
|
||||
# if len(link_from.split("/")) != 2:
|
||||
# raise ValueError("`link.from` should be '<env>/<package>'")
|
||||
|
||||
package["link"] = {
|
||||
"from": Path(CONFIG_DIR / link_from).expanduser(),
|
||||
|
||||
191
manifest.json
Normal file
191
manifest.json
Normal file
@@ -0,0 +1,191 @@
|
||||
{
|
||||
"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'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
196
scripts/macos-defaults.sh
Executable file
196
scripts/macos-defaults.sh
Executable file
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Close any open System Preferences panes, to prevent them from overriding
|
||||
# settings we’re 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."
|
||||
Reference in New Issue
Block a user