Dotfiles cá nhân, quản lý bằng GNU Stow, gom các cấu hình mình dùng hằng ngày cho terminal, editor, shell, window management và key remap trên macOS.
Repo này không chỉ có nvim và wezterm, mà là một bộ workflow tương đối đầy đủ:
WezTerm: giao diện Catppuccin Mocha, nền transparent, tab/status bar đặt lại, có AI usage bar cho Codex/Claude, hotkey toggle nhanh kiểu dropdown terminal, và trợ lý AI đơn giản qua OpenAI API.Neovim: LazyVim + các plugin phục vụ code, note, và xử lý IME để gõ tiếng Việt không pháNormal Mode.Hammerspoon: hotkey toàn hệ thống để bật/tắt WezTerm và quản lý cửa sổ nhanh.Karabiner: hoán đổiCaps Lock/Left Control, thêmvim navigation modebật/tắt bằngd+f, và hỗ trợ bàn phím 60% qua cơ chếgrave -> Escapekhi đang ở navigation mode.Zsh,Yazi,Git,fastfetch: tối ưu shell workflow, di chuyển thư mục nhanh, file manager trong terminal, và trải nghiệm CLI hằng ngày.
- Dotfiles
bash <(curl -fsSL https://raw.githubusercontent.com/thachpn165/dotfiles/main/install.sh)README này hiện tập trung cho macOS.
Script sẽ mở menu chọn component ngay trong terminal: dùng Space để bật/tắt, ↑/↓ hoặc j/k để di chuyển, rồi Enter để xác nhận. Nếu đã từng chạy trước đó, selection cũ sẽ được tick sẵn.
Ví dụ chạy non-interactive:
bash <(curl -fsSL https://raw.githubusercontent.com/thachpn165/dotfiles/main/install.sh) -- --only zsh,nvim,wezterm
bash <(curl -fsSL https://raw.githubusercontent.com/thachpn165/dotfiles/main/install.sh) -- --skip karabiner,hammerspoonNếu máy chưa có, install.sh sẽ tự xử lý các phần sau cho những component bạn chọn:
- Cài Homebrew.
- Cài
gitvàstowtrước, rồi cài thêm dependency đúng theo component được chọn. - Nếu chọn
zsh, script sẽ cài Oh My Zsh, stow~/.config/zsh/, rồi append blocksourcevào~/.zshenv,~/.zprofile,~/.zshrcnếu chưa có, thay vì ghi đè các file shell sẵn có của user. - Nếu chọn
weztermtrên macOS, script sẽ cài thêmpngpaste, WezTerm vàim-select. - Nếu chọn
hammerspoonhoặckarabinertrên macOS, script sẽ cài app tương ứng qua Homebrew Cask. - Clone repo vào
~/dotfilesnếu chưa có; nếu đã có thìgit pull. - Tự init/update git submodules.
- Backup config cũ sang thư mục dạng
~/.dotfiles-backup-YYYYMMDDHHMMSS/trước khi stow nếu phát hiện file/folder thật đang tồn tại. - Dùng
stow --restowcho đúng component được chọn, nên có thể chạy lại để update mà không phải relink toàn bộ. - Ghi nhớ selection gần nhất để lần rerun sau có thể dùng lại ngay.
Script không tự làm các phần sau, bạn vẫn cần cấu hình tay nếu muốn dùng đầy đủ:
OPENAI_API_KEYcho WezTerm AI assistant.~/.ssh/configvà alias host nếu muốn dùng SSH picker / phân biệtprod/staging.- Quyền Accessibility cho Hammerspoon trên macOS.
- Quyền Input Monitoring và Accessibility cho Karabiner-Elements trên macOS.
OBSIDIAN_VAULTnếu vault của bạn không nằm ở path mặc định.
| Package | Target | Cách hoạt động |
|---|---|---|
nvim |
~/.config/nvim/ |
stow (symlink) |
wezterm |
~/.config/wezterm/ |
stow (symlink) |
zsh |
~/.config/zsh/ + block source trong ~/.zshenv, ~/.zprofile, ~/.zshrc |
stow cho phần managed + append idempotent |
hammerspoon |
~/.hammerspoon/ |
stow (symlink) |
git |
~/.gitconfig |
stow (symlink) |
fastfetch |
~/.config/fastfetch/ |
stow (symlink) |
yazi |
~/.config/yazi/ |
stow (symlink) |
karabiner |
~/.config/karabiner/ |
stow (symlink) |
Cài các dependency ở mục Yêu cầu trước, rồi chạy:
git clone https://github.com/thachpn165/dotfiles.git ~/dotfiles
cd ~/dotfiles
git submodule update --init --recursive
stow --restow nvim
stow --restow wezterm
stow --restow zsh
stow --restow hammerspoon
stow --restow git
stow --restow fastfetch
stow --restow yazi
stow --restow karabinerSau đó thêm các block sau nếu file tương ứng chưa có:
# ~/.zshenv
[ -r "$HOME/.config/zsh/.zshenv" ] && source "$HOME/.config/zsh/.zshenv"
# ~/.zprofile
[ -r "$HOME/.config/zsh/.zprofile" ] && source "$HOME/.config/zsh/.zprofile"
# ~/.zshrc
[ -r "$HOME/.config/zsh/.zshrc" ] && source "$HOME/.config/zsh/.zshrc"Để chạy script cài nhanh, bạn chỉ cần:
bashcurl- Kết nối Internet
- Hệ điều hành
macOS
Nếu bạn không dùng install.sh mà muốn cài thủ công, các dependency chính của repo này là:
- Neovim (LazyVim)
- WezTerm
- Oh My Zsh (theme: amuse)
- GNU Stow
- Git
- delta (diff đẹp và dễ đọc)
- Hammerspoon (hotkey toàn hệ thống + tiling)
- Karabiner-Elements (remap phím toàn hệ thống trên macOS)
- eza (thay thế
ls, có tree/icons, xem git status) - bat (thay thế
cat, preview đẹp; tích hợp preview choCtrl+Ttrong fzf) - fastfetch (welcome screen khi mở terminal session mới)
- fzf (fuzzy finder)
- zoxide (smart cd)
- yazi (terminal file manager cho workflow ops)
- ripgrep (Telescope live grep)
- jq (WezTerm AI assistant build/parse JSON)
- glow (markdown preview trong Neovim)
- im-select (macOS IME switching cho Neovim/VSCodeVim)
- macOS (tuỳ chọn):
pngpaste(Obsidian paste image)
Mục tiêu: thay thế app như Rectangle bằng 1 file init.lua nhỏ gọn, sử dụng phím tắt nhanh.
| Phím | Tác vụ |
|---|---|
Cmd+J |
Toggle WezTerm (an/hien/launch trên màn hình đang focus) |
Ctrl+Alt+Left |
Snap left half |
Ctrl+Alt+Right |
Snap right half |
Ctrl+Alt+Up |
Snap top half |
Ctrl+Alt+Down |
Snap bottom half |
Ctrl+Alt+F |
Maximize |
Ctrl+Alt+C |
Center (70%) |
Ghi chú:
- Lần đầu mở cần cấp quyền Accessibility: System Settings -> Privacy & Security -> Accessibility.
- Config tự reload khi save.
Repo này track file karabiner/.config/karabiner/karabiner.json và stow vào ~/.config/karabiner/karabiner.json.
Trên macOS, script install.sh sẽ tự cài karabiner-elements.
Nếu cài tay bằng Homebrew:
brew install --cask karabiner-elementsKarabiner-EventViewer đi kèm chung với Karabiner-Elements, nên không cần cài thêm cask riêng. Sau khi cài xong có thể mở từ Spotlight hoặc:
open -a Karabiner-Elements
open -a Karabiner-EventViewerLần đầu mở, macOS sẽ yêu cầu cấp quyền Input Monitoring và Accessibility cho Karabiner.
Nếu dùng bàn phím rời, vào Karabiner-Elements -> Devices, chọn đúng keyboard đang dùng và bật Modify events. Nếu không bật mục này thì remap có thể không ăn trên bàn phím ngoài dù app vẫn đang chạy.
Nếu đã clone repo và dùng stow, chỉ cần:
stow karabinerSau đó mở Karabiner-Elements để app reload config, hoặc thoát/mở lại app nếu chưa nhận file mới.
Nếu trước đó bạn từng sửa config trực tiếp trong Karabiner-Elements, file thật ở ~/.config/karabiner/karabiner.json có thể đã không còn là symlink về repo này nữa. Khi đó stow karabiner hoặc stow --restow karabiner là cách đồng bộ lại; nếu vẫn không ăn thì kiểm tra lại bằng:
ls -l ~/.config/karabiner/karabiner.jsonNếu output không trỏ về repo này, Karabiner đang dùng file local tách riêng và các thay đổi trong repo sẽ không tự load.
simple_modificationsđang hoán đổi 2 phím vật lý:Caps Lock -> Left ControlvàLeft Control -> Caps Lock.- Vì có bước hoán đổi này, phím
Left Controlvật lý mới là phím kích hoạtHyper(Cmd+Ctrl+Option+Shift) trong cáccomplex_modifications. - Phím
Caps Lockvật lý hiện hoạt động nhưLeft Control. Hypervẫn còn trong config, nhưng không còn là cách chính để điều hướng.- Điều hướng hiện tại dùng
vim_navigation_mode, bật/tắt bằng cách bấm đồng thờid + f. - Trong mode này:
h/j/k/l->Left/Down/Up/Rightu/d->Page Up/Page Downa/e->Home/Endw/b-> nhảy theo từ phải/trái (Option + Arrow)Shift + h/j/k/l-> chọn theo hướngShift + w/b-> chọn theo từShift + a/e-> chọn tới đầu/cuối dòngSpacehoặcEnter-> thoát mode và gõ phím tương ứnggrave_accent_and_tilde-> gửiEscapevà thoát mode
- Thiết kế này hữu ích khi đổi giữa nhiều bàn phím khác nhau, nhất là layout 60%/HHKB-like, nơi không phải lúc nào cũng có
Ctrl,Althoặcgraveở vị trí quen thuộc. - Nếu bạn tự thêm
simple_modificationskiểuEscape -> grave_accent_and_tilde, thì trongvim_navigation_modephím đang ra`sẽ trở lạiEscape.
Một số plugin ZSH hữu ích mình sử dụng mỗi ngày.
- Gợi ý lệnh từ history (
zsh-autosuggestions) - Highlight lệnh để giảm sai (
fast-syntax-highlighting) - Tìm kiếm file/command nhanh (
fzf) - Nhớ đường dẫn thông minh (
zoxide), chỉ cần gõz <tên-folder>không cần gõ full path. - SSH vào prod/staging là biết ngay mình đang ở đâu (màu tab/status trong WezTerm)
zsh-autosuggestions: gõ 1 lần, nhớ cả đờifast-syntax-highlighting: highlight lệnh bash nhanh gọn nhẹ
| Tool | Làm gì | Dùng khi nào |
|---|---|---|
eza |
thay ls (icons/tree/git) |
ls, ll, lt, lg |
bat |
thay cat (highlight + line numbers) |
preview trong fzf (Ctrl+T) |
fzf |
fuzzy finder | Ctrl+R, Ctrl+T |
zoxide |
smart cd | z <folder> |
Wrapper ssh() sẽ set WezTerm user vars để statusbar/tab title có màu theo môi trường (prod đỏ, staging vàng).
Chỉnh host pattern tại ~/.config/zsh/custom/ssh.zsh:
SSH_PRODUCTION_HOSTS="prod-server work-prod"
SSH_STAGING_HOSTS="staging-server"Yazi được cấu hình theo hướng nhanh, ít bấm phím, và hợp với workflow ops + note:
- Preview code/text tốt, wrap dòng dài để đọc log/note dễ hơn.
- Mở file text/code mặc định bằng
nvim. - Có wrapper
yytrong zsh: thoát Yazi xong shell tựcdtới thư mục đang đứng. - Có phím tắt tìm file dự án nhanh bằng
fzf.
| Key | Tác vụ |
|---|---|
Ctrl+P |
Tìm file trong project bằng fzf |
g p |
Tìm file trong project bằng fzf (2 phím kiểu Vim) |
F |
Search tên file qua fd |
E |
Open with... (chọn app/editor mở file) |
z |
Jump nhanh bằng fzf (mặc định Yazi) |
Z |
Jump thư mục bằng zoxide (mặc định Yazi) |
Mẹo dùng shell:
- Gõ
y(alias củayy) để mở Yazi. - Khi thoát, terminal sẽ tự chuyển vào đúng thư mục bạn vừa đứng trong Yazi.
Neovim dùng LazyVim + Catppuccin Mocha cùng một số plugin hữu ích để sử dụng mỗi ngày.
Vấn đề cổ điển: nếu IME tiếng Việt đang bật, bạn bấm w trong Normal/Visual mode mà nó không chạy hoặc bị nuốt phím. Lúc đó bạn sẽ mất motions quan trọng (w, dd, /...)
Repo này đã giải quyết bằng im-select.nvim:
- Khi rời Insert mode (InsertLeave/CmdlineLeave/VimEnter): tự động chuyển IME về
ABC(English) để motions luôn đúng. - Khi vào Insert mode (InsertEnter): trả về IME trước đó (nếu bạn đang gõ tiếng Việt thì cứ gõ tiếp).
Config: nvim/.config/nvim/lua/plugins/im-select.lua (macOS cần có binary im-select).
Tích hợp Obsidian qua obsidian.nvim: search, quick switch, daily note, backlinks, paste image, và mở note bằng app Obsidian.
Sau khi pull update repo này, restart Neovim và chạy:
:Lazy syncOverride biến OBSIDIAN_VAULT nếu cần để khai báo lại đường dẫn Vault mặc định:
export OBSIDIAN_VAULT="$HOME/obsidian-vault"Phím tắt:
| Key | Tác vụ |
|---|---|
<leader>on |
Tạo note mới (title/path) |
<leader>oN |
Tạo note mới (chọn folder bằng Telescope) |
<leader>ot |
Today |
<leader>oy |
Yesterday |
<leader>os |
Search |
<leader>oq |
Quick switch |
<leader>ob |
Backlinks |
<leader>ol |
Links |
<leader>or |
Rename |
<leader>op |
Paste image |
<leader>oo |
Mở note hiện tại trong app Obsidian |
Note: Nếu bạn chưa biết thì phím <leader> trong nvim sẽ là phím Space.
Mẹo dùng nhanh:
- Muốn tạo
Projects/AntiWHMCS/code.md: dùng<leader>oN-> chọnProjects/AntiWHMCS-> nhậpcode. - Paste image: cần
pngpaste
Ghi chú:
- Nếu thấy cảnh báo
Obsidian vault not found: path vault sai hoặc iCloud chưa mount -> setOBSIDIAN_VAULT. - LazyVim có thể dùng
blink.cmpthay vìnvim-cmp; plugin đã tự động tắt completion integration nếu không cócmp.
- hardtime.nvim: nhắc bạn dùng motions tốt hơn khi lặp
hjklquá nhiều - precognition.nvim: gợi ý phím điều hướng bằng virtual text
Code block trong .md được syntax highlight bằng Treesitter (bao gồm markdown/markdown_inline và các parser phổ biến như bash, lua, json, yaml, php, ts/js, ...).
Nếu vừa pull repo:
:Lazy syncdelta làm diff đẹp và dễ đọc (side-by-side), nhưng mình đã giảm độ "nền xanh/nền đỏ" để code không bị "lòe màu" khó đọc.
Áp dụng cho git diff, git log -p, git show qua ~/.gitconfig.
WezTerm là terminal chính: đẹp, nhanh, có workspace/session, và có vài tiện ích dành cho ops.
- Theme: Catppuccin Mocha (opacity 0.7, blur 20)
- Font: Menlo (fallback: MesloLGS Nerd Font Mono)
- Tab bar dưới đáy, có màu theo server type (prod/staging)
- Status bar: workspace, SSH host, git user/branch, AI usage của Codex/Claude, time
- Tra cứu danh sách theme: WezTerm Color Schemes
Nếu muốn đổi theme/font/opacity riêng mà không sửa repo:
- Copy
~/.config/wezterm/local.example.luathành~/.config/wezterm/local.lua - Vào danh sách built-in themes của WezTerm tại WezTerm Color Schemes
- Chọn tên theme muốn dùng rồi sửa
config.color_schemetronglocal.lua - Nếu đổi font thì nhớ dùng font đã cài trên máy
- Save file, WezTerm sẽ tự reload config
Ví dụ:
local M = {}
function M.apply(config)
config.color_scheme = "Calamity"
end
return MKhông cần tải theme repo ngoài nếu theme đó đã có sẵn trong danh sách chính thức của WezTerm.
local.lua đã được ignore trong git, nên mỗi người có thể giữ cấu hình cá nhân riêng.
Leader: Ctrl+A (timeout 2s). Bấm Ctrl+A 2 lần để gửi literal Ctrl+A vào terminal.
WezTerm shortcuts dùng physical key mapping, nên vẫn hoạt động khi bật bộ gõ tiếng Việt trên macOS.
| Key | Tác vụ |
|---|---|
Leader + | |
Split vertical |
Leader + - |
Split horizontal |
Leader + hjkl |
Navigate panes |
Leader + HJKL |
Resize pane |
Leader + x |
Close pane |
Leader + z |
Zoom pane |
| Key | Tác vụ |
|---|---|
Leader + n |
New tab |
Leader + , |
Rename current tab (để trống để reset) |
Leader + 1-9 |
Switch tab N |
Leader + [ / Leader + ] |
Prev/next tab |
| Key | Tác vụ |
|---|---|
Leader + w |
Workspace switcher |
Leader + W |
Tạo workspace mới |
Leader + d |
Xóa workspace hiện tại (gõ lại tên để xác nhận) |
Leader + s |
Save session |
Leader + r |
Restore session |
Leader + g |
SSH host picker |
Leader + N |
Mở scratch notes |
Leader + ? |
Hint leader keys |
| Key | Tác vụ |
|---|---|
Leader + f |
Fullscreen |
Shift + Enter |
Insert newline (zsh bind để xuống dòng không chạy lệnh) |
Ctrl+Shift+P |
Command Palette |
Ctrl+Shift+A |
AI Assistant |
Dùng plugin resurrect.wezterm:
Leader + s: save workspace stateLeader + r: restore session đã lưuLeader + d: xóa workspace hiện tại và session file tương ứng (không cho xóamain)- Auto-save mỗi 5 phút
Trợ lý AI trong WezTerm hoạt động kiểu "Warp-lite": nó lấy 50 dòng output gần nhất, hỏi bạn, trả lời, và nếu có command thì cho chọn để gửi thẳng sang pane chính.
Status bar có thêm 2 segment cho Codex và Claude.
Codex 11%/45%: usage của 2 cửa sổ quota local mà Codex ghi trong session log- Vế đầu là
primarytrong300 phút(khoảng5 giờ) - Vế sau là
secondarytrong10080 phút(khoảng7 ngày) Claude 6%/1%: usage lấy từ Claude OAuth usage API- Vế đầu là
five_hour - Vế sau là
seven_day
Nguồn dữ liệu:
- Codex: đọc từ
~/.codex/sessions/...jsonl - Claude: gọi
https://api.anthropic.com/api/oauth/usagebằng credential local của Claude Code
Dữ liệu được cache ngắn hạn rồi mới render lại để status bar không bị lag khi WezTerm refresh.
Thêm API key vào ~/.secrets (không track git):
export OPENAI_API_KEY="sk-your-key-here"Trong ~/.config/zsh/conf.d/10-editor.zsh:
[ -f "$HOME/.secrets" ] && source "$HOME/.secrets"| Tác vụ | Cách dùng |
|---|---|
| Hỏi lệnh cần chạy | Ctrl+Shift+A -> gõ "how to ..." |
| Giải thích lỗi | Ctrl+Shift+A -> paste lỗi |
| Gợi ý fix nhanh | Ctrl+Shift+A -> "fix this" |
Ghi chú:
- Terminal context tự động kèm theo
- Command được để trong menu (chọn số để gửi)
- Trả lời copy vào clipboard qua
pbcopy - Model:
gpt-4o-mini
~/.config/wezterm/
├── wezterm.lua # entrypoint
├── appearance.lua # theme, font, blur, tab bar
├── keybindings.lua # leader key, pane/tab/workspace
├── statusbar.lua # SSH host, git user/branch, AI usage, time
├── ai_usage.lua # load/cache usage segments for status bar
├── events.lua # tab title formatting, startup, window size
├── workspaces.lua # session save/restore (resurrect)
├── ai.lua # AI assistant launcher
├── ssh_picker.lua # SSH picker (từ ~/.ssh/config)
├── ssh_hosts.lua # classify prod/staging
├── notes.lua # scratch notes
├── leader_hints.lua # hint leader (toast + picker)
└── scripts/
├── ai-ask.sh # AI shell script (OpenAI API)
└── ai-usage.js # probe Codex/Claude usage cho status bar