feat: re-organise files dir
This commit is contained in:
77
home/.aliases
Normal file
77
home/.aliases
Normal file
@@ -0,0 +1,77 @@
|
||||
alias bench='ZSH_BENCH=1 exec zsh'
|
||||
alias dots='cd $DOTFILES'
|
||||
alias j='z'
|
||||
alias ji='zi'
|
||||
alias reload='source ~/.zshrc'
|
||||
alias reload-path='rm -f "${XDG_CACHE_HOME:-$HOME/.cache}/dots/path" && exec zsh'
|
||||
alias reload-cache='rm -rf "${XDG_CACHE_HOME:-$HOME/.cache}/dots" ~/.zcompdump* && exec zsh'
|
||||
alias zen='curl -s https://api.github.com/zen && echo'
|
||||
alias la='ls -la'
|
||||
alias vi='vim'
|
||||
alias copilot='gh copilot'
|
||||
if [[ -z "${CODESPACES:-}" ]]; then
|
||||
cs() {
|
||||
local codespace="${1:-}"
|
||||
if [[ -z "$codespace" ]]; then
|
||||
codespace="$(gh cs list --json name -q '.[].name' | fzf)" || return
|
||||
fi
|
||||
[[ -n "$TMUX" ]] && tmux rename-window "cs:$codespace"
|
||||
trap '[[ -n "$TMUX" ]] && tmux set automatic-rename on' EXIT INT TERM
|
||||
gh cs ssh -c "$codespace"
|
||||
local rc=$?
|
||||
trap - EXIT INT TERM
|
||||
[[ -n "$TMUX" ]] && tmux set automatic-rename on
|
||||
if (( rc == 0 )); then
|
||||
local log="${XDG_DATA_HOME:-$HOME/.local/share}/ssh/log"
|
||||
mkdir -p "$(dirname "$log")"
|
||||
printf '%s cs:%s\n' "$(date +%s)" "$codespace" >> "$log"
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
fi
|
||||
alias colby='copilot --allow-all-tools --allow-all-paths'
|
||||
alias gs='git s'
|
||||
alias gd='git d'
|
||||
alias gdc='git dc'
|
||||
alias gc='git c'
|
||||
alias gl='git ld'
|
||||
alias ga='git a'
|
||||
alias gr='git r'
|
||||
|
||||
# fzf workflows
|
||||
gb() { local b; b="$(git branch --all --sort=-committerdate --format='%(refname:short)' | fzf --preview 'git log --oneline --color -20 {}')" && git checkout "${b#origin/}"; }
|
||||
glo() { git log --oneline --color --decorate | fzf --ansi --preview 'git show --color --stat {1}' --bind 'enter:become(echo {1})'; }
|
||||
f() { local f; f="$(fzf --preview 'head -100 {}')" && ${EDITOR:-vim} "$f"; }
|
||||
|
||||
if [[ -z "${CODESPACES:-}" ]]; then
|
||||
ssh() {
|
||||
local ssh_target="${@: -1}"
|
||||
[[ -n "$TMUX" ]] && tmux rename-window "ssh:$ssh_target"
|
||||
trap '[[ -n "$TMUX" ]] && tmux set automatic-rename on' EXIT INT TERM
|
||||
command ssh "$@"
|
||||
local rc=$?
|
||||
trap - EXIT INT TERM
|
||||
[[ -n "$TMUX" ]] && tmux set automatic-rename on
|
||||
|
||||
if (( rc == 0 )); then
|
||||
local host="$ssh_target"
|
||||
local ssh_log="${XDG_DATA_HOME:-$HOME/.local/share}/ssh/log"
|
||||
mkdir -p "$(dirname "$ssh_log")"
|
||||
|
||||
if [[ "$ssh_target" == *@* ]]; then
|
||||
local user="${ssh_target%%@*}"
|
||||
host="${ssh_target#*@}"
|
||||
local config_file="$HOME/.ssh/config.d/auto"
|
||||
mkdir -p "$HOME/.ssh/config.d"
|
||||
if ! grep -q "^Host $host$" "$config_file" 2>/dev/null; then
|
||||
printf '\nHost %s\n HostName %s\n User %s\n' "$host" "$host" "$user" >> "$config_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '%s %s\n' "$(date +%s)" "$host" >> "$ssh_log"
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
s() { local h; h="$(_dots_ssh_hosts | fzf)" && ssh "$h"; }
|
||||
fi
|
||||
|
||||
4
home/.bash_profile
Normal file
4
home/.bash_profile
Normal file
@@ -0,0 +1,4 @@
|
||||
# Load .profile, containing login, non-bash related initializations.
|
||||
[ -f "$HOME/.profile" ] && source "$HOME/.profile"
|
||||
|
||||
command -v mise &>/dev/null && eval "$(mise activate bash)"
|
||||
11
home/.config/.gitignore
vendored
Normal file
11
home/.config/.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
**/coc
|
||||
**/configstore
|
||||
**/firebase
|
||||
**/gcloud
|
||||
**/gh
|
||||
**/helm
|
||||
**/htop
|
||||
**/procps
|
||||
**/stripe
|
||||
**/TabNine
|
||||
**/wslu
|
||||
90
home/.gitconfig
Normal file
90
home/.gitconfig
Normal file
@@ -0,0 +1,90 @@
|
||||
[user]
|
||||
name = Andrejus
|
||||
email = git@andrejus.uk
|
||||
|
||||
[github]
|
||||
user = andrejusk
|
||||
|
||||
[credential]
|
||||
helper =
|
||||
|
||||
[credential "https://github.com"]
|
||||
helper = !/usr/bin/env gh auth git-credential
|
||||
|
||||
[credential "https://gist.github.com"]
|
||||
helper = !/usr/bin/env gh auth git-credential
|
||||
|
||||
[init]
|
||||
defaultBranch = master
|
||||
|
||||
[core]
|
||||
autocrlf = input
|
||||
pager = delta
|
||||
|
||||
[interactive]
|
||||
diffFilter = delta --color-only
|
||||
|
||||
[delta]
|
||||
navigate = true
|
||||
side-by-side = false
|
||||
line-numbers = true
|
||||
paging = always
|
||||
pager = less --mouse -R -+X -+F
|
||||
file-decoration-style = none
|
||||
file-style = "#2CB494" bold
|
||||
hunk-header-decoration-style = none
|
||||
line-numbers-left-style = "#2CB494"
|
||||
line-numbers-right-style = "#2CB494"
|
||||
plus-style = syntax "#0c2a24"
|
||||
plus-emph-style = syntax "#164a3c"
|
||||
|
||||
[merge]
|
||||
conflictstyle = zdiff3
|
||||
|
||||
[color]
|
||||
ui = auto
|
||||
|
||||
[color "status"]
|
||||
added = 42
|
||||
changed = 226
|
||||
untracked = 196
|
||||
branch = 45
|
||||
[color "diff"]
|
||||
meta = 91
|
||||
frag = 45
|
||||
old = 196
|
||||
new = 42
|
||||
context = 252
|
||||
[color "branch"]
|
||||
current = 45
|
||||
local = 252
|
||||
remote = 27
|
||||
[color "decorate"]
|
||||
branch = 45
|
||||
remoteBranch = 27
|
||||
tag = 226
|
||||
stash = 201
|
||||
|
||||
[alias]
|
||||
l = log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --date=short
|
||||
ls = log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate
|
||||
ll = log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --numstat
|
||||
ld = log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --date=relative
|
||||
le = log --oneline --decorate
|
||||
lg = log --graph --decorate --oneline
|
||||
d = diff
|
||||
ds = diff --stat
|
||||
dc = diff --cached
|
||||
s = status -s
|
||||
b = "!git for-each-ref --sort='-authordate' --format='%(authordate)%09%(objectname:short)%09%(refname)' refs/heads | sed -e 's-refs/heads/--'"
|
||||
a = add
|
||||
r = restore --staged
|
||||
ap = add -p
|
||||
c = commit --verbose
|
||||
ca = commit -a --verbose
|
||||
cm = commit -m
|
||||
cam = commit -a -m
|
||||
m = commit --amend --verbose
|
||||
st = stash
|
||||
sa = stash apply
|
||||
|
||||
30
home/.profile
Normal file
30
home/.profile
Normal file
@@ -0,0 +1,30 @@
|
||||
# Environment
|
||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
export WORKSPACE="${WORKSPACE:-$HOME/Workspace}"
|
||||
if [[ -n "${CODESPACES:-}" ]]; then
|
||||
export DOTFILES="${DOTFILES:-/workspaces/.codespaces/.persistedshare/dotfiles}"
|
||||
else
|
||||
export DOTFILES="${DOTFILES:-$HOME/.dotfiles}"
|
||||
fi
|
||||
export EDITOR=vim
|
||||
export VISUAL=vim
|
||||
export PAGER=less
|
||||
|
||||
# Homebrew
|
||||
export HOMEBREW_NO_ANALYTICS=1
|
||||
export HOMEBREW_NO_ENV_HINTS=1
|
||||
|
||||
# PATH setup with caching
|
||||
_dots_path_cache="${XDG_CACHE_HOME:-$HOME/.cache}/dots/path"
|
||||
if [[ -f "$_dots_path_cache" && "$_dots_path_cache" -nt ~/.profile ]]; then
|
||||
export PATH="$(cat "$_dots_path_cache")"
|
||||
else
|
||||
[[ ":$PATH:" != *":$HOME/.local/bin:"* ]] && export PATH="$HOME/.local/bin:$PATH"
|
||||
[[ -x "/opt/homebrew/bin/brew" && ":$PATH:" != *":/opt/homebrew/bin:"* ]] && export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"
|
||||
|
||||
# Cache the result
|
||||
mkdir -p "$(dirname "$_dots_path_cache")"
|
||||
echo "$PATH" > "$_dots_path_cache"
|
||||
fi
|
||||
unset _dots_path_cache
|
||||
8
home/.ssh/config
Normal file
8
home/.ssh/config
Normal file
@@ -0,0 +1,8 @@
|
||||
Include config.d/*
|
||||
|
||||
Host *
|
||||
IgnoreUnknown UseKeychain
|
||||
UseKeychain yes
|
||||
AddKeysToAgent yes
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
|
||||
76
home/.tmux.conf
Normal file
76
home/.tmux.conf
Normal file
@@ -0,0 +1,76 @@
|
||||
# Prefix: Ctrl+A
|
||||
unbind C-b
|
||||
set -g prefix C-a
|
||||
bind C-a send-prefix
|
||||
|
||||
# True color
|
||||
set -g default-terminal "tmux-256color"
|
||||
set -ag terminal-overrides ",xterm-256color:RGB"
|
||||
|
||||
# Shell
|
||||
set -g default-shell "$SHELL"
|
||||
|
||||
# Windows and panes start at 1
|
||||
set -g base-index 1
|
||||
setw -g pane-base-index 1
|
||||
set -g renumber-windows on
|
||||
set -g history-limit 100000
|
||||
set -sg escape-time 10
|
||||
set -g focus-events on
|
||||
set -g display-time 4000
|
||||
|
||||
# Mouse
|
||||
set -g mouse on
|
||||
set -g set-clipboard on
|
||||
|
||||
# Copy mode
|
||||
setw -g mode-keys vi
|
||||
bind -T copy-mode-vi v send -X begin-selection
|
||||
bind -T copy-mode-vi y send -X copy-pipe-and-cancel "pbcopy 2>/dev/null || xclip -selection clipboard 2>/dev/null || xsel --clipboard"
|
||||
bind -T copy-mode-vi MouseDown1Pane send -X clear-selection
|
||||
bind -T copy-mode-vi MouseDragEnd1Pane send -X copy-pipe "pbcopy 2>/dev/null || xclip -selection clipboard 2>/dev/null || xsel --clipboard"
|
||||
|
||||
# Splits
|
||||
bind | split-window -h -c "#{pane_current_path}"
|
||||
bind - split-window -v -c "#{pane_current_path}"
|
||||
unbind '"'
|
||||
unbind %
|
||||
|
||||
bind c new-window -c "#{pane_current_path}"
|
||||
|
||||
# Pane navigation
|
||||
bind h select-pane -L
|
||||
bind j select-pane -D
|
||||
bind k select-pane -U
|
||||
bind l select-pane -R
|
||||
|
||||
# Pane resize
|
||||
bind -r C-h resize-pane -L 5
|
||||
bind -r C-j resize-pane -D 5
|
||||
bind -r C-k resize-pane -U 5
|
||||
bind -r C-l resize-pane -R 5
|
||||
|
||||
# Quick switch to last window
|
||||
bind a last-window
|
||||
|
||||
# Reload
|
||||
bind r source-file ~/.tmux.conf \; display "Config reloaded"
|
||||
|
||||
# Status bar
|
||||
set -g status-position bottom
|
||||
set -g status-interval 5
|
||||
set -g status-style "fg=#728cb8,bg=default"
|
||||
set -g status-left ""
|
||||
set -g status-right ""
|
||||
set -g window-status-format " #I:#W "
|
||||
set -g window-status-current-format "#[fg=#2cb494,bold] #I:#W "
|
||||
set -g window-status-bell-style "fg=#f88c14,bold"
|
||||
set -g pane-border-style "fg=#728cb8"
|
||||
set -g pane-active-border-style "fg=#2cb494"
|
||||
set -g message-style "fg=#2cb494,bg=default"
|
||||
set -g message-command-style "fg=#f88c14,bg=default"
|
||||
set -g mode-style "fg=default,bg=#728cb8,bold"
|
||||
|
||||
# Auto-rename
|
||||
set -g automatic-rename on
|
||||
set -g automatic-rename-format '#{?#{==:#{pane_current_command},zsh},zsh:#{b:pane_current_path},#{pane_current_command}}'
|
||||
220
home/.vimrc
Normal file
220
home/.vimrc
Normal file
@@ -0,0 +1,220 @@
|
||||
let mapleader = " "
|
||||
|
||||
set number relativenumber
|
||||
set ignorecase smartcase incsearch hlsearch
|
||||
set autoindent expandtab tabstop=4 shiftwidth=4 softtabstop=4
|
||||
set scrolloff=8 wildmenu showcmd laststatus=2
|
||||
set mouse=a
|
||||
set hidden
|
||||
set noswapfile nobackup undofile
|
||||
let s:undo_dir = expand('~/.vim/undodir')
|
||||
if !isdirectory(s:undo_dir)
|
||||
call mkdir(s:undo_dir, 'p')
|
||||
endif
|
||||
set undodir=~/.vim/undodir
|
||||
set undolevels=1000
|
||||
set undoreload=10000
|
||||
set belloff=all
|
||||
set noerrorbells
|
||||
|
||||
set lazyredraw
|
||||
set synmaxcol=500
|
||||
set redrawtime=500
|
||||
set maxmempattern=5000
|
||||
set nomodeline
|
||||
set noshowmatch
|
||||
silent! set diffopt+=vertical,algorithm:histogram,indent-heuristic,iwhite,foldcolumn:0
|
||||
|
||||
if executable('rg')
|
||||
set grepprg=rg\ --vimgrep\ --smart-case\ --hidden\ -g\ '!.git'
|
||||
set grepformat=%f:%l:%c:%m
|
||||
endif
|
||||
set path+=**
|
||||
set wildignore+=**/node_modules/**,**/.git/**,**/vendor/**
|
||||
set wildignore+=**/tmp/**,**/dist/**,**/build/**,**/__pycache__/**,**/*.pyc
|
||||
|
||||
augroup filetypes
|
||||
autocmd!
|
||||
autocmd FileType gitcommit setlocal spell spelllang=en_gb textwidth=72 colorcolumn=50,72
|
||||
autocmd FileType go setlocal noexpandtab softtabstop=0
|
||||
autocmd FileType markdown,text setlocal spell spelllang=en_gb wrap
|
||||
autocmd FileType python setlocal textwidth=88 colorcolumn=88
|
||||
autocmd FileType typescript,typescriptreact setlocal syntax=javascript
|
||||
autocmd FileType qf nnoremap <buffer> q :cclose<CR>
|
||||
augroup END
|
||||
|
||||
augroup quickfix
|
||||
autocmd!
|
||||
autocmd QuickFixCmdPost [^l]* cwindow
|
||||
augroup END
|
||||
|
||||
let g:netrw_banner = 0
|
||||
let g:netrw_liststyle = 3
|
||||
let g:netrw_browse_split = 4
|
||||
|
||||
set background=dark
|
||||
|
||||
if has('termguicolors') && ($COLORTERM ==# 'truecolor' || $COLORTERM ==# '24bit')
|
||||
set termguicolors
|
||||
endif
|
||||
|
||||
highlight clear
|
||||
if exists("syntax_on")
|
||||
syntax reset
|
||||
endif
|
||||
syntax enable
|
||||
|
||||
highlight Normal guifg=#CCE0D0 guibg=NONE
|
||||
highlight LineNr guifg=#808080 guibg=NONE
|
||||
highlight CursorLineNr guifg=#FCFC38 guibg=NONE gui=bold
|
||||
highlight StatusLine guifg=#CCE0D0 guibg=#000080 gui=bold
|
||||
highlight StatusLineNC guifg=#808080 guibg=#000080 gui=NONE
|
||||
highlight VertSplit guifg=#808080 guibg=NONE
|
||||
highlight ColorColumn guibg=#2A1A0A
|
||||
|
||||
highlight Comment guifg=#808080 gui=italic
|
||||
highlight Constant guifg=#F88C14
|
||||
highlight String guifg=#2CB494
|
||||
highlight Number guifg=#F88C14
|
||||
highlight Identifier guifg=NONE
|
||||
highlight Function guifg=#7290B8 gui=bold
|
||||
highlight Statement guifg=#4068D4
|
||||
highlight Keyword guifg=#4068D4
|
||||
highlight Type guifg=#2CB494
|
||||
highlight Special guifg=#88409C
|
||||
highlight PreProc guifg=#F88C14
|
||||
highlight Error guifg=#F40404 guibg=NONE gui=bold,underline
|
||||
highlight Todo guifg=#FCFC38 guibg=NONE gui=bold
|
||||
|
||||
highlight Search guifg=#3C3C3C guibg=#FCFC38
|
||||
highlight IncSearch guifg=#3C3C3C guibg=#F88C14
|
||||
|
||||
highlight DiffAdd guifg=#2CB494 guibg=#0A2A1A gui=NONE
|
||||
highlight DiffDelete guifg=#F40404 guibg=#2A0A0A gui=NONE
|
||||
highlight DiffChange guifg=#4068D4 guibg=#0A1A2A gui=NONE
|
||||
highlight DiffText guifg=#CCE0D0 guibg=#1A2A3A gui=bold
|
||||
|
||||
highlight diffAdded guifg=#2CB494 gui=bold
|
||||
highlight diffRemoved guifg=#F40404 gui=bold
|
||||
highlight diffFile guifg=#7290B8 gui=bold
|
||||
highlight diffIndexLine guifg=#88409C
|
||||
highlight diffLine guifg=#00E4FC
|
||||
highlight diffSubname guifg=#F88C14
|
||||
|
||||
highlight SpellBad guifg=#F40404 gui=undercurl guisp=#F40404
|
||||
highlight SpellCap guifg=#FCFC38 gui=undercurl guisp=#FCFC38
|
||||
highlight SpellRare guifg=#88409C gui=undercurl guisp=#88409C
|
||||
|
||||
highlight Visual guibg=#1A3050
|
||||
|
||||
highlight Pmenu guifg=#CCE0D0 guibg=#000080
|
||||
highlight PmenuSel guifg=#3C3C3C guibg=#2CB494 gui=bold
|
||||
|
||||
highlight Folded guifg=#808080 guibg=#1A1A1A gui=NONE
|
||||
highlight FoldColumn guifg=#808080 guibg=NONE
|
||||
|
||||
highlight QuickFixLine guibg=#1A3050 gui=bold
|
||||
|
||||
" UI Groups
|
||||
highlight Title guifg=#00E4FC gui=bold
|
||||
highlight Underlined guifg=#CCE0D0 gui=underline
|
||||
highlight Directory guifg=#7290B8
|
||||
highlight MatchParen guifg=#3C3C3C guibg=#2CB494
|
||||
highlight NonText guifg=#808080
|
||||
highlight SpecialKey guifg=#808080
|
||||
highlight EndOfBuffer guifg=#808080
|
||||
highlight Conceal guifg=#808080
|
||||
highlight CursorLine guibg=#0A2A1A gui=NONE
|
||||
highlight CursorColumn guibg=#0A2A1A
|
||||
highlight SignColumn guifg=#808080 guibg=NONE
|
||||
highlight WarningMsg guifg=#FCFC38
|
||||
highlight ErrorMsg guifg=#F40404 gui=bold
|
||||
highlight ModeMsg guifg=#CCE0D0 gui=bold
|
||||
highlight MoreMsg guifg=#2CB494
|
||||
highlight Question guifg=#2CB494
|
||||
highlight WildMenu guifg=#3C3C3C guibg=#FCFC38
|
||||
highlight TabLine guifg=#808080 guibg=#000080 gui=NONE
|
||||
highlight TabLineFill guibg=#000080
|
||||
highlight TabLineSel guifg=#CCE0D0 guibg=#000080 gui=bold
|
||||
highlight SpellLocal guifg=#00E4FC gui=undercurl guisp=#00E4FC
|
||||
|
||||
" Syntax Groups
|
||||
highlight Boolean guifg=#F88C14
|
||||
highlight Float guifg=#F88C14
|
||||
highlight Character guifg=#2CB494
|
||||
highlight Conditional guifg=#4068D4
|
||||
highlight Repeat guifg=#4068D4
|
||||
highlight Label guifg=#88409C
|
||||
highlight Operator guifg=#CCE0D0
|
||||
highlight Exception guifg=#F40404
|
||||
highlight Include guifg=#F88C14
|
||||
highlight Define guifg=#F88C14
|
||||
highlight Macro guifg=#F88C14
|
||||
highlight PreCondit guifg=#F88C14
|
||||
highlight StorageClass guifg=#4068D4
|
||||
highlight Structure guifg=#4068D4
|
||||
highlight Typedef guifg=#4068D4
|
||||
highlight Delimiter guifg=#CCE0D0
|
||||
highlight SpecialChar guifg=#88409C
|
||||
highlight SpecialComment guifg=#FCFC38
|
||||
highlight Debug guifg=#F032E6
|
||||
highlight Tag guifg=#7290B8
|
||||
highlight Ignore guifg=#808080
|
||||
|
||||
" HTML/Markdown Groups
|
||||
highlight htmlBold guifg=#CCE0D0 gui=bold
|
||||
highlight htmlItalic guifg=#CCE0D0 gui=italic
|
||||
highlight htmlTagName guifg=#4068D4
|
||||
highlight htmlLink guifg=#CCE0D0 gui=underline
|
||||
highlight htmlTag guifg=#808080
|
||||
highlight htmlEndTag guifg=#808080
|
||||
highlight markdownH1Delimiter guifg=#808080
|
||||
highlight markdownH2Delimiter guifg=#808080
|
||||
highlight markdownH3Delimiter guifg=#808080
|
||||
highlight markdownH4Delimiter guifg=#808080
|
||||
highlight markdownH5Delimiter guifg=#808080
|
||||
highlight markdownH6Delimiter guifg=#808080
|
||||
|
||||
" Language-specific Groups
|
||||
highlight pythonBuiltinObj guifg=#F88C14
|
||||
highlight pythonDottedName guifg=#CCE0D0
|
||||
highlight rubyInterpolation guifg=#88409C
|
||||
highlight rubyInterpolationDelimiter guifg=#88409C
|
||||
highlight rubyBlockParameter guifg=#CCE0D0
|
||||
highlight rubyBlockArgument guifg=#CCE0D0
|
||||
highlight jsxCloseString guifg=#4068D4
|
||||
|
||||
function! GitRoot()
|
||||
let l:root = systemlist('git rev-parse --show-toplevel')[0]
|
||||
if v:shell_error == 0 && isdirectory(l:root)
|
||||
execute 'silent cd' fnameescape(l:root)
|
||||
echo 'Project Root: ' . l:root
|
||||
else
|
||||
echo 'Not in a git repository'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! OpenScratch()
|
||||
split | noswapfile hide enew
|
||||
setlocal buftype=nofile bufhidden=hide localindentkeys=
|
||||
nnoremap <buffer> q :q<CR>
|
||||
endfunction
|
||||
|
||||
nnoremap <leader>gr :call GitRoot()<CR>
|
||||
nnoremap <leader>s :call OpenScratch()<CR>
|
||||
nnoremap <leader>t :!ctags -R .<CR>
|
||||
nnoremap <Esc><Esc> :nohlsearch<CR>
|
||||
nnoremap <leader>dw :set diffopt+=iwhite<CR>
|
||||
nnoremap <leader>dW :set diffopt-=iwhite<CR>
|
||||
|
||||
nnoremap ]c ]czz
|
||||
nnoremap [c [czz
|
||||
nnoremap ]q :cnext<CR>zz
|
||||
nnoremap [q :cprev<CR>zz
|
||||
nnoremap <C-j> :cnext<CR>
|
||||
nnoremap <C-k> :cprev<CR>
|
||||
|
||||
nnoremap <leader>g :silent grep! <cword><CR>
|
||||
vnoremap <leader>g "zy:silent grep! "<C-R>z""<CR>
|
||||
nnoremap <leader>/ :grep<Space>
|
||||
|
||||
281
home/.zsh/prompt.zsh
Normal file
281
home/.zsh/prompt.zsh
Normal file
@@ -0,0 +1,281 @@
|
||||
# Prompt
|
||||
(( ${+PROMPT_MIN_DURATION} )) || typeset -gi PROMPT_MIN_DURATION=2 # show duration after N seconds
|
||||
(( ${+PROMPT_FLASH_DELAY} )) || typeset -gi PROMPT_FLASH_DELAY=4 # flash prompt for N centiseconds
|
||||
|
||||
typeset -gi _dots_prompt_cmd_start=0
|
||||
typeset -gi _dots_prompt_cmd_ran=0
|
||||
typeset -gi _dots_prompt_flashing=0
|
||||
typeset -g _dots_prompt_symbol="λ"
|
||||
typeset -g _dots_prompt_base=""
|
||||
typeset -gA _dots_pc
|
||||
|
||||
_dots_init_colors() {
|
||||
if [[ "$COLORTERM" == (truecolor|24bit) ]]; then
|
||||
_dots_pc=(
|
||||
teal $'%{\e[38;2;44;180;148m%}'
|
||||
orange $'%{\e[38;2;248;140;20m%}'
|
||||
red $'%{\e[38;2;244;4;4m%}'
|
||||
grey $'%{\e[38;2;114;144;184m%}'
|
||||
)
|
||||
elif [[ "$TERM" == *256color* ]]; then
|
||||
_dots_pc=(
|
||||
teal $'%{\e[38;5;43m%}'
|
||||
orange $'%{\e[38;5;208m%}'
|
||||
red $'%{\e[38;5;196m%}'
|
||||
grey $'%{\e[38;5;103m%}'
|
||||
)
|
||||
else
|
||||
_dots_pc=(
|
||||
teal $'%{\e[36m%}'
|
||||
orange $'%{\e[33m%}'
|
||||
red $'%{\e[31m%}'
|
||||
grey $'%{\e[34m%}'
|
||||
)
|
||||
fi
|
||||
_dots_pc[reset]=$'%{\e[0m%}'
|
||||
_dots_pc[bold]=$'%{\e[1m%}'
|
||||
}
|
||||
|
||||
_dots_abbrev_path() {
|
||||
local dir="${PWD/#$HOME/~}"
|
||||
local -a parts=( "${(@s:/:)dir}" )
|
||||
local count=${#parts[@]}
|
||||
|
||||
(( count <= 3 )) && { print -r -- "$dir"; return }
|
||||
|
||||
local result=""
|
||||
local i
|
||||
for (( i=1; i <= count-3; i++ )); do
|
||||
result+="${parts[i][1]}/"
|
||||
done
|
||||
print -r -- "${result}${parts[-3]}/${parts[-2]}/${parts[-1]}"
|
||||
}
|
||||
|
||||
_dots_session() {
|
||||
[[ -n "$CODESPACE_NAME" ]] && { print -r -- "$CODESPACE_NAME"; return }
|
||||
[[ -n "$SSH_CONNECTION" || -n "$SSH_CLIENT" || -n "$SSH_TTY" ]] && { print -r -- "%n@%m"; return }
|
||||
[[ -f /.dockerenv ]] && { print -r -- "${DEVCONTAINER_ID:-$(</etc/hostname)}"; return }
|
||||
}
|
||||
|
||||
_dots_git_info_sync() {
|
||||
# Use git status --short with awk for better performance
|
||||
# Avoids shell loops and uses compiled awk for parsing
|
||||
local output
|
||||
output=$(git status --short --branch --ignore-submodules=dirty 2>/dev/null) || return
|
||||
|
||||
local branch="" ahead=0 behind=0 staged=0 unstaged=0 untracked=0
|
||||
|
||||
# Parse efficiently: branch info from first line, counts from rest
|
||||
local first_line="${output%%$'\n'*}"
|
||||
|
||||
# Extract branch from "## branch...remote [ahead N, behind M]"
|
||||
if [[ "$first_line" == "## "* ]]; then
|
||||
branch="${first_line#\#\# }"
|
||||
# Handle detached HEAD
|
||||
if [[ "$branch" == "HEAD (no branch)" || "$branch" == [0-9a-f]##* ]]; then
|
||||
branch="${branch:0:7}"
|
||||
else
|
||||
# Remove tracking info
|
||||
branch="${branch%%...*}"
|
||||
branch="${branch%% *}"
|
||||
fi
|
||||
|
||||
# Extract ahead/behind
|
||||
[[ "$first_line" =~ "ahead ([0-9]+)" ]] && ahead="${match[1]}"
|
||||
[[ "$first_line" =~ "behind ([0-9]+)" ]] && behind="${match[1]}"
|
||||
fi
|
||||
|
||||
[[ -z "$branch" ]] && return
|
||||
|
||||
# Count file status with awk (fast, no shell loops)
|
||||
local -a counts
|
||||
counts=( $(awk '
|
||||
NR == 1 { next } # Skip branch line
|
||||
/^\?\?/ { untracked++; next }
|
||||
{
|
||||
x = substr($0, 1, 1)
|
||||
y = substr($0, 2, 1)
|
||||
if (x != " " && x != "?") staged++
|
||||
if (y != " " && y != "?") unstaged++
|
||||
}
|
||||
END { print staged+0, unstaged+0, untracked+0 }
|
||||
' <<< "$output") )
|
||||
|
||||
staged=${counts[1]:-0}
|
||||
unstaged=${counts[2]:-0}
|
||||
untracked=${counts[3]:-0}
|
||||
|
||||
local info="${_dots_pc[grey]}(${branch})${_dots_pc[reset]}"
|
||||
|
||||
local dirty=""
|
||||
local sep=""
|
||||
if (( staged )); then
|
||||
dirty+="${_dots_pc[teal]}+${staged}${_dots_pc[reset]}"
|
||||
sep=" "
|
||||
fi
|
||||
if (( unstaged )); then
|
||||
dirty+="${sep}${_dots_pc[orange]}~${unstaged}${_dots_pc[reset]}"
|
||||
sep=" "
|
||||
fi
|
||||
if (( untracked )); then
|
||||
dirty+="${sep}${_dots_pc[grey]}?${untracked}${_dots_pc[reset]}"
|
||||
fi
|
||||
|
||||
local arrows=""
|
||||
sep=""
|
||||
if (( ahead )); then
|
||||
arrows+="${_dots_pc[teal]}↑${ahead}${_dots_pc[reset]}"
|
||||
sep=" "
|
||||
fi
|
||||
if (( behind )); then
|
||||
arrows+="${sep}${_dots_pc[orange]}↓${behind}${_dots_pc[reset]}"
|
||||
fi
|
||||
|
||||
if [[ -n "$dirty" || -n "$arrows" ]]; then
|
||||
info+=" "
|
||||
[[ -n "$dirty" ]] && info+="$dirty"
|
||||
[[ -n "$dirty" && -n "$arrows" ]] && info+=" "
|
||||
[[ -n "$arrows" ]] && info+="$arrows"
|
||||
fi
|
||||
|
||||
print -r -- "$info"
|
||||
}
|
||||
|
||||
# Async git info
|
||||
typeset -g _dots_git_info_result=""
|
||||
typeset -g _dots_git_info_pwd=""
|
||||
typeset -g _dots_git_async_fd=""
|
||||
|
||||
_dots_git_async_callback() {
|
||||
local fd=$1
|
||||
local result=""
|
||||
# Use sysread for efficient non-blocking read from fd
|
||||
if [[ -n "$fd" ]] && sysread -i "$fd" result 2>/dev/null; then
|
||||
result="${result%$'\n'}" # trim trailing newline
|
||||
_dots_git_info_result="$result"
|
||||
_dots_build_dots_prompt_base
|
||||
PROMPT="$_dots_prompt_base"
|
||||
zle && zle reset-prompt
|
||||
fi
|
||||
# Clean up
|
||||
exec {fd}<&-
|
||||
zle -F "$fd" 2>/dev/null
|
||||
_dots_git_async_fd=""
|
||||
}
|
||||
|
||||
_dots_git_async_start() {
|
||||
# Check if we're in a git repo
|
||||
local git_dir
|
||||
git_dir=$(git rev-parse --git-dir 2>/dev/null) || return
|
||||
|
||||
# Cancel any pending async job (reuse single worker)
|
||||
if [[ -n "$_dots_git_async_fd" ]]; then
|
||||
exec {_dots_git_async_fd}<&- 2>/dev/null
|
||||
zle -F "$_dots_git_async_fd" 2>/dev/null
|
||||
_dots_git_async_fd=""
|
||||
fi
|
||||
|
||||
# Start background job
|
||||
exec {_dots_git_async_fd}< <(
|
||||
_dots_git_info_sync
|
||||
)
|
||||
zle -F "$_dots_git_async_fd" _dots_git_async_callback
|
||||
}
|
||||
|
||||
_dots_build_dots_prompt_base() {
|
||||
local dir_path="$(_dots_abbrev_path)"
|
||||
local symbol="${_dots_pc[grey]}${_dots_prompt_symbol}${_dots_pc[reset]}"
|
||||
(( EUID == 0 )) && symbol="${_dots_pc[orange]}${_dots_pc[bold]}#${_dots_pc[reset]}"
|
||||
|
||||
local line1="${_dots_pc[teal]}${dir_path}${_dots_pc[reset]}"
|
||||
[[ -n "$_dots_git_info_result" ]] && line1+=" ${_dots_git_info_result}"
|
||||
|
||||
_dots_prompt_base=$'\n'"${line1}"$'\n'"${symbol} "
|
||||
}
|
||||
|
||||
_dots_preexec() {
|
||||
_dots_prompt_cmd_start=$EPOCHSECONDS
|
||||
_dots_prompt_cmd_ran=1
|
||||
}
|
||||
|
||||
_dots_precmd() {
|
||||
local e=$? d=0
|
||||
# Only show exit code if a command actually ran
|
||||
(( _dots_prompt_cmd_ran )) || e=0
|
||||
_dots_prompt_cmd_ran=0
|
||||
# First prompt should never show error from shell init
|
||||
[[ -z "$_dots_first_prompt" ]] && { _dots_first_prompt=1; e=0; }
|
||||
|
||||
# Build RPROMPT: time, error, host
|
||||
local rp_parts=()
|
||||
|
||||
if (( _dots_prompt_cmd_start )); then
|
||||
d=$(( EPOCHSECONDS - _dots_prompt_cmd_start ))
|
||||
_dots_prompt_cmd_start=0
|
||||
if (( d >= PROMPT_MIN_DURATION )); then
|
||||
(( d >= 60 )) && rp_parts+=("${_dots_pc[grey]}($(( d/60 ))m$(( d%60 ))s)${_dots_pc[reset]}") \
|
||||
|| rp_parts+=("${_dots_pc[grey]}(${d}s)${_dots_pc[reset]}")
|
||||
fi
|
||||
fi
|
||||
|
||||
(( e )) && rp_parts+=("${_dots_pc[red]}[${e}]${_dots_pc[reset]}")
|
||||
|
||||
local session="$(_dots_session)"
|
||||
[[ -n "$session" ]] && rp_parts+=("${_dots_pc[orange]}[${session}]${_dots_pc[reset]}")
|
||||
|
||||
RPROMPT="${(j: :)rp_parts}"
|
||||
|
||||
# On directory change, clear git info until async refreshes
|
||||
if [[ "$PWD" != "$_dots_git_info_pwd" ]]; then
|
||||
_dots_git_info_pwd="$PWD"
|
||||
_dots_git_info_result=""
|
||||
fi
|
||||
|
||||
_dots_build_dots_prompt_base
|
||||
_dots_git_async_start
|
||||
PROMPT="$_dots_prompt_base"
|
||||
}
|
||||
|
||||
|
||||
|
||||
TRAPINT() {
|
||||
# Only customize when ZLE is active (at prompt, not during command)
|
||||
if [[ -o zle ]] && [[ -o interactive ]] && (( ${+WIDGET} )); then
|
||||
if [[ -z "$BUFFER" ]] && (( ! _dots_prompt_flashing )); then
|
||||
# Empty buffer: flash the prompt symbol
|
||||
_dots_prompt_flashing=1
|
||||
local git_part=""
|
||||
[[ -n "$_dots_git_info_result" ]] && git_part=" ${_dots_git_info_result}"
|
||||
local flash_prompt=$'\n'"${_dots_pc[teal]}$(_dots_abbrev_path)${_dots_pc[reset]}${git_part}"$'\n'$'%{\e[48;2;248;140;20m\e[30m%}'"${_dots_prompt_symbol}"$' %{\e[0m%}'
|
||||
PROMPT="$flash_prompt"
|
||||
zle reset-prompt
|
||||
zselect -t $PROMPT_FLASH_DELAY
|
||||
_dots_prompt_flashing=0
|
||||
PROMPT="$_dots_prompt_base"
|
||||
zle reset-prompt
|
||||
return 0
|
||||
elif [[ -n "$BUFFER" ]]; then
|
||||
# Buffer has content: clear autosuggest, then default behavior
|
||||
zle autosuggest-clear 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
# Propagate signal: use special return code -1 to let zsh handle normally
|
||||
return $((128 + ${1:-2}))
|
||||
}
|
||||
|
||||
_dots_prompt_init() {
|
||||
zmodload zsh/datetime 2>/dev/null
|
||||
zmodload zsh/zselect 2>/dev/null
|
||||
zmodload zsh/system 2>/dev/null
|
||||
_dots_init_colors
|
||||
_dots_build_dots_prompt_base
|
||||
|
||||
setopt PROMPT_SUBST EXTENDED_HISTORY INC_APPEND_HISTORY_TIME
|
||||
autoload -Uz add-zsh-hook
|
||||
add-zsh-hook preexec _dots_preexec
|
||||
add-zsh-hook precmd _dots_precmd
|
||||
add-zsh-hook chpwd _dots_build_dots_prompt_base
|
||||
|
||||
PROMPT="$_dots_prompt_base" RPROMPT=""
|
||||
}
|
||||
_dots_prompt_init
|
||||
295
home/.zsh/widgets.zsh
Normal file
295
home/.zsh/widgets.zsh
Normal file
@@ -0,0 +1,295 @@
|
||||
_dots_load_keybindings() {
|
||||
bindkey -e
|
||||
stty -ixon 2>/dev/null
|
||||
|
||||
# Ctrl+J: zoxide jump
|
||||
_dots_zoxide_widget() {
|
||||
local result
|
||||
result="$(zoxide query -i -- 2>&1)" || { zle reset-prompt; return; }
|
||||
BUFFER="cd ${(q)result}"
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_zoxide_widget
|
||||
bindkey '^J' _dots_zoxide_widget
|
||||
|
||||
# Ctrl+B: git branch checkout
|
||||
_dots_git_branch_widget() {
|
||||
local branch
|
||||
branch="$(git branch --all --sort=-committerdate --format='%(refname:short)' 2>/dev/null \
|
||||
| fzf --preview 'git log --oneline --color -20 {}')" || { zle reset-prompt; return; }
|
||||
branch="${branch#origin/}"
|
||||
BUFFER="git checkout ${(q)branch}"
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_git_branch_widget
|
||||
bindkey '^B' _dots_git_branch_widget
|
||||
|
||||
# Ctrl+E: edit file
|
||||
_dots_edit_widget() {
|
||||
local file
|
||||
file="$(rg --files --hidden --glob '!.git' 2>/dev/null \
|
||||
| fzf --preview 'head -100 {}')" || { zle reset-prompt; return; }
|
||||
BUFFER="${EDITOR:-vim} ${(q)file}"
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_edit_widget
|
||||
bindkey '^E' _dots_edit_widget
|
||||
|
||||
# Ctrl+G: remote connect
|
||||
if [[ -z "${CODESPACES:-}" ]]; then
|
||||
_dots_ssh_hosts() {
|
||||
local ssh_log="${XDG_DATA_HOME:-$HOME/.local/share}/ssh/log"
|
||||
local cs_cache="$_dots_cache_dir/codespaces"
|
||||
|
||||
# Refresh codespace cache in background if stale (>5 min)
|
||||
if [[ ! -f "$cs_cache" ]] || [[ -n "$(find "$cs_cache" -mmin +5 2>/dev/null)" ]]; then
|
||||
{ gh cs list --json name -q '.[].name' 2>/dev/null | sed 's/^/cs:/' > "$cs_cache.tmp" && mv "$cs_cache.tmp" "$cs_cache"; } &!
|
||||
fi
|
||||
|
||||
{
|
||||
if [[ -f "$ssh_log" ]]; then
|
||||
awk '{c[$2]++; t[$2]=$1} END {for(h in c) print c[h]*1000+t[h], h}' "$ssh_log" | sort -rn | awk '{print $2}'
|
||||
fi
|
||||
awk '/^Host / && !/\*/ {print $2}' ~/.ssh/config ~/.ssh/config.d/* 2>/dev/null
|
||||
awk '{print $1}' ~/.ssh/known_hosts 2>/dev/null | tr ',' '\n' | sed 's/\[//;s/\]:.*//'
|
||||
[[ -f "$cs_cache" ]] && cat "$cs_cache"
|
||||
} | awk '!seen[$0]++'
|
||||
}
|
||||
_dots_ssh_widget() {
|
||||
local target
|
||||
target="$(_dots_ssh_hosts | fzf)" || { zle reset-prompt; return; }
|
||||
if [[ "$target" == cs:* ]]; then
|
||||
BUFFER="cs ${target#cs:}"
|
||||
else
|
||||
BUFFER="ssh $target"
|
||||
fi
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_ssh_widget
|
||||
bindkey '^G' _dots_ssh_widget
|
||||
else
|
||||
bindkey -r '^G'
|
||||
fi
|
||||
|
||||
# Ctrl+F: find in files
|
||||
_dots_find_in_files_widget() {
|
||||
local selection
|
||||
selection="$(rg --color=always --line-number --no-heading --hidden --glob '!.git' '' 2>/dev/null \
|
||||
| fzf --ansi --delimiter=: \
|
||||
--preview 'head -n $((({2}+30))) {1} | tail -n 60' \
|
||||
--preview-window='right:60%')" || { zle -I; zle reset-prompt; return; }
|
||||
local file="${selection%%:*}"
|
||||
local line="${${selection#*:}%%:*}"
|
||||
BUFFER="${EDITOR:-vim} +${line} ${(q)file}"
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_find_in_files_widget
|
||||
bindkey '^F' _dots_find_in_files_widget
|
||||
|
||||
# Ctrl+A: git log browser
|
||||
_dots_git_log_widget() {
|
||||
local commit
|
||||
commit="$(git log --oneline --color --decorate -50 2>/dev/null \
|
||||
| fzf --ansi --no-sort \
|
||||
--preview 'git show --color=always {1}' \
|
||||
--preview-window='right:60%')" || { zle reset-prompt; return; }
|
||||
BUFFER="git show ${commit%% *}"
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_git_log_widget
|
||||
bindkey '^A' _dots_git_log_widget
|
||||
|
||||
# Ctrl+K: command help lookup
|
||||
_dots_help_widget() {
|
||||
local cmd
|
||||
cmd="$(print -l ${(ko)commands} | fzf --preview 'tldr {1} 2>/dev/null || man -P cat {1} 2>/dev/null | head -80')" \
|
||||
|| { zle reset-prompt; return; }
|
||||
if command -v tldr &>/dev/null; then
|
||||
BUFFER="tldr ${(q)cmd}"
|
||||
else
|
||||
BUFFER="man ${(q)cmd}"
|
||||
fi
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_help_widget
|
||||
bindkey '^K' _dots_help_widget
|
||||
|
||||
# Ctrl+N: tmux session
|
||||
_dots_tmux_widget() {
|
||||
[[ -n "${CODESPACES:-}" ]] && { zle reset-prompt; return; }
|
||||
local sessions
|
||||
sessions="$(tmux list-sessions -F '#{session_name}' 2>/dev/null)"
|
||||
if [[ -z "$sessions" ]]; then
|
||||
BUFFER="tmux new-session"
|
||||
elif [[ -n "$TMUX" ]]; then
|
||||
local session
|
||||
session="$({ echo '+ new session'; echo "$sessions"; } \
|
||||
| fzf --preview 'case {} in "+ new session") echo "Create a new tmux session";; *) tmux list-windows -t {} -F " #{window_index}: #{window_name} #{pane_current_command}";; esac')" \
|
||||
|| { zle reset-prompt; return; }
|
||||
if [[ "$session" == "+ new session" ]]; then
|
||||
BUFFER="tmux new-session -d && tmux switch-client -n"
|
||||
else
|
||||
BUFFER="tmux switch-client -t ${(q)session}"
|
||||
fi
|
||||
else
|
||||
local session
|
||||
session="$(echo "$sessions" \
|
||||
| fzf --preview 'tmux list-windows -t {} -F " #{window_index}: #{window_name} #{pane_current_command}"')" \
|
||||
|| { zle reset-prompt; return; }
|
||||
BUFFER="tmux attach -t ${(q)session}"
|
||||
fi
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_tmux_widget
|
||||
bindkey '^N' _dots_tmux_widget
|
||||
|
||||
# Ctrl+O: open in browser
|
||||
_dots_open_widget() {
|
||||
local choice
|
||||
choice="$(printf 'repo\npr\nissues\nactions' | fzf)" || { zle reset-prompt; return; }
|
||||
case "$choice" in
|
||||
repo) BUFFER="gh browse" ;;
|
||||
pr) BUFFER="gh pr view --web" ;;
|
||||
issues) BUFFER="gh browse --issues" ;;
|
||||
actions) BUFFER="gh browse --actions" ;;
|
||||
esac
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_open_widget
|
||||
bindkey '^O' _dots_open_widget
|
||||
|
||||
# Ctrl+P: project switch
|
||||
_dots_project_widget() {
|
||||
local result
|
||||
result="$(zoxide query -l 2>/dev/null | grep "${WORKSPACE:-$HOME/Workspace}" \
|
||||
| fzf --preview 'ls -1 {}')" || { zle reset-prompt; return; }
|
||||
BUFFER="cd ${(q)result}"
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_project_widget
|
||||
bindkey '^P' _dots_project_widget
|
||||
|
||||
# Ctrl+S: copilot sessions
|
||||
_dots_copilot_session_widget() {
|
||||
local session_dir="$HOME/.copilot/session-state"
|
||||
[[ -d "$session_dir" ]] || { zle reset-prompt; return; }
|
||||
local session
|
||||
session="$(python3 -c "
|
||||
import os, json, glob
|
||||
sd = os.path.expanduser('~/.copilot/session-state')
|
||||
home = os.path.expanduser('~')
|
||||
entries = []
|
||||
for ws in glob.glob(os.path.join(sd, '*/workspace.yaml')):
|
||||
try:
|
||||
d = {}
|
||||
with open(ws) as f:
|
||||
for l in f:
|
||||
for k in ('updated_at:','cwd:','id:','summary:','repository:'):
|
||||
if l.startswith(k): d[k[:-1]] = l.split(': ',1)[1].strip()
|
||||
sid = d.get('id','')
|
||||
if not sid: continue
|
||||
ts = d.get('updated_at','?')[:16]
|
||||
repo = d.get('repository','').split('/')[-1] if d.get('repository') else ''
|
||||
summary = d.get('summary','')
|
||||
msg = ''
|
||||
ev = os.path.join(os.path.dirname(ws), 'events.jsonl')
|
||||
if os.path.exists(ev):
|
||||
with open(ev) as f:
|
||||
for l in f:
|
||||
if '\"user.message\"' in l:
|
||||
try: msg = json.loads(l)['data']['content'].strip().split(chr(10))[0][:60]
|
||||
except: pass
|
||||
break
|
||||
if not msg: continue
|
||||
ctx = repo or d.get('cwd','?').replace(home,'~')
|
||||
label = f'{ctx} \u00b7 {summary}' if summary else f'{ctx} \u00b7 {msg}'
|
||||
entries.append((ts, sid, label))
|
||||
except: pass
|
||||
for jf in glob.glob(os.path.join(sd, '*.jsonl')):
|
||||
try:
|
||||
sid = os.path.basename(jf).replace('.jsonl','')
|
||||
with open(jf) as f:
|
||||
ts = json.loads(f.readline())['data']['startTime'][:16]
|
||||
msg = ''
|
||||
with open(jf) as f:
|
||||
for l in f:
|
||||
if '\"user.message\"' in l:
|
||||
try: msg = json.loads(l)['data']['content'].strip().split(chr(10))[0][:60]
|
||||
except: pass
|
||||
break
|
||||
if not msg: continue
|
||||
entries.append((ts, sid, msg))
|
||||
except: pass
|
||||
entries.sort(key=lambda x: x[0], reverse=True)
|
||||
for ts, sid, label in entries:
|
||||
print(f'{ts} | {sid} | {label}')
|
||||
" 2>/dev/null | fzf --preview '
|
||||
id=$(echo {} | cut -d"|" -f2 | tr -d " ")
|
||||
sd="'"$session_dir"'"
|
||||
f="$sd/$id/events.jsonl"
|
||||
[[ -f "$f" ]] || f="$sd/${id}.jsonl"
|
||||
[[ -f "$f" ]] || exit 0
|
||||
grep "\"user.message\"" "$f" | python3 -c "
|
||||
import sys,json
|
||||
for line in sys.stdin:
|
||||
try:
|
||||
msg=json.loads(line)[\"data\"][\"content\"].strip().split(chr(10))[0][:100]
|
||||
print(\">\", msg)
|
||||
except: pass
|
||||
" 2>/dev/null
|
||||
' --header 'enter=colby | ctrl-r=restricted' \
|
||||
--expect=ctrl-r)" || { zle reset-prompt; return; }
|
||||
local key=$(echo "$session" | head -1)
|
||||
local line=$(echo "$session" | tail -1)
|
||||
local id=$(echo "$line" | cut -d'|' -f2 | tr -d ' ')
|
||||
if [[ "$key" == "ctrl-r" ]]; then
|
||||
BUFFER="gh copilot --resume $id"
|
||||
else
|
||||
BUFFER="copilot --allow-all-tools --allow-all-paths --resume $id"
|
||||
fi
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_copilot_session_widget
|
||||
bindkey '^S' _dots_copilot_session_widget
|
||||
|
||||
# Ctrl+X: process manager
|
||||
_dots_process_widget() {
|
||||
local proc
|
||||
proc="$(ps -eo pid,user,%cpu,%mem,command 2>/dev/null \
|
||||
| fzf --header-lines=1 --preview 'ps -p {1} -o pid,ppid,stat,start,time,command 2>/dev/null' \
|
||||
--preview-window='down:4:wrap')" || { zle reset-prompt; return; }
|
||||
local pid="${${proc## #}%% *}"
|
||||
BUFFER="kill $pid"
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_process_widget
|
||||
bindkey '^X' _dots_process_widget
|
||||
|
||||
# Ctrl+Y: git stash browser
|
||||
_dots_stash_widget() {
|
||||
local stash
|
||||
stash="$(git stash list --color=always 2>/dev/null \
|
||||
| fzf --ansi --no-sort \
|
||||
--preview 'git stash show -p --color=always $(echo {} | cut -d: -f1)' \
|
||||
--preview-window='right:60%')" || { zle reset-prompt; return; }
|
||||
local ref="${stash%%:*}"
|
||||
BUFFER="git stash apply $ref"
|
||||
zle reset-prompt
|
||||
zle accept-line
|
||||
}
|
||||
zle -N _dots_stash_widget
|
||||
bindkey '^Y' _dots_stash_widget
|
||||
}
|
||||
_dots_load_keybindings
|
||||
119
home/.zshrc
Normal file
119
home/.zshrc
Normal file
@@ -0,0 +1,119 @@
|
||||
# Profiling: ZSH_BENCH=1 zsh
|
||||
[[ -n "$ZSH_BENCH" ]] && zmodload zsh/zprof
|
||||
|
||||
# Assume truecolor support if terminal advertises 256color (covers SSH, tmux)
|
||||
[[ -z "$COLORTERM" && "$TERM" == *256color* ]] && export COLORTERM=truecolor
|
||||
|
||||
_dots_cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/dots"
|
||||
|
||||
_dots_load_profile() { source "$HOME/.profile" }
|
||||
_dots_load_profile
|
||||
|
||||
_dots_setup_dirs() {
|
||||
mkdir -p "$XDG_DATA_HOME" "$XDG_CONFIG_HOME" "$HOME/.local/bin" "$WORKSPACE" "$_dots_cache_dir"
|
||||
}
|
||||
_dots_setup_dirs
|
||||
|
||||
_dots_cache_ls_colors() {
|
||||
local cache_file="$_dots_cache_dir/ls-colours"
|
||||
if [[ -f "$cache_file" ]]; then
|
||||
source "$cache_file"
|
||||
else
|
||||
if ls --color -d . &>/dev/null; then
|
||||
echo 'alias ls="ls --color=auto"' > "$cache_file"
|
||||
elif ls -G -d . &>/dev/null; then
|
||||
echo 'alias ls="ls -G"' > "$cache_file"
|
||||
fi
|
||||
[[ -f "$cache_file" ]] && source "$cache_file"
|
||||
fi
|
||||
}
|
||||
_dots_cache_ls_colors
|
||||
|
||||
[[ -f ~/.aliases ]] && source ~/.aliases
|
||||
|
||||
_dots_init_completion() {
|
||||
local comp_dir="${XDG_DATA_HOME:-$HOME/.local/share}/zsh/completions"
|
||||
[[ -d "$comp_dir" ]] && fpath=("$comp_dir" $fpath)
|
||||
|
||||
autoload -Uz compinit
|
||||
# Daily cache invalidation
|
||||
local dump="$HOME/.zcompdump"
|
||||
if [[ -f "$dump" ]]; then
|
||||
zmodload -F zsh/stat b:zstat 2>/dev/null
|
||||
local -a dump_stat
|
||||
zstat -A dump_stat +mtime "$dump" 2>/dev/null
|
||||
if (( dump_stat[1] > EPOCHSECONDS - 86400 )); then
|
||||
compinit -C
|
||||
else
|
||||
compinit
|
||||
fi
|
||||
else
|
||||
compinit
|
||||
fi
|
||||
}
|
||||
_dots_init_completion
|
||||
|
||||
_dots_load_plugins() {
|
||||
local plugin_dir="${XDG_DATA_HOME:-$HOME/.local/share}/zsh/plugins"
|
||||
local f="$plugin_dir/zsh-autosuggestions/zsh-autosuggestions.zsh"
|
||||
[[ -f "$f" ]] && source "$f"
|
||||
# syntax-highlighting must be sourced last
|
||||
f="$plugin_dir/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
|
||||
[[ -f "$f" ]] && source "$f"
|
||||
}
|
||||
_dots_load_plugins
|
||||
|
||||
_dots_load_history() {
|
||||
HISTFILE="${XDG_DATA_HOME:-$HOME/.local/share}/zsh/history"
|
||||
HISTSIZE=50000
|
||||
SAVEHIST=50000
|
||||
[[ -d "${HISTFILE:h}" ]] || mkdir -p "${HISTFILE:h}"
|
||||
setopt HIST_IGNORE_DUPS HIST_IGNORE_SPACE SHARE_HISTORY
|
||||
}
|
||||
_dots_load_history
|
||||
|
||||
setopt IGNORE_EOF
|
||||
|
||||
source "$HOME/.zsh/widgets.zsh"
|
||||
|
||||
_dots_load_fzf() {
|
||||
command -v fzf &>/dev/null || return
|
||||
export FZF_DEFAULT_COMMAND='rg --files --hidden --glob "!.git"'
|
||||
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
|
||||
export FZF_DEFAULT_OPTS='--layout=reverse --height=40% --prompt="> " --info=inline-right --no-separator --margin=1,0,0,0'
|
||||
# fzf --zsh requires v0.48+
|
||||
if fzf --zsh &>/dev/null; then
|
||||
source <(fzf --zsh)
|
||||
else
|
||||
local -a fzf_paths=(
|
||||
"${HOMEBREW_PREFIX:-/opt/homebrew}/opt/fzf/shell"
|
||||
"/usr/share/fzf"
|
||||
"${XDG_DATA_HOME:-$HOME/.local/share}/fzf/shell"
|
||||
)
|
||||
for dir in "${fzf_paths[@]}"; do
|
||||
[[ -f "$dir/key-bindings.zsh" ]] && source "$dir/key-bindings.zsh" && break
|
||||
done
|
||||
for dir in "${fzf_paths[@]}"; do
|
||||
[[ -f "$dir/completion.zsh" ]] && source "$dir/completion.zsh" && break
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
_dots_load_zoxide() {
|
||||
command -v zoxide &>/dev/null || return
|
||||
export _ZO_FZF_OPTS="$FZF_DEFAULT_OPTS"
|
||||
export _ZO_ECHO=0
|
||||
eval "$(zoxide init zsh)"
|
||||
}
|
||||
|
||||
source "$HOME/.zsh/prompt.zsh"
|
||||
|
||||
_dots_load_mise() {
|
||||
command -v mise &>/dev/null && eval "$(mise activate zsh)"
|
||||
}
|
||||
_dots_load_mise
|
||||
_dots_load_fzf
|
||||
_dots_load_zoxide
|
||||
|
||||
[[ -n "$ZSH_BENCH" ]] && zprof || true
|
||||
Reference in New Issue
Block a user