commit 29e2149d6625de32bb184c5f88028ebffe3c631b Author: syui Date: Mon Mar 30 17:38:45 2026 +0900 init diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 0000000..a8c6f34 --- /dev/null +++ b/.gitconfig @@ -0,0 +1,12 @@ +[user] + name = syui + email = syui@syui.ai + signingkey = 5417CFEBAD92DF56 +[commit] + gpgsign = true +[core] + editor = vim +[pull] + rebase = false +[init] + defaultBranch = main diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a528052 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.DS_Store +.env +.claude +Cargo.lock +node_modules +package-lock.json +/target +/dist +/claude.md +/CLAUDE.md +/tmp +*.swp diff --git a/.hushlogin b/.hushlogin new file mode 100644 index 0000000..e69de29 diff --git a/.local/bin/git-ci b/.local/bin/git-ci new file mode 100755 index 0000000..d8b30e0 --- /dev/null +++ b/.local/bin/git-ci @@ -0,0 +1,10 @@ +#!/bin/bash +if [ $# -eq 0 ]; then + git commit -v +else + if [ "$1" = "--amend" ]; then + git commit -v --amend + else + git commit -m "$*" + fi +fi diff --git a/.local/bin/git-orphan b/.local/bin/git-orphan new file mode 100755 index 0000000..baf78ed --- /dev/null +++ b/.local/bin/git-orphan @@ -0,0 +1,7 @@ +#!/bin/bash +git checkout --orphan temp +git add -A +git commit -m "init" +git branch -D main +git branch -m temp main +git push -f origin main diff --git a/.local/bin/vren b/.local/bin/vren new file mode 100755 index 0000000..1667280 --- /dev/null +++ b/.local/bin/vren @@ -0,0 +1,65 @@ +#!/bin/zsh +# vren - rename files with vim +# usage: vren [dir] + +dir="${1:-.}" +cd "$dir" || exit 1 + +# git init if no .git +has_git=0 +if [ -d .git ]; then + has_git=1 +else + git init -q + git add -A + git commit -q -m "before rename" +fi + +# list files +old=$(mktemp) +new=$(mktemp) +ls -1 > "$old" +cp "$old" "$new" + +# edit +vim "$new" + +# check +old_count=$(wc -l < "$old") +new_count=$(wc -l < "$new") +if [ "$old_count" -ne "$new_count" ]; then + echo "error: line count mismatch ($old_count -> $new_count)" + rm "$old" "$new" + exit 1 +fi + +# diff +changes=0 +paste "$old" "$new" | while IFS=$'\t' read -r o n; do + [ "$o" != "$n" ] && echo " $o -> $n" && changes=$((changes+1)) +done + +if ! diff -q "$old" "$new" >/dev/null 2>&1; then + echo "" + printf "apply? (y/n): " + read -q ans + echo "" + if [ "$ans" = "y" ]; then + paste "$old" "$new" | while IFS=$'\t' read -r o n; do + [ "$o" != "$n" ] && mv -- "$o" "$n" + done + echo "done" + # restore point + if [ "$has_git" -eq 0 ]; then + git add -A + git commit -q -m "after rename" + echo "restore: git log / git checkout HEAD~1 -- ." + fi + else + echo "cancelled" + fi +else + echo "no changes" +fi + +rm "$old" "$new" diff --git a/.local/share/fonts/aifont.ttf b/.local/share/fonts/aifont.ttf new file mode 100644 index 0000000..0725d4a Binary files /dev/null and b/.local/share/fonts/aifont.ttf differ diff --git a/.tmux.conf b/.tmux.conf new file mode 100644 index 0000000..c50bcf9 --- /dev/null +++ b/.tmux.conf @@ -0,0 +1,52 @@ +# prefix +unbind C-b +set -g prefix ^T +bind t send-prefix + +# general +set -s escape-time 0 +set -g base-index 1 +set -g pane-base-index 1 +set -g renumber-windows on +set -g history-limit 10000 +set -g default-terminal "xterm-256color" +set -g allow-passthrough on +set -g set-clipboard on +set-window-option -g mode-keys vi +set-window-option -g xterm-keys on + +# pane/window +bind s split-window -v -c "#{pane_current_path}" +bind v split-window -h -c "#{pane_current_path}" +bind h select-pane -L +bind j select-pane -D +bind k select-pane -U +bind l select-pane -R +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 +bind K kill-pane +bind c new-window +bind w choose-window +bind C-t run "tmux last-pane || tmux last-window || tmux new-window" + +# copy +bind ^y copy-mode +bind -r ^"[" copy-mode +bind p paste-buffer +bind-key -T copy-mode-vi v send-keys -X begin-selection +bind-key -T copy-mode-vi Space send-keys -X begin-selection +if-shell "uname | grep -q Darwin" \ + 'bind-key -T copy-mode-vi y send -X copy-pipe-and-cancel "pbcopy"; bind-key -T copy-mode-vi Enter send -X copy-pipe-and-cancel "pbcopy"' +if-shell 'which xclip' \ + 'bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -i -sel c"; bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xclip -i -sel c"' + +# url open +bind u run-shell "~/.tmux/plugin/urlopen.zsh" + +# plugins +run-shell "~/.tmux/plugin/ailog.zsh" + +# reload +bind r source-file ~/.tmux.conf\; display-message "reloaded" diff --git a/.tmux/plugin/ailog.zsh b/.tmux/plugin/ailog.zsh new file mode 100755 index 0000000..9b3fb2e --- /dev/null +++ b/.tmux/plugin/ailog.zsh @@ -0,0 +1,107 @@ +#!/bin/zsh +# tmux plugin: ailog powerline status bar +# requires: aifont, ailog, jq + +INTERVAL=60 +SEP=$'\ue0b0' +RSEP=$'\ue0b2' + +get_icon() { + local handle=$(ailog pds s 2>/dev/null | jq -r '.handle // empty' 2>/dev/null) + case "$handle" in + ai.*) echo $'\ue001' ;; + syui.*) echo $'\ue002' ;; + *) echo "❯" ;; + esac +} + +get_cfg() { + case "$(uname)" in + Darwin) echo "$HOME/Library/Application Support/ai.syui.log/config.json" ;; + *) echo "${XDG_CONFIG_HOME:-$HOME/.config}/ai.syui.log/config.json" ;; + esac +} + +has_aifont() { + [ -f "$HOME/Library/Fonts/aifont.ttf" ] || [ -f "$HOME/.local/share/fonts/aifont.ttf" ] +} + +can_run() { + local cfg=$(get_cfg) + command -v ailog &>/dev/null && command -v jq &>/dev/null && [ -f "$cfg" ] && has_aifont +} + +get_handle() { + ailog pds s 2>/dev/null | jq -r '.handle // empty' 2>/dev/null +} + +get_notify_count() { + ailog notify count 2>/dev/null | jq -r '.count // 0' 2>/dev/null +} + +get_latest_post() { + local data=$(ailog f tl -l 1 2>/dev/null | tr -d '\t' | sed 's/\\n/ /g') + local handle=$(echo "$data" | jq -r '.feed[0].post.author.handle // empty' 2>/dev/null | cut -d. -f1) + local full=$(echo "$data" | jq -r '.feed[0].post.record.text // empty' 2>/dev/null | tr '\n' ' ') + local text="${full:0:20}" + [[ ${#full} -gt 20 ]] && text+="..." + [ -n "$text" ] && echo "@${handle} ${text}" +} + +status_left() { + can_run || return + local handle=$(get_handle) + local count=$(get_notify_count) + local post=$(get_latest_post) + + local icon=$(get_icon) + local out="" + out+="#[fg=yellow,bg=black] ${icon} " + out+="#[fg=black,bg=colour234]${SEP}" + out+="#[fg=yellow,bg=colour234] @${handle} " + if [ -n "$count" ] && [ "$count" != "0" ] && [ "$count" != "null" ]; then + out+="#[fg=colour234,bg=black]${SEP}" + out+="#[fg=yellow,bg=black] ${count} " + else + out+="#[fg=colour234,bg=black]${SEP}" + fi + if [ -n "$post" ]; then + out+="#[fg=white,bg=black] ${post} " + fi + out+="#[fg=black,bg=default]${SEP}#[default] " + echo -n "$out" +} + +get_pds() { + ailog pds s 2>/dev/null | jq -r '.issuer // empty' 2>/dev/null | sed 's|https://||' +} + +status_right() { + local pds=$(get_pds) + local out="" + if [ -n "$pds" ]; then + out+="#[fg=colour236]${RSEP}#[fg=cyan,bg=colour236] ${pds} " + fi + out+="#[fg=colour234]${RSEP}#[fg=white,bg=colour234] #S " + echo -n "$out" +} + +case "$1" in + left) status_left ;; + right) status_right ;; + notify) get_notify_count ;; + handle) get_handle ;; + latest) get_latest_post ;; + *) + if can_run; then + tmux set-option -g status-style "bg=default,fg=white" + tmux set-window-option -g window-status-format "" + tmux set-window-option -g window-status-current-format "" + tmux set-option -g status-left-length 100 + tmux set-option -g status-right-length 50 + tmux set-option -g status-left "#(~/.tmux/plugin/ailog.zsh left)" + tmux set-option -g status-right "#(~/.tmux/plugin/ailog.zsh right)#[fg=black,bg=colour234]${RSEP}#[fg=white,bg=black] %Y-%m-%dT%H:%M " + tmux set-option -g status-interval $INTERVAL + fi + ;; +esac diff --git a/.tmux/plugin/urlopen.zsh b/.tmux/plugin/urlopen.zsh new file mode 100755 index 0000000..b08cfe2 --- /dev/null +++ b/.tmux/plugin/urlopen.zsh @@ -0,0 +1,7 @@ +#!/bin/zsh +url=$(tmux capture-pane -pJ -S -100 | grep -oE 'https?://[^ ]+' | tail -1) +[ -z "$url" ] && exit 0 +case "$(uname)" in + Darwin) open "$url" ;; + *) xdg-open "$url" ;; +esac diff --git a/.vim/plugin/autosave.vim b/.vim/plugin/autosave.vim new file mode 100644 index 0000000..05bcf31 --- /dev/null +++ b/.vim/plugin/autosave.vim @@ -0,0 +1,26 @@ +if exists('g:loaded_autosave') + finish +endif +let g:loaded_autosave = 1 + +let g:autosave = get(g:, 'autosave', 0) + +fu! s:autosave_start() + aug autosave + au! + au TextChanged,CursorHold,InsertLeave * sil! update + aug END + echo 'autosave: on' +endf + +fu! s:autosave_stop() + au! autosave + echo 'autosave: off' +endf + +com! AirsaveOn call autosave_start() +com! AirsaveOff call autosave_stop() + +if g:autosave + call autosave_start() +endif diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..f52ffa9 --- /dev/null +++ b/.vimrc @@ -0,0 +1,37 @@ +set nocompatible +set encoding=utf-8 +set fileencoding=utf-8 +set number +set ruler +set cursorline +set showmatch +set laststatus=2 +set wildmenu +set showcmd + +set tabstop=4 +set shiftwidth=4 +set softtabstop=4 +set autoindent +set smartindent + +set incsearch +set hlsearch +set ignorecase +set smartcase +set wrapscan + +set backspace=indent,eol,start +set clipboard=unnamed +set mouse=a +set ttimeoutlen=10 + +let g:autosave = 1 +nnoremap Q :q! + +call plug#begin('~/.vim/plugged') +Plug 'github/copilot.vim' +call plug#end() + +syntax on +filetype plugin indent on diff --git a/.zsh/plugin/cdselect.zsh b/.zsh/plugin/cdselect.zsh new file mode 100644 index 0000000..55c916f --- /dev/null +++ b/.zsh/plugin/cdselect.zsh @@ -0,0 +1,57 @@ +autoload -Uz chpwd_recent_dirs cdr add-zsh-hook +add-zsh-hook chpwd chpwd_recent_dirs +zstyle ':chpwd:*' recent-dirs-max 50 + +cdselect() { + local dirs=("${(@f)$(cdr -l 2>/dev/null | sed 's/^[0-9]* *//')}") + [[ ${#dirs} -eq 0 ]] && return + local query="" cursor=1 selected="" + while true; do + local filtered=() + for d in "${dirs[@]}"; do + local match=1 + for word in ${(s: :)query}; do + [[ "${d:l}" != *"${word:l}"* ]] && match=0 && break + done + [[ $match -eq 1 ]] && filtered+=("$d") + done + # sort by path length (shortest first) + local sorted=() + for f in "${filtered[@]}"; do sorted+=("${#f} $f"); done + sorted=(${(n)sorted}) + filtered=() + for s in "${sorted[@]}"; do filtered+=("${s#* }"); done + [[ $cursor -gt ${#filtered} ]] && cursor=${#filtered} + [[ $cursor -lt 1 ]] && cursor=1 + clear + echo "cd> $query" + local i=1 + for d in "${filtered[@]}"; do + if [[ $i -eq $cursor ]]; then + printf "\e[7m %s\e[0m\n" "$d" + else + printf " %s\n" "$d" + fi + ((i++)) + [[ $i -gt 20 ]] && break + done + read -k1 key 2>/dev/null + case "$key" in + $'\n'|$'\r') [[ ${#filtered} -gt 0 ]] && selected="${filtered[$cursor]}"; break ;; + $'\x0e') ((cursor++)) ;; # C-n + $'\x10') ((cursor--)) ;; # C-p + $'\x7f'|$'\b') query="${query%?}"; cursor=1 ;; + $'\x1b') break ;; + *) query+="$key"; cursor=1 ;; + esac + done + clear + if [[ -n "$selected" ]]; then + selected="${selected/#\~/$HOME}" + selected="${selected//\\ / }" + cd "$selected" + fi + zle reset-prompt +} +zle -N cdselect +bindkey '^j' cdselect diff --git a/.zsh/plugin/cdup.zsh b/.zsh/plugin/cdup.zsh new file mode 100644 index 0000000..660b752 --- /dev/null +++ b/.zsh/plugin/cdup.zsh @@ -0,0 +1,3 @@ +cdup() { [[ -z "$BUFFER" ]] && { cd ..; zle reset-prompt } || zle self-insert 'k' } +zle -N cdup +bindkey '^k' cdup diff --git a/.zsh/plugin/clipcopy.zsh b/.zsh/plugin/clipcopy.zsh new file mode 100644 index 0000000..c296107 --- /dev/null +++ b/.zsh/plugin/clipcopy.zsh @@ -0,0 +1,14 @@ +# copy prompt buffer to clipboard +# C-p C-p (chord) + +clipcopy() { + if [[ -n "$BUFFER" ]]; then + case "$(uname)" in + Darwin) echo -n "$BUFFER" | pbcopy ;; + *) echo -n "$BUFFER" | xclip -sel c 2>/dev/null ;; + esac + zle -M "copied" + fi +} +zle -N clipcopy +bindkey '^p^p' clipcopy diff --git a/.zsh/plugin/fileselect.zsh b/.zsh/plugin/fileselect.zsh new file mode 100644 index 0000000..be8f452 --- /dev/null +++ b/.zsh/plugin/fileselect.zsh @@ -0,0 +1,49 @@ +# file select - search files and insert into prompt +# C-f: open file selector + +fileselect() { + local files=("${(@f)$(find . -maxdepth 3 -not -path '*/\.git/*' -type f 2>/dev/null | sed 's|^\./||' | sort)}") + [[ ${#files} -eq 0 ]] && return + local query="" cursor=1 selected="" + while true; do + local filtered=() + for f in "${files[@]}"; do + local match=1 + for word in ${(s: :)query}; do + [[ "${f:l}" != *"${word:l}"* ]] && match=0 && break + done + [[ $match -eq 1 ]] && filtered+=("$f") + done + [[ $cursor -gt ${#filtered} ]] && cursor=${#filtered} + [[ $cursor -lt 1 ]] && cursor=1 + clear + echo "file> $query (${#filtered})" + local i=1 + for f in "${filtered[@]}"; do + if [[ $i -eq $cursor ]]; then + printf "\e[7m %s\e[0m\n" "$f" + else + printf " %s\n" "$f" + fi + ((i++)) + [[ $i -gt 20 ]] && break + done + read -k1 key 2>/dev/null + case "$key" in + $'\n'|$'\r') [[ ${#filtered} -gt 0 ]] && selected="${filtered[$cursor]}"; break ;; + $'\x0e') ((cursor++)) ;; # C-n + $'\x10') ((cursor--)) ;; # C-p + $'\x7f'|$'\b') query="${query%?}"; cursor=1 ;; + $'\x1b') break ;; + *) query+="$key"; cursor=1 ;; + esac + done + clear + if [[ -n "$selected" ]]; then + BUFFER+="$selected" + CURSOR=${#BUFFER} + fi + zle reset-prompt +} +zle -N fileselect +bindkey '^f' fileselect diff --git a/.zsh/plugin/histselect.zsh b/.zsh/plugin/histselect.zsh new file mode 100644 index 0000000..d5d804b --- /dev/null +++ b/.zsh/plugin/histselect.zsh @@ -0,0 +1,49 @@ +# history select - search history and insert into prompt +# C-r: open history selector, type to filter, C-n/C-p to move, Enter to insert + +histselect() { + local lines=("${(@f)$(fc -l -n -r 1 | awk '!seen[$0]++')}") + [[ ${#lines} -eq 0 ]] && return + local query="" cursor=1 selected="" + while true; do + local filtered=() + for l in "${lines[@]}"; do + local match=1 + for word in ${(s: :)query}; do + [[ "${l:l}" != *"${word:l}"* ]] && match=0 && break + done + [[ $match -eq 1 ]] && filtered+=("$l") + done + [[ $cursor -gt ${#filtered} ]] && cursor=${#filtered} + [[ $cursor -lt 1 ]] && cursor=1 + clear + echo "hist> $query" + local i=1 + for l in "${filtered[@]}"; do + if [[ $i -eq $cursor ]]; then + printf "\e[7m %s\e[0m\n" "$l" + else + printf " %s\n" "$l" + fi + ((i++)) + [[ $i -gt 20 ]] && break + done + read -k1 key 2>/dev/null + case "$key" in + $'\n'|$'\r') [[ ${#filtered} -gt 0 ]] && selected="${filtered[$cursor]}"; break ;; + $'\x0e') ((cursor++)) ;; # C-n + $'\x10') ((cursor--)) ;; # C-p + $'\x7f'|$'\b') query="${query%?}"; cursor=1 ;; + $'\x1b') break ;; + *) query+="$key"; cursor=1 ;; + esac + done + clear + if [[ -n "$selected" ]]; then + BUFFER="$selected" + CURSOR=${#BUFFER} + fi + zle reset-prompt +} +zle -N histselect +bindkey '^r' histselect diff --git a/.zsh/plugin/powerline.zsh b/.zsh/plugin/powerline.zsh new file mode 100644 index 0000000..2bf1daa --- /dev/null +++ b/.zsh/plugin/powerline.zsh @@ -0,0 +1,55 @@ +# powerline prompt +# requires: aifont (MesloLGS NF + ai/syui icons) + +_has_aifont() { + [[ -f "$HOME/Library/Fonts/aifont.ttf" ]] || [[ -f "$HOME/.local/share/fonts/aifont.ttf" ]] +} + +_powerline_git() { + local branch=$(git symbolic-ref --short HEAD 2>/dev/null) || return + local dirty="" + [[ -n $(git status --porcelain 2>/dev/null) ]] && dirty="*" + echo "${branch}${dirty}" +} + +_powerline_icon() { + case "$USER" in + syui) echo $'\ue002' ;; + ai) echo $'\ue001' ;; + *) echo "❯" ;; + esac +} + +_powerline_prompt() { + local icon=$(_powerline_icon) + local sep=$'\ue0b0' + local dir="${PWD/#$HOME/~}" + local git=$(_powerline_git) + + local prompt="" + if [[ -n "$icon" ]]; then + prompt+="%F{yellow}%K{black} ${icon} %k%f" + prompt+="%F{black}%K{234}${sep}%f" + else + prompt+="%F{234}${sep}%f" + fi + prompt+="%F{yellow}%K{234} $USER %k%f" + prompt+="%F{234}%K{236}${sep}%f" + prompt+="%F{white}%K{236} ${dir} %k%f" + + if [[ -n "$git" ]]; then + prompt+="%F{236}%K{234}${sep}%f" + prompt+="%F{cyan}%K{234} ${git} %k%f" + prompt+="%F{234}${sep}%f" + else + prompt+="%F{236}${sep}%f" + fi + prompt+="%k%f " + + echo "$prompt" +} + +if _has_aifont; then + setopt PROMPT_SUBST + PROMPT='$(_powerline_prompt)' +fi diff --git a/.zshrc b/.zshrc new file mode 100644 index 0000000..5c20661 --- /dev/null +++ b/.zshrc @@ -0,0 +1,64 @@ +export CARGO_HOME="$HOME/.cargo" +export RUSTUP_HOME="$HOME/.rustup" +export PATH="$HOME/.cargo/bin:$HOME/.local/bin:$PATH" + +if command -v tmux &>/dev/null && [ -z "$TMUX" ] && [ -z "$SSH_CONNECTION" ]; then + tmux new +fi + +alias c="claude" +alias t="tmux" +alias v="vim" +alias ts="vim ~/.tmux.conf" +alias vs="vim ~/.vimrc" +alias zs="vim ~/.zshrc" +alias zr="exec $SHELL && . ~/.zshrc" +alias ll="ls -alh" +alias df="df -H" +alias f="vren" + +zmodload zsh/complist +zstyle ':completion:*' menu select +zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' +autoload -Uz compinit +compinit +bindkey -M menuselect '^n' down-line-or-history +bindkey -M menuselect '^p' up-line-or-history +#bindkey -M menuselect '^j' accept-and-menu-complete + +HISTSIZE=10000 +SAVEHIST=10000 +HISTFILE=~/.zsh_history +setopt SHARE_HISTORY +setopt HIST_IGNORE_DUPS + +case $OSTYPE in + darwin*) + alias ls="ls -aG" + alias ll="ls -alhG" + alias date=/opt/homebrew/bin/gdate + alias u="brew update && brew upgrade && brew doctor" + export PATH="/opt/homebrew/bin:$PATH" + ;; + linux*) + alias ls="ls -a --color=auto" + alias ll="ls -alh --color=auto" + alias u="sudo pacman -Syu --noconfirm" + fpath=(/usr/share/zsh/site-functions $fpath) + ;; +esac + +for p in /opt/homebrew/share /usr/share/zsh/plugins; do + [ -f "$p/zsh-autosuggestions/zsh-autosuggestions.zsh" ] && source "$p/zsh-autosuggestions/zsh-autosuggestions.zsh" + [ -f "$p/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" ] && source "$p/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" + [ -f "$p/zsh-history-substring-search/zsh-history-substring-search.zsh" ] && source "$p/zsh-history-substring-search/zsh-history-substring-search.zsh" +done + +bindkey '^[[A' history-substring-search-up +bindkey '^[[B' history-substring-search-down + +chpwd() { ls } + +for f in ~/.zsh/plugin/*.zsh; do source "$f"; done + + diff --git a/install.zsh b/install.zsh new file mode 100755 index 0000000..7d69f28 --- /dev/null +++ b/install.zsh @@ -0,0 +1,51 @@ +#!/bin/zsh +# dotfiles installer +# usage: ./install.zsh [dotfiles_dir] + +dotdir="${1:-$HOME/dotfiles}" + +files=(.zshrc .vimrc .tmux.conf .gitconfig) +dirs=(.zsh .vim/plugin .tmux .local/bin .local/share/fonts) + +# backup and symlink files +for f in "${files[@]}"; do + src="$dotdir/$f" + dst="$HOME/$f" + [ ! -f "$src" ] && continue + if [ -e "$dst" ] && [ ! -L "$dst" ]; then + mv "$dst" "${dst}.bak" + echo "backup: $dst -> ${dst}.bak" + fi + ln -sf "$src" "$dst" + echo "link: $dst -> $src" +done + +# symlink directories +for d in "${dirs[@]}"; do + src="$dotdir/.${d#.}" + dst="$HOME/.${d#.}" + # handle nested dirs + if [[ "$d" == */* ]]; then + src="$dotdir/$d" + dst="$HOME/$d" + mkdir -p "$(dirname "$dst")" + else + src="$dotdir/$d" + dst="$HOME/$d" + fi + [ ! -d "$src" ] && continue + if [ -d "$dst" ] && [ ! -L "$dst" ]; then + mv "$dst" "${dst}.bak" + echo "backup: $dst -> ${dst}.bak" + fi + ln -sf "$src" "$dst" + echo "link: $dst -> $src" +done + +# install font (mac only) +if [ "$(uname)" = "Darwin" ] && [ -f "$dotdir/.local/share/fonts/aifont.ttf" ]; then + cp -f "$dotdir/.local/share/fonts/aifont.ttf" ~/Library/Fonts/aifont.ttf + echo "font: aifont.ttf -> ~/Library/Fonts/" +fi + +echo "done"