├── .bash_profile ├── .bashrc ├── .config ├── bottom │ └── bottom.toml ├── ghostty │ └── config ├── htop │ └── htoprc ├── nvim │ ├── after │ │ ├── ftplugin │ │ │ ├── c.vim │ │ │ ├── clojure.vim │ │ │ ├── cs.vim │ │ │ ├── gitcommit.vim │ │ │ ├── go.vim │ │ │ ├── help.lua │ │ │ ├── java.vim │ │ │ ├── js.vim │ │ │ ├── lua.lua │ │ │ ├── markdown.vim │ │ │ ├── ps1.vim │ │ │ ├── python.vim │ │ │ ├── sh.vim │ │ │ ├── sql.vim │ │ │ ├── text.vim │ │ │ ├── typescript.vim │ │ │ └── vim.vim │ │ └── indent │ │ │ ├── java.vim │ │ │ └── lua.vim │ ├── doc │ │ └── xwiki.txt │ ├── init.lua │ └── lua │ │ └── my │ │ ├── bufdelete.lua │ │ ├── ctrl_s_shell.lua │ │ ├── fug.lua │ │ ├── hlheadings.lua │ │ ├── img.lua │ │ ├── keymaps.lua │ │ ├── replace-op.lua │ │ ├── slipnslide.lua │ │ ├── vscode-neovim.lua │ │ └── winning.lua └── z │ └── .gitignore ├── .emacs.d ├── elisp │ ├── init-bindings.el │ ├── init-core.el │ ├── init-util.el │ └── package-helper.el └── init.el ├── .gdbinit ├── .gitattributes ├── .gitconfig ├── .gitexcludes ├── .gitignore ├── .ideavimrc ├── .lldbinit ├── .lynxrc ├── .profile ├── .tmux.conf ├── .vimrc ├── .vrapperrc ├── .vsvimrc ├── AppData └── Local │ └── nvim │ └── init.vim ├── Library ├── Application Support │ └── Code │ │ └── User │ │ ├── keybindings.json │ │ └── settings.json └── Preferences │ └── kitty │ ├── kitty.conf │ └── launch-actions.conf └── bin ├── env.sh ├── git-filter-repo ├── git-when-merged ├── lldb_nvim.py └── z.sh /.bash_profile: -------------------------------------------------------------------------------- 1 | # login-shell bash looks for (in order): 2 | # .bash_profile 3 | # .bash_login 4 | # .profile 5 | # and executes _only_ the first one it finds 6 | [[ -s "${HOME}/.profile" ]] && source "${HOME}/.profile" 7 | 8 | -------------------------------------------------------------------------------- /.bashrc: -------------------------------------------------------------------------------- 1 | # Darwin/Debian/Cygwin/MSYS have different behavior: 2 | # - Darwin (and MacVim) runs a login shell every time (sources .bash_profile) 3 | # - MSYSGIT sources .bashrc _then_ .bash_profile (wtf?) 4 | # - Cygwin runs a login shell every time (sources .bash_profile) 5 | # - Debian/Ubuntu sources .bash_profile on login; thereafter only .bashrc 6 | # - GFW/MSYS2: .bash_profile > .profile > .bashrc 7 | 8 | # Environment variables (non-bash-specific) 9 | # ============================================================================= 10 | 11 | # TODO: Nice for performance/explicitness, but doesn't play well with fugitive. 12 | #export GIT_CEILING_DIRECTORIES=~ 13 | 14 | # do not continue if we are not in a bash shell 15 | [ -z "$BASH_VERSION" ] && return 16 | # do not continue if we are not running interactively 17 | [ -z "$PS1" ] && return 18 | 19 | GPG_TTY=$(tty) 20 | export GPG_TTY 21 | 22 | # Non-default history file, to avoid accidental truncation. 23 | [ -f "$HOME/.bash_history_x" ] || { [ -f "$HOME/.bash_history" ] && cp "$HOME/.bash_history" "$HOME/.bash_history_x" ; } 24 | HISTFILE="$HOME/.bash_history_x" 25 | HISTCONTROL=erasedups:ignoreboth 26 | HISTSIZE=99999 27 | HISTFILESIZE=99999 28 | HISTIGNORE='exit:cd:ls:bg:fg:history:f:fd' 29 | HISTTIMEFORMAT='%F %T ' 30 | # append to the history file, don't overwrite it 31 | shopt -s histappend 32 | # Before each command: 33 | # - mark start of prompt (OSC 133) 34 | # - set term title to $_MY_TITLE or cwd 35 | # - append to history file 36 | PROMPT_COMMAND='printf "\033]133;A\007\033]0;${_MY_TITLE:-$PWD}\007" ; history -a' 37 | # truncate long paths to ".../foo/bar/baz" 38 | PROMPT_DIRTRIM=4 39 | 40 | # update $LINES and $COLUMNS after each command. 41 | shopt -s checkwinsize 42 | # (bash 4+) enable recursive glob for grep, rsync, ls, ... 43 | shopt -s globstar &> /dev/null 44 | 45 | # Display matches for ambiguous patterns at first tab press 46 | bind "set show-all-if-ambiguous on" 47 | 48 | SSHAGENT=/usr/bin/ssh-agent 49 | if [ -z "$SSH_AUTH_SOCK" -a -x "$SSHAGENT" ]; then 50 | eval $($SSHAGENT -s) 51 | trap "kill $SSH_AGENT_PID" 0 52 | fi 53 | 54 | path_prepend() { 55 | [ -z "$1" ] && { echo 'path_prepend: missing/empty arg' ; exit 1 ; } 56 | # Remove existing match, if any. 57 | local path=''$(echo $PATH | sed 's:\:'$1'$::' | sed 's:\:'$1'\::\::' | sed 's:^'$1'\:::') 58 | PATH="${1}:${path}" 59 | } 60 | 61 | # Add these dirs to $PATH. 62 | path_prepend "${HOME}/bin" 63 | # path_prepend "${HOME}/dasht/bin" 64 | # path_prepend "${HOME}/ctags/" 65 | 66 | # Add these dirs to $MANPATH. 67 | [ -d "${HOME}/dasht/man" ] && MANPATH="${HOME}/dasht/man:$MANPATH" 68 | 69 | # bash completion (also provides __git_ps1 on some systems). Slow as dirt. 70 | # `brew --prefix` is also slow, avoid it. 71 | # brew install bash-completion@2 72 | # https://github.com/homebrew/brew/blob/89b8619153ce7f523fcf4d1bb5fa4b3a375c22a4/docs/Shell-Completion.md 73 | if [ -r '/opt/homebrew/etc/profile.d/bash_completion.sh' ]; then 74 | # homebrew uses /opt/homebrew for ARM packages. https://apple.stackexchange.com/a/410829/36305 75 | . '/opt/homebrew/etc/profile.d/bash_completion.sh' 76 | 77 | # These are separate, wtf? 78 | . /opt/homebrew/etc/bash_completion.d/git-completion.bash 79 | . /opt/homebrew/etc/bash_completion.d/npm 80 | elif [ -r '/usr/local/etc/profile.d/bash_completion.sh' ]; then 81 | # homebrew uses /usr/local for Intel packages. https://apple.stackexchange.com/a/410829/36305 82 | . '/usr/local/etc/profile.d/bash_completion.sh' 83 | elif [ -d '/usr/local/etc/bash_completion.d' ]; then 84 | for f in '/usr/local/etc/bash_completion.d/'*; do 85 | [ -r "$f" ] && source "$f" 86 | done 87 | elif [ -f /etc/bash_completion ] && ! shopt -oq posix; then 88 | . /etc/bash_completion 89 | fi 90 | 91 | PS1='$([ "$?" = 0 ] || printf "\[\e[1;31m\]")$(date +%m%d.%H%M)\[\e[0m\] \u@\h \w\[\e[0m\] 92 | $ ' 93 | [ -z $SSH_TTY ] || PS1='\[\e[0;30m\]\[\e[47m\]SSH\[\e[0m\] '$PS1 94 | # Mark end of prompt (OSC 133). 95 | 96 | if [ -x /usr/bin/dircolors ]; then 97 | test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" 98 | fi 99 | 100 | alias ls='ls -C --color=auto' 101 | 102 | # change to parent directory matching partial string, eg: 103 | # in directory /home/foo/bar/baz, 'bd f' changes to /home/foo 104 | bd() { 105 | local old_dir=`pwd` 106 | local new_dir=`echo $old_dir | sed 's|\(.*/'$1'[^/]*/\).*|\1|'` 107 | index=`echo $new_dir | awk '{ print index($1,"/'$1'"); }'` 108 | if [ $index -eq 0 ] ; then 109 | echo "No such occurrence." 110 | else 111 | echo $new_dir 112 | cd "$new_dir" 113 | fi 114 | } 115 | 116 | # Some old systems (msysgit) do not support grep --color. 117 | if grep --color "a" <<< "a" &> /dev/null ; then 118 | alias grep='grep --color=auto' 119 | fi 120 | 121 | #MacOS 122 | # http://stackoverflow.com/q/394230/152142 123 | # also: $OSTYPE 124 | if [ "$(uname)" = Darwin ] ; then 125 | export LSCOLORS=GxFxCxDxBxegedabagaced 126 | #BSD-style aliases 127 | alias ls='ls -GC' 128 | 129 | if ! [ '0' = "$(defaults read -g ApplePressAndHoldEnabled)" ] ; then 130 | printf '\n%s\n\n' 'bashrc: initialize macOS defaults' 131 | # Display ASCII control characters using caret notation in standard text views 132 | # Try e.g. `cd /tmp; unidecode "\x{0000}" > cc.txt; open -e cc.txt` 133 | defaults write -g NSTextShowsControlCharacters -bool true 134 | defaults write com.apple.finder DisableAllAnimations -bool true 135 | # Display full POSIX path as Finder window title 136 | defaults write com.apple.finder _FXShowPosixPathInTitle -bool true 137 | # Avoid creating .DS_Store files on network volumes 138 | defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true 139 | # Set key-repeat rate. But not too high: on macOS 10.13 KeyRepeat=0 is insane. 140 | defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false 141 | defaults write NSGlobalDomain KeyRepeat -int 2 142 | defaults write -g KeyRepeat -int 2 143 | defaults write -g InitialKeyRepeat -int 15 144 | fi 145 | fi 146 | 147 | ghpr() { 148 | local sed_cmd=$( [ "$(uname)" = Darwin ] && echo 'sed -E' || echo 'sed -r' ) 149 | local PR=${1} 150 | local REPO_SLUG="$(git config --get remote.upstream.url \ 151 | | sed 's/^.*github.com[\/:]\(.*\)\.git/\1/')" 152 | local req_url="https://api.github.com/repos/${REPO_SLUG}/pulls/${PR}" 153 | local PR_TITLE="$(curl -Ss "$req_url" \ 154 | | grep '"title"' \ 155 | | $sed_cmd 's/.*(\[(RFC|RDY)\]) *(.*)../\3/')" 156 | # ^ Trailing ", in JSON response. 157 | 158 | [ -z "$PR_TITLE" ] && { printf "error. request: $req_url\n response: $(curl -Ss $req_url)\n"; return 1; } 159 | 160 | git checkout upstream/master \ 161 | && git merge --no-commit --no-ff -m "Merge #${PR} '${PR_TITLE}'" refs/pull/upstream/${PR} 162 | } 163 | 164 | ghco() { 165 | git checkout refs/pull/upstream/${1} || git checkout refs/pull/origin/${1} 166 | } 167 | 168 | ghrebase1() { 169 | local PR=${1} 170 | local sed_cmd=$( [ "$(uname)" = Darwin ] && echo 'sed -E' || echo 'sed -r' ) 171 | 172 | git checkout --quiet refs/pull/upstream/${PR} \ 173 | && git rebase upstream/master \ 174 | && git checkout upstream/master \ 175 | && git merge --ff-only - \ 176 | && git commit --amend -m "$(git log -1 --pretty=format:"%B" \ 177 | | $sed_cmd "1 s/^(.*)\$/\\1 #${PR}/g")" \ 178 | && git log --oneline --graph --decorate -n 5 179 | } 180 | 181 | p() { 182 | if [ "$(uname)" = Darwin ] ; then 183 | ps -e "$@" -o state,pid,rss,vsz,command 184 | else 185 | ps -e "$@" -o state,pidns,pid,rss,vsz,command 186 | fi 187 | } 188 | 189 | _Z_DATA="$HOME/.config/z/z" 190 | . ~/bin/z.sh 191 | 192 | [ -f ~/.bashrc.local ] && source ~/.bashrc.local 193 | 194 | -------------------------------------------------------------------------------- /.config/bottom/bottom.toml: -------------------------------------------------------------------------------- 1 | # config docs: 2 | # https://bottom.pages.dev/stable/configuration/config-file/layout/ 3 | # default config: 4 | # https://github.com/ClementTsang/bottom/blob/main/sample_configs/default_config.toml 5 | 6 | # Layout - layouts follow a pattern like this: 7 | # [[row]] represents a row in the application. 8 | # [[row.child]] represents either a widget or a column. 9 | # [[row.child.child]] represents a widget. 10 | # 11 | # Widget `type` must be one of ["cpu", "mem", "proc", "net", "temp", "disk", "empty"]. 12 | # Layout components have a `ratio` (defaults to 1). 13 | # The default widget layout: 14 | [[row]] 15 | ratio=10 16 | [[row.child]] 17 | type="cpu" 18 | [[row.child]] 19 | type="mem" 20 | [[row.child]] 21 | type="net" 22 | [[row]] 23 | ratio=90 24 | [[row.child]] 25 | type="proc" 26 | default=true 27 | 28 | [flags] 29 | avg_cpu = true 30 | 31 | temperature_type = "c" 32 | 33 | rate = 1000 34 | cpu_left_legend = true 35 | current_usage = true 36 | # group_processes = true 37 | case_sensitive = false 38 | whole_word = false 39 | regex = true 40 | show_full_command = true 41 | default_time_value = 60000 42 | process_command = true 43 | process_per_cpu = true 44 | # tree = true 45 | 46 | # columns = ["PID", "Name", "CPU%", "Mem%", "R/s", "W/s", "T.Read", "T.Write", "User", "State", "GMem%", "GPU%"] 47 | [processes] 48 | columns = [ 49 | "pid", 50 | "state", 51 | # "user", 52 | "cpu%", 53 | "mem%", 54 | # "read", 55 | # "write", 56 | "name", 57 | ] 58 | -------------------------------------------------------------------------------- /.config/ghostty/config: -------------------------------------------------------------------------------- 1 | macos-option-as-alt = true 2 | 3 | background = #000000 4 | foreground = #ffffff 5 | 6 | font-family = Menlo Regular 7 | font-size = 14 8 | -------------------------------------------------------------------------------- /.config/htop/htoprc: -------------------------------------------------------------------------------- 1 | # Beware! This file is rewritten by htop when settings are changed in the interface. 2 | # The parser is also very primitive, and not human-friendly. 3 | htop_version=3.3.0 4 | config_reader_min_version=3 5 | fields=20 0 48 17 18 38 39 2 46 47 49 1 6 | hide_kernel_threads=1 7 | hide_userland_threads=0 8 | hide_running_in_container=0 9 | shadow_other_users=0 10 | show_thread_names=0 11 | show_program_path=0 12 | highlight_base_name=1 13 | highlight_deleted_exe=1 14 | shadow_distribution_path_prefix=0 15 | highlight_megabytes=1 16 | highlight_threads=1 17 | highlight_changes=0 18 | highlight_changes_delay_secs=5 19 | find_comm_in_cmdline=1 20 | strip_exe_from_cmdline=1 21 | show_merged_command=1 22 | header_margin=1 23 | screen_tabs=1 24 | detailed_cpu_time=0 25 | cpu_count_from_one=1 26 | show_cpu_usage=0 27 | show_cpu_frequency=0 28 | update_process_names=0 29 | account_guest_in_cpu_meter=0 30 | color_scheme=0 31 | enable_mouse=0 32 | delay=15 33 | hide_function_bar=0 34 | header_layout=two_50_50 35 | column_meters_0=AllCPUs4 MemorySwap 36 | column_meter_modes_0=1 1 37 | column_meters_1=DiskIO NetworkIO FileDescriptors 38 | column_meter_modes_1=2 2 2 39 | tree_view=1 40 | sort_key=46 41 | tree_sort_key=46 42 | sort_direction=-1 43 | tree_sort_direction=-1 44 | tree_view_always_by_pid=0 45 | all_branches_collapsed=0 46 | screen:Main=STARTTIME PID USER PRIORITY NICE M_VIRT M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command 47 | .sort_key=PERCENT_CPU 48 | .tree_sort_key=PERCENT_CPU 49 | .tree_view_always_by_pid=0 50 | .tree_view=1 51 | .sort_direction=-1 52 | .tree_sort_direction=-1 53 | .all_branches_collapsed=0 54 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/c.vim: -------------------------------------------------------------------------------- 1 | setlocal textwidth=100 2 | setlocal comments-=:// comments+=:///,:// 3 | 4 | nnoremap [[ [[3 5 | 6 | " indent after parens, etc. 7 | setlocal cinoptions=>s,e0,n0,f0,{0,}0,^0,:s,=s,l1,b0 " Control structures 8 | setlocal cinoptions+=ps,t0 " function declarations 9 | setlocal cinoptions+=c3,C1,/0 " Comments 10 | setlocal cinoptions+=+s " Continuation lines 11 | setlocal cinoptions+=(0,u0,U1,w1,W0,m0,M0 " Parens and arguments 12 | setlocal cinoptions+=)20,*30 " Search range 13 | 14 | if '' ==# findfile('.clang-format', ';') 15 | setlocal formatprg=clang-format\ -style=LLVM 16 | else 17 | setlocal formatprg=clang-format\ -style=file 18 | endif 19 | 20 | if fnamemodify(@%, ':p') =~# 'neovim' 21 | let b:printf_pattern = 'ILOG("%d", %s);' 22 | nnoremap log oELOG(""); 23 | endif 24 | 25 | command! InsertCBreak norm! i#include raise(SIGINT);  26 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/clojure.vim: -------------------------------------------------------------------------------- 1 | nnoremap yxx :.,.Eval 2 | nnoremap yxal :%Eval 3 | nnoremap yxiw :Eval 4 | xnoremap :Eval 5 | " eval-last-sexp 6 | inoremap "9y%:Eval! 9%a 7 | 8 | " TODO: http://stackoverflow.com/a/17830491/152142 9 | " func! s:fmt(line1, line2) abort 10 | " call append(lclose, split(dump, "\n")) 11 | " silent exe lopen.','.lclose.'delete _' 12 | " endf 13 | " command! -buffer -range=% Format :call s:fmt(, ) 14 | 15 | xmap af (sexp_outer_list) 16 | omap af (sexp_outer_list) 17 | xmap if (sexp_inner_list) 18 | omap if (sexp_inner_list) 19 | xmap aF (sexp_outer_top_list) 20 | omap aF (sexp_outer_top_list) 21 | xmap iF (sexp_inner_top_list) 22 | omap iF (sexp_inner_top_list) 23 | xmap ae (sexp_outer_element) 24 | omap ae (sexp_outer_element) 25 | xmap ie (sexp_inner_element) 26 | omap ie (sexp_inner_element) 27 | nmap ( (sexp_move_to_prev_bracket) 28 | xmap ( (sexp_move_to_prev_bracket) 29 | omap ( (sexp_move_to_prev_bracket) 30 | nmap ) (sexp_move_to_next_bracket) 31 | xmap ) (sexp_move_to_next_bracket) 32 | omap ) (sexp_move_to_next_bracket) 33 | nmap (sexp_move_to_prev_element_head) 34 | xmap (sexp_move_to_prev_element_head) 35 | omap (sexp_move_to_prev_element_head) 36 | nmap (sexp_move_to_next_element_head) 37 | xmap (sexp_move_to_next_element_head) 38 | omap (sexp_move_to_next_element_head) 39 | nmap [[ (sexp_move_to_prev_top_element) 40 | xmap [[ (sexp_move_to_prev_top_element) 41 | omap [[ (sexp_move_to_prev_top_element) 42 | nmap ]] (sexp_move_to_next_top_element) 43 | xmap ]] (sexp_move_to_next_top_element) 44 | omap ]] (sexp_move_to_next_top_element) 45 | nmap == (sexp_indent) 46 | nmap =- (sexp_indent_top) 47 | nmap crf( (sexp_round_head_wrap_list) 48 | nmap crf) (sexp_round_tail_wrap_list) 49 | nmap crf[ (sexp_square_head_wrap_list) 50 | nmap crf] (sexp_square_tail_wrap_list) 51 | nmap crf{ (sexp_curly_head_wrap_list) 52 | nmap crf} (sexp_curly_tail_wrap_list) 53 | nmap cr( (sexp_round_head_wrap_element) 54 | nmap cr) (sexp_round_tail_wrap_element) 55 | nmap cr[ (sexp_square_head_wrap_element) 56 | nmap cr] (sexp_square_tail_wrap_element) 57 | nmap cr{ (sexp_curly_head_wrap_element) 58 | nmap cr} (sexp_curly_tail_wrap_element) 59 | nmap (sexp_insert_at_list_head) 60 | nmap >I (sexp_insert_at_list_tail) 61 | nmap gs (sexp_splice_list) 62 | nmap dof (sexp_raise_list) 63 | nmap doe (sexp_raise_element) 64 | nmap cx< (sexp_swap_list_backward) 65 | nmap cx> (sexp_swap_list_forward) 66 | nmap cxE (sexp_swap_element_backward) 67 | nmap cxe (sexp_swap_element_forward) 68 | nmap gsB (sexp_emit_head_element) 69 | nmap gsb (sexp_emit_tail_element) 70 | nmap gsS (sexp_capture_prev_element) 71 | nmap gss (sexp_capture_next_element) 72 | 73 | imap (sexp_insert_backspace) 74 | imap " (sexp_insert_double_quote) 75 | imap ( (sexp_insert_opening_round) 76 | imap ) (sexp_insert_closing_round) 77 | imap [ (sexp_insert_opening_square) 78 | imap ] (sexp_insert_closing_square) 79 | imap { (sexp_insert_opening_curly) 80 | imap } (sexp_insert_closing_curly) 81 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/cs.vim: -------------------------------------------------------------------------------- 1 | " %VS120COMNTOOLS% => C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\ 2 | " $COMSPEC /k $VS120COMNTOOLS."vsvars32.bat" 3 | 4 | setlocal tabstop=4 shiftwidth=4 copyindent 5 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/gitcommit.vim: -------------------------------------------------------------------------------- 1 | let b:editorconfig = v:false 2 | 3 | inoreabbrev co Co-authored-by: 4 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/go.vim: -------------------------------------------------------------------------------- 1 | inoremap err if err != nil {log.Fatal(err)} 2 | 3 | for s:gopath in split($GOPATH, ':') 4 | "set up Golint https://github.com/golang/lint 5 | if isdirectory(s:gopath."/src/github.com/golang/lint/misc/vim") 6 | exe 'set runtimepath+='.s:gopath.'/src/github.com/golang/lint/misc/vim' 7 | autocmd BufWritePost,FileWritePost *.go execute 'Lint' | cwindow 8 | break 9 | endif 10 | endfor 11 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/help.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[[set iskeyword&]] 2 | 3 | -- execute/evaluate 4 | vim.cmd[[ 5 | nnoremap yxal :Runtime 6 | xnoremap :keeppatterns '<,'>g/^/exe getline('.') 7 | 8 | " Justify a line, using cursor position as the midpoint. 9 | nnoremap :let g:old_et=&l:etsetlocal et 10 | \i:rightk 11 | \:left0 12 | \:keeppatterns norm! dv/\ze\s*$ 13 | \jR"0k"_dd 14 | \:let &l:et=g:old_etunlet g:old_et.retab! 15 | ]] 16 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/java.vim: -------------------------------------------------------------------------------- 1 | autocmd FileType java setlocal tabstop=4 shiftwidth=4 copyindent nolist 2 | 3 | if fnamemodify(@%, ':p') =~# 'hw-dashboard' 4 | nnoremap log oLog.info("XXX: "); 5 | endif 6 | 7 | let b:printf_pattern = 'System.out.println(String.format("%s", %s));' 8 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/js.vim: -------------------------------------------------------------------------------- 1 | command! -buffer -range=% Format let b:winview = winsaveview() | execute . "," . . "!js-beautify -f - -j -B -s " . &shiftwidth | call winrestview(b:winview) 2 | 3 | let b:printf_pattern = 'console.log(`xxx %s=${JSON.stringify(%s,null,2)}`);' 4 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/lua.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[[ 2 | " From https://github.com/tpope/tpope/blob/master/.vimrc 3 | setlocal includeexpr=substitute(v:fname,'\\.','/','g').'.lua' 4 | 5 | setlocal comments-=:-- comments+=:---,:-- 6 | let b:printf_pattern = 'print(string.format("%s", %s))' 7 | 8 | nnoremap yxal :luafile % 9 | 10 | inoreabbrev lo local 11 | inoreabbrev lf local function() 12 | inoreabbrev fu function() end 13 | inoreabbrev fo (''):format() 14 | 15 | ]] 16 | 17 | vim.keymap.set('n', 'log', function() 18 | vim.api.nvim_paste([[ 19 | local function flog(o, s) 20 | local ok, _inspect = pcall(require, 'inspect') 21 | _inspect = ok and _inspect or tostring 22 | local f = assert(io.open('dbg.txt','wa+')) 23 | f:write(('xxx: %s\n'):format(_inspect(s))) 24 | f:flush() 25 | f:close() 26 | end 27 | ]], false, -1) 28 | end, { buffer = true }) 29 | 30 | vim.keymap.set('n', 'dbg', function() 31 | vim.api.nvim_paste([[ 32 | local function dbg_this(o, s) 33 | if o and ( 34 | (o.find and o:find(s)) 35 | or (o.name and o.name:find(s)) 36 | or (o.keyset_name and o.keyset_name:find(s))) 37 | then 38 | error(vim.inspect(o)) 39 | end 40 | end 41 | ]], false, -1) 42 | end, { buffer = true }) 43 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/markdown.vim: -------------------------------------------------------------------------------- 1 | setlocal shiftwidth=4 2 | 3 | " Presentation-mode: Nvim 0.10 URL tokens + treesitter! 4 | "nnoremap exe 'setlocal ' (&conceallevel ? 'conceallevel=0 concealcursor=' : 'conceallevel=2 concealcursor=nv') 5 | nnoremap :packadd render-markdown.nvimRenderMarkdown toggle 6 | 7 | " URL/footnote macro 8 | nnoremap fn "fyiWmfGo[f]: `fyiwi[ebEa]b 9 | 10 | " Github "collapse" markup. 11 | nnoremap det odetails>summary>xxx/summary>/details> 12 | 13 | inoreabbrev h1 ================================================================================ 14 | inoreabbrev h2 -------------------------------------------------------------------------------- 15 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/ps1.vim: -------------------------------------------------------------------------------- 1 | " %VS120COMNTOOLS% => C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\ 2 | " $COMSPEC /k $VS120COMNTOOLS."vsvars32.bat" 3 | 4 | "open current file in powershell ISE 5 | nnoremap yxG :Start powershell_ise.exe % 6 | 7 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/python.vim: -------------------------------------------------------------------------------- 1 | setlocal copyindent 2 | setlocal formatprg=python3\ -m\ black\ --quiet\ --skip-string-normalization\ - 3 | 4 | if 0 != 0+search('import logging', 'nw', 0, 100) 5 | let b:printf_pattern = "logging.info('%{}'.format(%s))" 6 | else 7 | let b:printf_pattern = "print('%{}'.format(%s))" 8 | endif 9 | 10 | " setlocal omnifunc=lsp#complete 11 | " setlocal keywordprg=:LspHover 12 | " nnoremap :LspDefinition 13 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/sh.vim: -------------------------------------------------------------------------------- 1 | setlocal makeprg=shellcheck\ --shell=bash\ % 2 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/sql.vim: -------------------------------------------------------------------------------- 1 | setlocal commentstring=--\ %s 2 | 3 | nnoremap yxal :%DBExecRangeSQL 4 | nnoremap yxx :.,.DBExecRangeSQL 5 | xmap DBExecVisualSQL 6 | 7 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/text.vim: -------------------------------------------------------------------------------- 1 | inoreabbrev ps Problem:Solution: 2 | if &filetype !~# 'fugitive\|git*' 3 | setlocal textwidth=80 4 | endif 5 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/typescript.vim: -------------------------------------------------------------------------------- 1 | exe 'source' fnamemodify(expand(''), ':h').'/js.vim' 2 | -------------------------------------------------------------------------------- /.config/nvim/after/ftplugin/vim.vim: -------------------------------------------------------------------------------- 1 | lua vim.treesitter.start() 2 | 3 | " execute/evaluate 4 | nnoremap yxal :source % 5 | nnoremap yxx :keeppatterns .g/^/exe getline('.') 6 | xnoremap :keeppatterns '<,'>g/^/exe getline('.') 7 | -------------------------------------------------------------------------------- /.config/nvim/after/indent/java.vim: -------------------------------------------------------------------------------- 1 | setlocal cindent 2 | setlocal indentexpr= 3 | 4 | " indent after parens, etc. 5 | setlocal cinoptions=>s,e0,n0,f0,{0,}0,^0,:s,=s,l1,b0 " Control structures 6 | setlocal cinoptions+=ps,t0 " function declarations 7 | setlocal cinoptions+=c3,C1,/0 " Comments 8 | setlocal cinoptions+=+s " Continuation lines 9 | setlocal cinoptions+=(0,u0,U1,w1,W0,m0,M0 " Parens and arguments 10 | setlocal cinoptions+=)20,*30 " Search range 11 | setlocal cinoptions+=j1 " Java anonymous classes 12 | -------------------------------------------------------------------------------- /.config/nvim/after/indent/lua.vim: -------------------------------------------------------------------------------- 1 | setlocal copyindent indentexpr= 2 | -------------------------------------------------------------------------------- /.config/nvim/doc/xwiki.txt: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | XWiki syntax 2.1 *xwiki-syntax* 3 | 4 | From https://www.xwiki.org/xwiki/bin/view/Documentation/UserGuide/Features/XWikiSyntax/ 5 | 6 | ============================================================================== 7 | EDITING 8 | 9 | ### Paragraphs 10 | 11 | Paragraphs are text elements separated by 2 or more new lines. 12 | 13 | Paragraph on multiple lines: > 14 | 15 | Paragraph on 16 | multiple lines 17 | 18 | Parametrized paragraph: > 19 | 20 | (% style="text-align:center;color:blue" %) 21 | Centered and blue paragraph 22 | 23 | Inline styling: > 24 | 25 | paragraph with (% style="color:red" %)red text(%%) inside 26 | 27 | ============================================================================== 28 | HEADINGS 29 | 30 | Standard headings: > 31 | 32 | = level 1 = 33 | == level 2 == 34 | === level 3 === 35 | ==== level 4 ==== 36 | ===== level 5 ===== 37 | ====== level 6 ====== 38 | 39 | 40 | ============================================================================== 41 | TEXT FORMATTING 42 | 43 | General text formatting: > 44 | 45 | **bold** 46 | __underline__ 47 | //italic// 48 | --strikeout-- 49 | ##monospace## 50 | ^^superscript^^ 51 | ,,subscript,, 52 | 53 | Horizontal Line: must be 4 or more dashes. > 54 | 55 | ---- 56 | 57 | Parametrized horizontal line: > 58 | 59 | (% style="border-color:blue" %) 60 | ---- 61 | 62 | 63 | LITERAL 64 | 65 | Use "{{{…}}}" for verbatim (aka "preformatted", literal, will not be parsed): > 66 | 67 | {{{**[[verbatim]]**}}} content 68 | 69 | {{{ 70 | multiline 71 | **verbatim** 72 | content 73 | }}} 74 | 75 | 76 | outputs exactly > 77 | 78 | **[[verbatim]]** content 79 | 80 | multiline 81 | **verbatim** 82 | content 83 | 84 | 85 | BLOCKQUOTE 86 | 87 | Quotations (blockquote): > 88 | 89 | > quote ... 90 | >> nested quote ... 91 | no quote. 92 | 93 | 94 | ============================================================================== 95 | LISTS 96 | 97 | Bulleted list: > 98 | 99 | * item 1 100 | ** item 2 101 | *** item 3 102 | * item 4 103 | 104 | looks like... > 105 | 106 | * item 1 107 | * item 2 108 | * item 3 109 | * item 4 110 | 111 | Numbered list: > 112 | 113 | 1. item 1 114 | 11. item 2 115 | 111. item 3 116 | 1. item 4 117 | 118 | looks like... > 119 | 120 | 1. item 1 121 | 1. item 2 122 | 1. item 3 123 | 2. item 4 124 | 125 | 126 | Definition List: > 127 | 128 | ; term 1 129 | : definition 1 130 | :; term 2 (nested) 131 | :: definition 2 132 | 133 | looks like... > 134 | 135 | **term 1** 136 | definition 1 137 | **term 2 (nested)** 138 | definition 2 139 | 140 | 141 | 142 | ============================================================================== 143 | LINKS 144 | 145 | The full format of a link is: > 146 | 147 | [label>>] (resource) [||parameters] 148 | 149 | Absolute link to page PageB located in PageA: > 150 | 151 | [[PageA.PageB]] 152 | 153 | => [PageB](…) 154 | 155 | Relative link to page PageA from the current page: > 156 | 157 | [[PageA]] or [[.PageA]] 158 | 159 | => [PageA](…) 160 | 161 | Relative link to page PageB in PageA from the current page: > 162 | 163 | [[.PageA.PageB]] 164 | 165 | => [PageB](#) 166 | 167 | Link with a label (XWiki Syntax is supported inside link labels): > 168 | 169 | [[label>>PageA]] 170 | 171 | => [label](…) 172 | 173 | Link with wiki syntax in the label: > 174 | 175 | [[**bold label**>>PageA]] 176 | 177 | => [**bold label**](…) 178 | 179 | Link on an image: > 180 | 181 | [[image:PageA@img.png>>PageA]] 182 | 183 | => [![img.png](/xwiki/bin/download/XWiki/XWikiSyntaxLinks/img.png?rev=1.1)](…) 184 | 185 | Absolute link to page PageB located in PageA in wiki WikiA: > 186 | 187 | [[WikiA:PageA.PageB]] 188 | 189 | => [PageB](…) 190 | 191 | Link that opens in a new window: > 192 | 193 | [[PageA||target="_blank"]] 194 | 195 | => [PageA](…) 196 | 197 | Implicit link to a URL: > 198 | 199 | This is a URL: https://xwiki.org 200 | 201 | Explicit link to a URL: > 202 | 203 | [[https://xwiki.org]] 204 | 205 | Explicit link to a URL with a label: > 206 | 207 | [[XWiki>>https://xwiki.org]] 208 | 209 | Link to an Anchor in a page: > 210 | 211 | [[PageA.PageB||anchor="anchor"]] 212 | 213 | ...anchor generated from a heading: 214 | [[PageA.PageB||anchor="HMyheading"]] 215 | 216 | ...anchor in the current page: 217 | [[label>>||anchor="anchor"]] 218 | 219 | Note: When you add a Heading, an anchor named "H" followed by the heading 220 | title with only alpha characters is created. For example, for a Heading named 221 | "My heading", the generated anchor will be "HMyheading". 222 | 223 | 224 | 225 | ============================================================================== 226 | TABLES 227 | 228 | Standard table: > 229 | 230 | |=Title 1|=Title 2 231 | |Word 1|Word 2 232 | 233 | or 234 | 235 | !=Title 1!=Title 2 236 | !!Word 1!!Word 2 237 | 238 | Parametrized table: > 239 | 240 | (% style="background-color:red;text-align:center" %) 241 | |=Title 1|=(% style="background-color:yellow" %)Title 2 242 | |Word 1|Word 2 243 | 244 | Filterable Sortable table: > 245 | 246 | {{velocity}} 247 | $xwiki.ssfx.use("js/xwiki/table/table.css") 248 | $xwiki.jsfx.use("js/xwiki/table/tablefilterNsort.js", true) 249 | {{/velocity}} 250 | 251 | (% class="grid sortable filterable doOddEven" id="tableid" %) 252 | (% class="sortHeader" %)|=Title 1|=Title 2 253 | |Cell 11|Cell 12 254 | |Cell 21|Cell 22 255 | 256 | 257 | ============================================================================== 258 | IMAGES 259 | 260 | The format of an image is either: > 261 | 262 | image: (reference) 263 | 264 | or 265 | 266 | [[{caption>>}image: (reference) {||parameters}]] 267 | 268 | Image from attachment on current page: > 269 | 270 | image:img.png 271 | 272 | => ![img.png](/xwiki/bin/download/XWiki/XWikiSyntaxImages/img.png?rev=1.2) 273 | 274 | ...from attachment on another page: 275 | image:PageA.PageB@img.png 276 | 277 | Image with parameters: > 278 | 279 | [[image:img.png||width="25" height="25"]] 280 | 281 | => ![img.png](/xwiki/bin/download/XWiki/XWikiSyntaxImages/img.png?width=25&height=25&rev=1.2) 282 | 283 | Image with caption (can nest XWiki markup): > 284 | 285 | [[~[~[XWiki~>~>https://www.xwiki.org~]~] supports captions.>>image:img.png]] 286 | 287 | => ![img.png](/xwiki/bin/download/XWiki/XWikiSyntaxImages/img.png?rev=1.2) 288 | 289 | Images located at URL: > 290 | 291 | image:https://some/url/img.png 292 | 293 | => ![img.png](/xwiki/bin/download/XWiki/XWikiSyntaxImages/img.png?rev=1.2) 294 | 295 | Prepackaged Icons: > 296 | 297 | image:icon:accept 298 | 299 | => ![accept](/xwiki/resources/icons/silk/accept.png?cache-version=1666345755000) 300 | 301 | 302 | 303 | ============================================================================== 304 | ADVANCED 305 | 306 | Groups: Use groups "(((…)))" to inline a document into a list item, table 307 | cell, etc. This allows for example to insert complex elements or style. 308 | Supports nesting: a Group can contain another Group, etc. 309 | 310 | Example: inlining group into a table cell: > 311 | 312 | |=Header 1|=Header 2|=Header 3 313 | |Cell One|((( 314 | = Embedded document = 315 | * Embedded list item one 316 | * Embedded list item two 317 | ** sub-item 1 318 | ** sub-item 2 319 | ))) | Cell Three 320 | Next paragraph in the top-level document 321 | 322 |   323 | 324 | The "~" character escapes XWiki syntax: > 325 | 326 | not ~[~[link~]~] 327 | 328 | Use "~~" to enter a literal "~" character. 329 | 330 | 331 | MACROS 332 | 333 | There is only one kind of macro in XWiki Syntax 2.1, which is called by the 334 | syntax: > 335 | 336 | {{macroname param1="value1" ... paramN="valueN"}}...{{/macroname}} 337 | 338 | For macros without content: > 339 | 340 | {{macroname param1="value1" ... paramN="valueN"/}} 341 | 342 | Use the {{html}} macro to enter HTML: > 343 | 344 | {{html}}HTML{{/html}} 345 | 346 | 347 | 348 | 349 | vim:tw=78:sw=4:ts=8:ft=help:norl: 350 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/bufdelete.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[[ 2 | func! s:compare_numbers(n1, n2) abort 3 | return a:n1 == a:n2 ? 0 : a:n1 > a:n2 ? 1 : -1 4 | endfunc 5 | 6 | func! s:compare_bufs(b1, b2) abort 7 | let b1_visible = index(tabpagebuflist(), a:b1) >= 0 8 | let b2_visible = index(tabpagebuflist(), a:b2) >= 0 9 | " - sort by buffer number (descending) 10 | " - prefer loaded, NON-visible buffers 11 | if bufloaded(a:b1) 12 | if bufloaded(a:b2) 13 | if b1_visible == b2_visible 14 | return s:compare_numbers(a:b1, a:b2) 15 | endif 16 | return s:compare_numbers(b2_visible, b1_visible) 17 | endif 18 | return 1 19 | endif 20 | return !bufloaded(a:b2) ? s:compare_numbers(a:b1, a:b2) : 1 21 | endf 22 | 23 | func! s:buf_find_displayed_bufs() abort " find all buffers displayed in any window, any tab. 24 | let bufs = [] 25 | for i in range(1, tabpagenr('$')) 26 | call extend(bufs, tabpagebuflist(i)) 27 | endfor 28 | return bufs 29 | endf 30 | 31 | func! s:buf_is_valid(bnr) abort 32 | " Exclude: 33 | " - current 34 | " - unlisted 35 | " - buffers marked as 'readonly' AND 'modified' (netrw brain-damage) 36 | " Include: normal buffers; 'help' buffers 37 | return buflisted(a:bnr) 38 | \ && ("" ==# getbufvar(a:bnr, "&buftype") || "help" ==# getbufvar(a:bnr, "&buftype")) 39 | \ && a:bnr != bufnr("%") 40 | \ && -1 == index(tabpagebuflist(), a:bnr) 41 | \ && !(getbufvar(a:bnr, "&modified") && getbufvar(a:bnr, "&readonly")) 42 | endfunc 43 | 44 | " Gets the first empty, unchanged buffer not in the current tabpage. 45 | func! s:buf_find_unused() abort 46 | for i in range(1, bufnr('$')) 47 | if bufexists(i) 48 | \&& -1 == index(tabpagebuflist(), i) 49 | \&& nvim_buf_get_changedtick(i) <= 2 50 | \&& buflisted(i) 51 | \&& bufname(i) ==# '' 52 | \&& getbufvar(i, '&buftype') ==# '' 53 | return i 54 | endif 55 | endfor 56 | return 0 57 | endf 58 | 59 | " Switches to a new (empty, unchanged) buffer or creates a new one. 60 | func! s:buf_new() abort 61 | let newbuf = s:buf_find_unused() 62 | if newbuf == 0 63 | enew 64 | else 65 | exe 'buffer' newbuf 66 | endif 67 | endf 68 | 69 | func! s:buf_find_valid_next_bufs() abort 70 | let validbufs = filter(range(1, bufnr('$')), 'buf_is_valid(v:val)') 71 | call sort(validbufs, 'compare_bufs') 72 | return validbufs 73 | endf 74 | 75 | func! s:buf_switch_to_altbuff() abort 76 | " change to alternate buffer if it is not the current buffer (yes, that can happen) 77 | if buflisted(bufnr("#")) && bufnr("#") != bufnr("%") 78 | buffer # 79 | return 1 80 | endif 81 | 82 | " change to newest valid buffer 83 | let lastbnr = bufnr('$') 84 | if s:buf_is_valid(lastbnr) 85 | exe 'buffer '.lastbnr 86 | return 1 87 | endif 88 | 89 | " change to any valid buffer 90 | let validbufs = s:buf_find_valid_next_bufs() 91 | if len(validbufs) > 0 92 | exe 'buffer '.validbufs[0] 93 | return 1 94 | endif 95 | 96 | return 0 97 | endf 98 | 99 | " close the current buffer with a vengeance 100 | " BDSN: Buffer DiScipliNe 101 | func! s:buf_kill(mercy) abort 102 | let origbuf = bufnr("%") 103 | let origbufname = bufname(origbuf) 104 | if a:mercy && &modified 105 | echom 'buffer has unsaved changes (use "[count]ZB" to discard changes)' 106 | return 107 | endif 108 | 109 | if !s:buf_switch_to_altbuff() 110 | " No alternate buffer, create an empty buffer. 111 | " :bdelete still closes other windows displaying the buffer... 112 | call s:buf_new() 113 | endif 114 | 115 | " remove the buffer filename (if any) from the args list, else it might come back in the next session. 116 | if !empty(origbufname) 117 | silent! exe 'argdelete '.origbufname 118 | endif 119 | " Unload the buffer state and remove it from the buffer list. 120 | if buflisted(origbuf) || bufloaded(origbuf) 121 | exe 'bdelete! '.origbuf 122 | endif 123 | endf 124 | 125 | " manage buffers 126 | nnoremap ZB ':call buf_kill('. !v:count .')' 127 | nnoremap :call buf_new() 128 | ]] 129 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/ctrl_s_shell.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[[ 2 | " :shell 3 | " 4 | " Creates a global default :shell with maximum 'scrollback'. 5 | func! s:ctrl_s(cnt, here) abort 6 | let g:term_shell = get(g:, 'term_shell', { 'prevwid': win_getid() }) 7 | let b = bufnr(':shell') 8 | 9 | if bufexists(b) && a:here " Edit the :shell buffer in this window. 10 | exe 'buffer' b 11 | setlocal nobuflisted 12 | let g:term_shell.prevwid = win_getid() 13 | return 14 | endif 15 | 16 | " 17 | " Return to previous window, maybe close the :shell tabpage. 18 | " 19 | if bufnr('%') == b 20 | let tab = tabpagenr() 21 | let term_prevwid = win_getid() 22 | if !win_gotoid(g:term_shell.prevwid) 23 | wincmd p 24 | endif 25 | if tabpagewinnr(tab, '$') == 1 && tabpagenr() != tab 26 | " Close the :shell tabpage if it's the only window in the tabpage. 27 | exe 'tabclose' tab 28 | endif 29 | if bufnr('%') == b 30 | " Edge-case: :shell buffer showing in multiple windows in curtab. 31 | " Find a non-:shell window in curtab. 32 | let bufs = filter(tabpagebuflist(), 'v:val != '.b) 33 | if len(bufs) > 0 34 | exe bufwinnr(bufs[0]).'wincmd w' 35 | else 36 | " Last resort: can happen if :mksession restores an old :shell. 37 | " tabprevious 38 | if &buftype !=# 'terminal' && getline(1) == '' && line('$') == 1 39 | " XXX: cleanup stale, empty :shell buffer (caused by :mksession). 40 | bwipeout! % 41 | " Try again. 42 | call s:ctrl_s(a:cnt, a:here) 43 | end 44 | return 45 | endif 46 | endif 47 | let g:term_shell.prevwid = term_prevwid 48 | 49 | return 50 | endif 51 | 52 | " 53 | " Go to existing :shell or create a new one. 54 | " 55 | let curwinid = win_getid() 56 | if a:cnt == 0 && bufexists(b) && winbufnr(g:term_shell.prevwid) == b 57 | " Go to :shell displayed in the previous window. 58 | call win_gotoid(g:term_shell.prevwid) 59 | elseif bufexists(b) 60 | " Go to existing :shell. 61 | 62 | let w = bufwinid(b) 63 | if a:cnt == 0 && w > 0 64 | " Found in current tabpage. 65 | call win_gotoid(w) 66 | else 67 | " Not in current tabpage. 68 | let ws = win_findbuf(b) 69 | if a:cnt == 0 && !empty(ws) 70 | " Found in another tabpage. 71 | call win_gotoid(ws[0]) 72 | else 73 | " Not in any existing window; open a tabpage (or split-window if [count] was given). 74 | exe ((a:cnt == 0) ? 'tab split' : a:cnt.'split') 75 | exe 'buffer' b 76 | endif 77 | endif 78 | 79 | if &buftype !=# 'terminal' && getline(1) == '' && line('$') == 1 80 | call win_gotoid(g:term_shell.prevwid) 81 | " XXX: cleanup stale, empty :shell buffer (caused by :mksession). 82 | exe 'bwipeout!' b 83 | " Try again. 84 | call s:ctrl_s(a:cnt, a:here) 85 | end 86 | else 87 | " Create new :shell. 88 | 89 | let origbuf = bufnr('%') 90 | if !a:here 91 | exe ((a:cnt == 0) ? 'tab split' : a:cnt.'split') 92 | endif 93 | terminal 94 | setlocal scrollback=-1 95 | file :shell 96 | " XXX: original term:// buffer hangs around after :file ... 97 | bwipeout! # 98 | autocmd VimLeavePre * bwipeout! ^:shell$ 99 | " Set alternate buffer to something intuitive. 100 | let @# = origbuf 101 | tnoremap :call ctrl_s(0, v:false) 102 | endif 103 | 104 | let g:term_shell.prevwid = curwinid 105 | setlocal nobuflisted 106 | endfunc 107 | nnoremap :call ctrl_s(v:count, v:false) 108 | nnoremap ' :call ctrl_s(v:count, v:true) 109 | ]] 110 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/fug.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[=[ 2 | augroup config_fug 3 | autocmd! 4 | " Defaults for text-like buffers. 5 | autocmd VimEnter,BufNew * autocmd InsertEnter ++once if &filetype ==# '' | exe 'runtime! after/ftplugin/text.vim' | endif 6 | autocmd FileType markdown,gitcommit runtime! after/ftplugin/text.vim 7 | 8 | autocmd FileType gitconfig setlocal commentstring=#\ %s 9 | " For the ":G log" buffer opened by the "UL" mapping. 10 | autocmd FileType git if get(b:, 'fugitive_type') ==# 'temp' 11 | \ | exe 'nnoremap 0j:call feedkeys("p")' 12 | \ | exe 'nnoremap 0k:call feedkeys("p")' 13 | \ | exe 'nnoremap q q' 14 | \ | match Comment / \S\+ ([^)]\+)$/ 15 | \ | endif 16 | function! s:setup_gitstatus() abort 17 | unmap U 18 | endfunction 19 | autocmd FileType fugitive call setup_gitstatus() 20 | autocmd FileType fugitive,fugitiveblame nmap q gq 21 | autocmd BufWinEnter * if exists("*FugitiveDetect") && empty(expand(''))|call FugitiveDetect(getcwd())|endif 22 | 23 | "when Vim starts in diff-mode (vim -d, git mergetool): 24 | " - do/dp should not auto-fold 25 | autocmd VimEnter * if &diff | exe 'windo set foldmethod=manual' | endif 26 | augroup END 27 | 28 | func! s:fug_detect() abort 29 | if !exists('b:git_dir') 30 | call FugitiveDetect() 31 | endif 32 | endfunc 33 | 34 | nmap &diff?']c]n':(luaeval('({pcall(require, "gitsigns")})[1]')?'lua require("gitsigns").next_hunk({wrap=false})':']n') 35 | nmap &diff?'[c[n':(luaeval('({pcall(require, "gitsigns")})[1]')?'lua require("gitsigns").prev_hunk({wrap=false})':'[n') 36 | 37 | " version control 38 | xnoremap D (mode() ==# "V" ? ':Linediff' : 'D') 39 | 40 | " Blame: 41 | nnoremap Ub '@_G blame '..(v:count?'--ignore-revs-file ""':'')..'' 42 | nnoremap 1Ub :.,G blamecall feedkeys("\cr>") 43 | xnoremap Ub :G blame 44 | " Blame "name": 45 | nnoremap Un Gitsigns blame_line 46 | 47 | " Commit using the current file's most-recent commit-message. 48 | nnoremap Uc '@_:G commit '..(v:count ? '--no-verify' : '')..' --edit -m '..shellescape(FugitiveExecute(['log', '-1', '--format=%s', '--', FugitivePath()]).stdout[0])..'' 49 | nnoremap Ud :if &diffdiffupdateelseif !v:count && empty(FugitiveExecute(['diff', '--', FugitivePath()]))echo 'no changes'elseexe 'Gvdiffsplit'.(v:count ? ' HEAD'.repeat('^', v:count) : '')call feedkeys('')endif 50 | nnoremap Ue :Gedit 51 | nnoremap Uf :G show =FugitiveExecute(['log', '-1', '--format=%h', '--', FugitivePath()]).stdout[0]:G commit --fixup==FugitiveExecute(['log', '-1', '--format=%h', '--', FugitivePath()]).stdout[0] 52 | 53 | " Log: 54 | nnoremap Ul '@_G log --pretty="%h%d %s %aN (%cr)" --date=relative'.(v:count?'':' --follow -- %').'' 55 | xnoremap Ul :Gclog! 56 | nnoremap 1Ul '@_Gedit @' 57 | 58 | nnoremap U: :G log --pretty="%h%d %s %aN (%cr)" --date=relative 59 | nnoremap Um :G log --pretty="%h%d %s %aN (%cr)" --date=relative -L ::% 60 | nnoremap Ur '@_Gread'.(v:count?(' @'.repeat('^',v:count).':%'):'').'' 61 | nnoremap Us :G 62 | nnoremap Uu :Gedit 63 | nnoremap Uw :call fug_detect()Gwrite! 64 | nnoremap Ux :try.GBrowsecatchcall feedkeys(':.GBrowse @')endtry 65 | xnoremap Ux :try'<,'>GBrowsecatchcall feedkeys('gv:GBrowse @')endtry 66 | nnoremap U. :G G s 67 | 68 | nmap UB Ub 69 | nmap 1UB 1Ub 70 | xmap UB Ub 71 | nmap UC Uc 72 | nmap UD Ud 73 | nmap UE Ue 74 | nmap UF Uf 75 | nmap UL Ul 76 | xmap UL Ul 77 | nmap 1UL 1Ul 78 | nmap UM Um 79 | nmap UN Un 80 | nmap UR Ur 81 | nmap US Us 82 | nmap UU Uu 83 | nmap UW Uw 84 | nmap UX Ux 85 | xmap UX Ux 86 | 87 | "linewise partial staging in visual-mode. 88 | xnoremap :diffput 89 | xnoremap :diffget 90 | ]=] 91 | 92 | local function ctrl_g() 93 | local msg = {} 94 | local fn = vim.fn 95 | local isfile = 0 == fn.empty(fn.expand('%:p')) 96 | -- Show file info. 97 | local oldmsg = vim.trim(fn.execute('norm! 2'..vim.keycode(''))) 98 | local mtime = isfile and fn.strftime('%Y-%m-%d %H:%M',fn.getftime(fn.expand('%:p'))) or '' 99 | table.insert(msg, { ('%s %s\n'):format(oldmsg:sub(1), mtime) }) 100 | -- Show git branch 101 | local gitref = 1 == fn.exists('*FugitiveHead') and fn['FugitiveHead'](7) or nil 102 | if gitref then 103 | table.insert(msg, { ('branch: %s\n'):format(gitref) }) 104 | end 105 | -- Show current directory. 106 | table.insert(msg, { ('dir: %s\n'):format(fn.fnamemodify(fn.getcwd(), ':~')) }) 107 | -- Show current session. 108 | table.insert(msg, { ('ses: %s\n'):format(#vim.v.this_session > 0 and fn.fnamemodify(vim.v.this_session ':~') or '?') }) 109 | -- Show process id. 110 | table.insert(msg, { ('PID: %s\n'):format(fn.getpid()) }) 111 | -- Show current context. 112 | -- https://git.savannah.gnu.org/cgit/diffutils.git/tree/src/diff.c?id=eaa2a24#n464 113 | table.insert(msg, { 114 | fn.getline(fn.search('\\v^[[:alpha:]$_]', 'bn', 1, 100)), 115 | 'Identifier', 116 | }) 117 | vim.api.nvim_echo(msg, false, {}) 118 | end 119 | 120 | vim.keymap.set('n', '', ctrl_g) 121 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/hlheadings.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local ns = vim.api.nvim_create_namespace('my.hlheadings.hl') 4 | local event_ns = vim.api.nvim_create_augroup('my.hlheadings', { clear=true }) 5 | 6 | ---@return integer,integer,string 7 | local function getbufline(node, bufnr, offset) 8 | offset = offset or 0 9 | local line1, _, line2, _ = node:range() 10 | line1 = line1 - offset 11 | line2 = line2 + offset 12 | local lines = vim.fn.getbufline(bufnr, line1 + 1, line2 + 1) 13 | return line1, line2, table.concat(lines, '\n') 14 | end 15 | 16 | --- Recursively applies `fn` to all nodes in tree starting at `root`. 17 | local function ts_traverse_descendants(root, level, lang_tree, bufnr, fn) 18 | assert(root and level and lang_tree and bufnr and fn) 19 | local node_name = (root.named and root:named()) and root:type() or nil 20 | 21 | if root:child_count() > 0 then 22 | for node, _ in root:iter_children() do 23 | if node:named() then 24 | ts_traverse_descendants(node, level + 1, lang_tree, bufnr, fn) 25 | end 26 | end 27 | end 28 | 29 | local startline, endline, text = getbufline(root, bufnr) 30 | fn(root, node_name, startline, endline, text) 31 | end 32 | 33 | --- Traverses all treesitter trees in the given buffer. 34 | --- 35 | ---@param fn fun(node: table, name: string, startline: integer, endline: integer, text: string) 36 | local function ts_traverse(bufnr, fn) 37 | local lang_tree = assert(vim.treesitter.get_parser(bufnr, nil, { error = false })) 38 | for _, tree in ipairs(lang_tree:trees()) do 39 | ts_traverse_descendants(tree:root(), 0, tree, bufnr, fn) 40 | end 41 | lang_tree:destroy() 42 | end 43 | 44 | --- Overlays a highlight on a line. 45 | --- HACK: copies the line text into a virt_text overlay. 46 | local function hl_line(bufnr, linenr, hide, ns, hlgroup, minlen) 47 | local line = vim.api.nvim_buf_get_lines(bufnr, linenr, linenr + 1, false)[1] 48 | if not line then 49 | return 50 | end 51 | -- Scrub markup chars. 52 | line = line:gsub('^%s*[#]+', ''):gsub('%s*$', '') 53 | local len = vim.fn.strdisplaywidth(line) 54 | local pad_len = math.max(minlen and 0 or len, (minlen or 0) - len) 55 | vim.api.nvim_buf_set_extmark(bufnr, ns, linenr, 0, { 56 | virt_text = {{ (hide and '' or line) .. (' '):rep(pad_len), hlgroup }}, 57 | virt_text_pos = 'overlay', 58 | hl_mode = 'combine', 59 | }) 60 | end 61 | 62 | local function clear() 63 | vim.api.nvim_buf_clear_namespace(0, ns, 0, -1) 64 | end 65 | 66 | local function hlheadings_do_hl() 67 | -- vim.cmd[[hi clear @markup.heading.1.delimiter.vimdoc]] 68 | -- vim.cmd[[hi clear @markup.heading.2.delimiter.vimdoc]] 69 | clear() 70 | local minlen = 300 71 | 72 | local curline = vim.fn.line('.') 73 | local did_h1 = false 74 | local stop = false 75 | 76 | -- Highlight headings in markdown docs. 77 | ts_traverse(0, function(node, name, startline, endline, text) 78 | local hlgroup = 'MyH2' -- name == 'atx_heading' and 'MyH1' or 'MyH2' 79 | local at_or_below_cursor = startline + 1 >= curline 80 | if stop then 81 | return 82 | end 83 | if at_or_below_cursor and did_h1 and name == 'atx_h1_marker' then 84 | stop = true 85 | end 86 | if at_or_below_cursor and name == 'atx_h1_marker' then 87 | did_h1 = true 88 | end 89 | if name == 'setext_heading' or name == 'atx_heading' then 90 | hl_line(0, startline, false, ns, hlgroup, minlen) 91 | -- elseif name == 'setext_h1_underline' or name == 'setext_h2_underline' then 92 | -- hl_line(0, startline, true, ns, 'Normal') 93 | end 94 | end) 95 | end 96 | 97 | vim.cmd[[ 98 | autocmd VimEnter,OptionSet background if v:option_new ==# 'dark' 99 | \| hi MyH1 ctermfg=white ctermbg=DarkGrey guisp=fg guifg=white guibg=#3b3b3b 100 | \| hi MyH2 ctermfg=white ctermbg=DarkGrey guisp=fg guifg=white guibg=#3a3a3a 101 | \| else 102 | \| hi MyH1 ctermfg=black ctermbg=LightGrey guisp=fg guifg=black guibg=LightGrey 103 | \| hi MyH2 ctermfg=black ctermbg=LightGrey guisp=fg guifg=black guibg=LightGrey 104 | \| endif 105 | hi MyH1 ctermfg=white ctermbg=DarkGrey guisp=fg guifg=white guibg=#3b3b3b 106 | ]] -- cterm=underdouble gui=underdouble guisp=fg 107 | 108 | -- vim.api.nvim_create_autocmd({'FileType'}, { 109 | -- pattern = 'markdown', 110 | -- group = event_ns, 111 | -- callback = function() 112 | -- if vim.wo.diff then 113 | -- clear() 114 | -- else 115 | -- hlheadings_do_hl() 116 | -- end 117 | -- 118 | -- if vim.b.did_hlheadings then 119 | -- return 120 | -- end 121 | -- 122 | -- vim.api.nvim_create_autocmd({'InsertEnter'}, { 123 | -- buffer = 0, 124 | -- callback = function() 125 | -- clear() 126 | -- end, 127 | -- }) 128 | -- vim.api.nvim_create_autocmd({'InsertLeave'}, { 129 | -- buffer = 0, 130 | -- callback = function() 131 | -- hlheadings_do_hl() 132 | -- end, 133 | -- }) 134 | -- 135 | -- vim.b.did_hlheadings = true 136 | -- end, 137 | -- }) 138 | 139 | return M 140 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/img.lua: -------------------------------------------------------------------------------- 1 | -- credit: timg + https://github.com/neovim/neovim/issues/30889 2 | -- 3 | -- TODO: look at 4 | -- - https://github.com/folke/snacks.nvim/blob/main/docs/image.md 5 | -- - https://github.com/HakonHarnes/img-clip.nvim 6 | -- 7 | -- ref: https://sw.kovidgoyal.net/kitty/graphics-protocol/ 8 | 9 | local M = {} 10 | 11 | --- Gets the current tty name. E.g. "/dev/ttys008" 12 | ---@return string|nil 13 | local function get_tty_name() 14 | -- local handle = io.popen('tty 2>/dev/null') 15 | -- if not handle then return nil end 16 | -- local rv = handle:read('*a') 17 | -- handle:close() 18 | 19 | -- TODO: this is a hack, $GPG_TTY is set in my personal bashrc. 20 | local rv = vim.fn.trim(vim.env.GPG_TTY) 21 | return rv ~= '' and rv or nil 22 | end 23 | 24 | local TTY_NAME = assert(get_tty_name(), 'failed to read editor tty name') 25 | 26 | local function base64_encode_file(fname) 27 | local f = assert(io.open(fname, 'rb')) 28 | local data = f:read('*a') 29 | f:close() 30 | return vim.base64.encode(data) 31 | end 32 | 33 | ---Writes data to the editor tty. 34 | ---@param ... string|number 35 | local function write(...) 36 | local handle = io.open(TTY_NAME, 'w') 37 | if not handle then 38 | error('failed to open ' .. TTY_NAME) 39 | end 40 | handle:write(...) 41 | handle:close() 42 | end 43 | 44 | local CODES = { 45 | BEL = '\x07', -- aka ^G 46 | ESC = '\x1B', -- aka ^[ 47 | } 48 | 49 | local function move_cursor(x, y, save) 50 | -- if is_SSH and utils.tmux.is_tmux then 51 | -- -- When tmux is running over ssh, set-cursor sometimes doesn't actually get sent 52 | -- -- I don't know why this fixes the issue... 53 | -- utils.tmux.get_cursor_x() 54 | -- utils.tmux.get_cursor_y() 55 | -- end 56 | if save then write(CODES.ESC .. '[s') end 57 | write(CODES.ESC .. '[' .. y .. ';' .. x .. 'H') 58 | vim.uv.sleep(1) 59 | end 60 | 61 | local function restore_cursor() 62 | write(CODES.ESC .. '[u') 63 | end 64 | 65 | ---@param opts? {data?:string, filename?:string, proto?:'iterm2'|'kitty'} 66 | function M.show(opts) 67 | opts = opts or {} 68 | 69 | local data = opts.data 70 | if opts.filename then 71 | data = base64_encode_file(opts.filename) 72 | end 73 | 74 | -- Exit early if nothing to show 75 | if not data or string.len(data) == 0 then 76 | print('NO DATA') 77 | return 78 | end 79 | 80 | local proto = opts.proto or 'kitty' 81 | 82 | move_cursor(60, 4, true) 83 | 84 | if proto == 'iterm2' then 85 | -- NOTE: We MUST mark as inline otherwise not rendered and put in a 86 | -- downloads folder 87 | write(CODES.ESC .. ']1337') -- Begin sequence 88 | write(';File=inline=1') -- Display image inline 89 | write(':' .. data) -- Transmit base64 data 90 | write(CODES.BEL) -- End sequence 91 | elseif proto == 'kitty' then 92 | local CHUNK_SIZE = 4096 93 | local pos = 1 94 | local DATA_LEN = string.len(data) 95 | 96 | -- For kitty, we need to write an image in chunks 97 | -- 98 | -- Graphics codes are in this form: 99 | -- 100 | -- _G;\ 101 | -- 102 | -- To simultaneously transmit and display an image, we use `a=T`. 103 | -- 104 | -- Chunking data (such as from over a network) requires the 105 | -- specification of `m=0|1`, where all chunks must have a 106 | -- value of `1` except the very last chunk. 107 | while pos <= DATA_LEN do 108 | write(CODES.ESC .. '_G') -- Begin sequence 109 | 110 | -- If at the beginning of our image, mark as a PNG to be 111 | -- transmitted and displayed immediately. 112 | -- a=T : "transmit and display" 113 | -- f=100 : PNG 114 | -- w=width 115 | -- h=height 116 | -- c=columns 117 | -- H=horizontal offset 118 | -- V=vertical offset 119 | -- C=1 : "don't move the cursor" 120 | if pos == 1 then 121 | write('a=T,f=100,C=1,c=44,w=1000,h=1000,') 122 | -- write('a=T,f=100,C=1,c=50,X=1000,Y=200,H=100,V=100,') 123 | end 124 | 125 | -- Get our specific chunk of data and increment position 126 | local chunk = data:sub(pos, pos + CHUNK_SIZE) 127 | pos = pos + CHUNK_SIZE 128 | 129 | -- If we are still sending chunks and not at the end 130 | if pos <= DATA_LEN then 131 | write('m=1') 132 | end 133 | 134 | -- If we have a chunk available, write it 135 | if string.len(chunk) > 0 then 136 | write(';') 137 | write(chunk) 138 | end 139 | 140 | write(CODES.ESC .. '\\') -- End sequence 141 | end 142 | end 143 | 144 | restore_cursor() 145 | end 146 | 147 | function M.clear_all(proto) 148 | proto = proto and proto or 'kitty' 149 | 150 | if proto == 'iterm2' then 151 | error() 152 | elseif proto == 'kitty' then 153 | -- Graphics codes are in this form: 154 | -- 155 | -- _G;\ 156 | -- 157 | -- a=d without other params means 'delete all'. 158 | write(CODES.ESC .. '_Ga=d;' .. CODES.ESC .. '\\') 159 | end 160 | 161 | restore_cursor() 162 | end 163 | 164 | M.clear_all() 165 | -- M.show({ filename = vim.fn.expand('~/notes/talks/img/mtg-homunculus.png') }) 166 | -- write(CODES.ESC .. '[2J') 167 | 168 | return M 169 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/keymaps.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[[ 2 | " key mappings/bindings =================================================== {{{ 3 | " 4 | " available mappings: 5 | " visual: c-\ m R c-r c-n c-g c-a c-x c-h, 6 | " insert: c-\ c-g 7 | " normal: vd gy c-f c-t c-b c-j c-k + _ c-\ g= zu z/ m zy zi zp m q y q 8 | " c 9 | " !@ --> async run 10 | 11 | "tnoremap '"'.nr2char(getchar()).'pi' 12 | 13 | :xnoremap y zy 14 | :nnoremap p zp 15 | :nnoremap P zP 16 | " copy selection to gui-clipboard 17 | xnoremap Y "+y 18 | " copy entire file contents (to gui-clipboard if available) 19 | nnoremap yY :let b:winview=winsaveview()exe 'keepjumps keepmarks norm ggVG"+y'call winrestview(b:winview) 20 | " copy current (relative) filename (to gui-clipboard if available) 21 | nnoremap "%y let @+=fnamemodify(@%, ':.') 22 | 23 | " Put filename tail. 24 | cnoremap =fnamemodify(@%, ':t') 25 | cmap 26 | " current-file directory 27 | noremap! =expand('%:.:h', 1) 28 | noremap! ? =substitute(getreg('/'), '[<>\\]', '', 'g') 29 | " /: Inverse search (line NOT containing pattern). 30 | cnoremap (getcmdtype() =~ '[/?]' && getcmdline() == '') ? '\v^(()@!.)*$' : '' 31 | " Hit space to match multiline whitespace. 32 | cnoremap getcmdtype() =~ '[/?]' ? '\_s\+' : ' ' 33 | " //: "Search within visual selection". 34 | cnoremap / (getcmdtype() =~ '[/?]' && getcmdline() == '') ? "\\/\\%V" : '/' 35 | 36 | nnoremap g: :lua = 37 | nnoremap z= setlocal spellz= 38 | nnoremap ' ` 39 | inoremap 40 | 41 | " niceblock 42 | xnoremap I (mode()=~#'[vV]'?'^o^I':'I') 43 | xnoremap A (mode()=~#'[vV]'?'0o$A':'A') 44 | 45 | 46 | nnoremap g> :set nomoreecho repeat("\n",&cmdheight)40messagesset more 47 | 48 | " word-wise i_CTRL-Y 49 | inoremap pumvisible() ? "\" : matchstr(getline(line('.')-1), '\%' . virtcol('.') . 'v\%(\k\+\\|.\)') 50 | 51 | " mark position before search 52 | nnoremap / ms/ 53 | 54 | nnoremap n 'Nn'[v:searchforward] 55 | nnoremap N 'nN'[v:searchforward] 56 | 57 | nnoremap 58 | nnoremap 59 | 60 | 61 | " :help :DiffOrig 62 | command! DiffOrig leftabove vnew | set bt=nofile | r ++edit # | 0d_ | diffthis | wincmd p | diffthis 63 | 64 | nnoremap yo :set =(&diffopt =~# 'iwhiteall') ? 'diffopt-=iwhiteall' : 'diffopt+=iwhiteall' 65 | 66 | " Format filters 67 | " ideas: https://github.com/sbdchd/neoformat 68 | nnoremap gqax :%!tidy -q -i -xml -utf8 69 | nnoremap gqah :%!tidy -q -i -ashtml -utf8 70 | nnoremap gqaj :%!python3 -m json.tool 71 | nnoremap gqav :call append('$', json_encode(eval(join(getline(1,'$')))))'[k"_dVgg:%!python -m json.tool 72 | 73 | " un-join (split) the current line at the cursor position 74 | nnoremap gj ik$ 75 | xnoremap x "_d 76 | 77 | nnoremap vK :help 78 | 79 | " text-object: entire buffer 80 | " Elegant text-object pattern hacked out of jdaddy.vim. 81 | function! s:line_outer_movement(count) abort 82 | if empty(getline(1)) && 1 == line('$') 83 | return "\" 84 | endif 85 | let [lopen, copen, lclose, cclose] = [1, 1, line('$'), 1] 86 | call setpos("'[", [0, lopen, copen, 0]) 87 | call setpos("']", [0, lclose, cclose, 0]) 88 | return "'[o']" 89 | endfunction 90 | xnoremap al line_outer_movement(v:count1) 91 | onoremap al :normal Val 92 | 93 | " text-object: line 94 | " Elegant text-object pattern hacked out of jdaddy.vim. 95 | function! s:line_inner_movement(count) abort 96 | "TODO: handle count 97 | if empty(getline('.')) 98 | return "\" 99 | endif 100 | let [lopen, copen, lclose, cclose] = [line('.'), 1, line('.'), col('$')-1] 101 | call setpos("'[", [0, lopen, copen, 0]) 102 | call setpos("']", [0, lclose, cclose, 0]) 103 | return "`[o`]" 104 | endfunction 105 | xnoremap il line_inner_movement(v:count1) 106 | onoremap il :normal vil 107 | 108 | " Insert formatted datetime (from @tpope vimrc). 109 | inoremap =repeat(complete(col('.'),map(["%Y-%m-%d %H:%M:%S","%a, %d %b %Y %H:%M:%S %z","%Y %b %d","%d-%b-%y","%a %b %d %T %Z %Y","%Y%m%d"],'strftime(v:val)')+[localtime()]),0) 110 | " Print unix time at cursor as human-readable datetime. 1677604904 => '2023-02-28 09:21:45' 111 | nnoremap gA :echo strftime('%Y-%m-%d %H:%M:%S', '') 112 | 113 | " Preserve '[ '] on :write. 114 | nnoremap z. :silent lockmarks update ++p 115 | 116 | " Select last inserted text. 117 | nnoremap gV `[v`] 118 | 119 | " Repeat last command for each line of a visual selection. 120 | xnoremap . :normal . 121 | " Repeat the last edit on the next [count] matches. 122 | nnoremap gn :normal n. 123 | 124 | " Record a macro, or set the last-recorded macro to v:register (example: "aq). 125 | nnoremap q (v:register==#'"')?'q':(':let @'.(empty(reg_recorded())?'q':reg_recorded())." = '=substitute(@".v:register.",\"'\",\"''\",\"g\")'010l") 126 | nnoremap q q 127 | nnoremap \q q 128 | 129 | command! -nargs=+ -bang -complete=command R if !0 | wincmd n | endif 130 | \ | call execute(printf("put=execute('%s')", substitute(escape(, '"'), "'", "''", 'g'))) 131 | inoremap R :R! 132 | 133 | " special-purpose mappings/commands =========================================== 134 | nnoremap vv :exe 'e' fnameescape(resolve($MYVIMRC)) 135 | nnoremap vp :exe 'e' stdpath('config')..'/plugin/' 136 | nnoremap vr :Vimref 137 | 138 | ]] 139 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/replace-op.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[[ 2 | func! s:trimws_ml(s) abort "trim whitespace across multiple lines 3 | return substitute(a:s, '^\_s*\(.\{-}\)\_s*$', '\1', '') 4 | endf 5 | "why? 6 | " - repeatable 7 | " - faster/more convenient than visual-replace 8 | " - does not modify ' mark 9 | " - DWIM behavior for linewise => characterwise 10 | let s:rr_reg = '"' 11 | func! s:set_reg(reg_name) abort 12 | let s:rr_reg = a:reg_name 13 | endf 14 | func! s:replace_without_yank(type) abort 15 | let rr_orig = getreg(s:rr_reg, 1) "save registers and types to restore later. 16 | let rr_type = getregtype(s:rr_reg) 17 | let sel_save = &selection 18 | let &selection = "inclusive" 19 | let replace_curlin = (1==col("'[") && (col('$')==1 || col('$')==(col("']")+1)) && line("'[")==line("']")) 20 | 21 | if a:type ==? 'line' || replace_curlin 22 | exe "keepjumps normal! '[V']\"".s:rr_reg."P" 23 | elseif a:type ==? 'block' 24 | exe "keepjumps normal! `[\`]\"".s:rr_reg."P" 25 | else 26 | "DWIM: if pasting linewise contents in a _characterwise_ motion, trim 27 | " surrounding whitespace from the content to be pasted. 28 | if rr_type ==# "V" 29 | call setreg(s:rr_reg, s:trimws_ml(rr_orig), "v") 30 | endif 31 | exe "keepjumps normal! `[v`]\"".s:rr_reg."P" 32 | endif 33 | 34 | let &selection = sel_save 35 | call setreg(s:rr_reg, rr_orig, rr_type) 36 | endf 37 | 38 | nnoremap dr :call set_reg(v:register)set opfunc=replace_without_yankg@ 39 | nnoremap drr :call set_reg(v:register)0:set opfunc=replace_without_yankg@$ 40 | ]] 41 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/slipnslide.lua: -------------------------------------------------------------------------------- 1 | -- TODO: https://sli.dev/ 2 | -- TODO: use this instead?: https://github.com/sotte/presenting.nvim 3 | 4 | local saved = {} 5 | 6 | -- Gets the dir of the current buffer. 7 | local function buf_dir() 8 | return vim.fn.fnamemodify(vim.fn.expand('%'), ':p:h') 9 | end 10 | 11 | -- Searches between previous and next H1 heading ("^(#|=)"). 12 | function _G.search_cur_slide(pat) 13 | -- Temporarily move cursor 1 row down, in case it is on a heading already. 14 | vim.cmd[[norm! j]] 15 | 16 | local cur_row, _ = unpack(vim.api.nvim_win_get_cursor(0)) 17 | cur_row = cur_row - 1 18 | -- Find previous H1 heading, or use topline. 19 | local start_row, _ = unpack(vim.fn.searchpos('^#[^#]', 'nb')) 20 | start_row = start_row > 0 and (start_row - 1) or vim.fn.line('w0') 21 | -- Find next H1 heading, or use botline. 22 | local end_row, _ = unpack(vim.fn.searchpos('^#[^#]', 'ne')) 23 | end_row = end_row > 0 and (end_row - 1) or vim.fn.line('w$') 24 | 25 | -- Now, search for the pattern within that section/range. 26 | local matches = {} 27 | local lines = vim.api.nvim_buf_get_lines(0, start_row, end_row + 1, false) 28 | for _, line in ipairs(lines) do 29 | local m = line:match(pat) 30 | if m then 31 | table.insert(matches, m) 32 | end 33 | end 34 | 35 | -- Restore cursor. 36 | vim.cmd[[norm! k]] 37 | 38 | return matches 39 | end 40 | 41 | -- Gets the image filepath for the current slide, if any. 42 | local function get_slide_img() 43 | -- "img: ./foo/bar.png" 44 | local el = search_cur_slide('^img: .*')[1] 45 | if not el then 46 | return nil 47 | end 48 | local relpath = vim.trim(el:gsub('img: ', '')) 49 | local fullpath = vim.fs.joinpath(buf_dir(), relpath) 50 | assert(vim.fn.filereadable(fullpath) ~= 0) 51 | return fullpath 52 | end 53 | 54 | local function try_show_img() 55 | local imgpath = get_slide_img() 56 | if not imgpath then 57 | return 58 | end 59 | vim.cmd[[redraw]] 60 | -- vim.cmd[[sleep 100m]] 61 | require('my.img').show({ filename = imgpath }) 62 | end 63 | 64 | function _G.slides_clear() 65 | -- vim.cmd[[mapclear ]] 66 | vim.cmd[[setlocal laststatus=2]] 67 | require'my.img'.clear_all() 68 | vim.fn.clearmatches() 69 | vim.o.tabline = saved.tabline 70 | vim.o.ruler = saved.ruler 71 | end 72 | 73 | function _G.slides_setopt() 74 | vim.o.tabline = ' ' 75 | vim.o.ruler = false 76 | vim.o.virtualedit = 'all' 77 | vim.cmd[[ 78 | setlocal laststatus=0 cmdheight=1 scrolloff=0 signcolumn=no 79 | setlocal textwidth=53 80 | ]] 81 | end 82 | 83 | function _G.show_cur_slide() 84 | _G.slides_setopt() 85 | 86 | if vim.fn.hlID('SlidesHide') == 0 then 87 | -- use folds instead of highlight 88 | else 89 | vim.cmd[=[ 90 | " Hide all lines after the current slide 91 | exe 'match SlidesHideAfterSlide /\%>'.(line('w0')-1).'l\n\(#[^#]\|==\)[^\n]*\n\_.\{-}\zs\n.*\n\(#[^#]\|==\)\+\_.*/' 92 | " Hide "img:…" lines. 93 | 2match SlidesHideImg /^img: .*/ 94 | " Hide "http://…" lines. 95 | 3match SlidesHideUrl /^https:.*/ 96 | ]=] 97 | end 98 | 99 | vim.cmd[[doautocmd FileType]] -- Trigger hlheadings.lua:hlheadings_do_hl(). 100 | require'my.img'.clear_all() 101 | try_show_img() 102 | end 103 | 104 | function _G.Slides() 105 | saved.tabline = vim.o.tabline 106 | saved.ruler = vim.o.ruler 107 | 108 | vim.cmd[[ 109 | lua slides_clear() 110 | 111 | tab split 112 | lua slides_setopt() 113 | 4vnew 114 | setlocal nocursorline winfixwidth 115 | wincmd p 116 | 117 | "let editing = !!a:0 118 | "if editing 119 | " setlocal colorcolumn=54,67 textwidth=53 120 | " exe printf('hi ColorColumn gui%sg=#555555 cterm%sg=235', 'bf'[&bg], 'bf'[&bg]) 121 | "endif 122 | 123 | hi markdownError ctermbg=NONE ctermfg=NONE guifg=NONE guibg=NONE 124 | 125 | " For cterm. 126 | let bg = synIDattr(synIDtrans(hlID('Normal')), 'bg', 'cterm') 127 | let bg = !empty(bg) ? bg : (&bg==#'dark'?'black':'white') 128 | " Hide slides before/after the current one. 129 | exe 'hi SlidesHide ctermbg='..bg..' ctermfg='..bg..' cterm=nocombine guibg=bg guifg=bg gui=nocombine' 130 | hi link SlidesHideImg SlidesHide 131 | hi link SlidesHideUrl SlidesHide 132 | hi link SlidesHideAfterSlide SlidesHide 133 | 134 | hi! link EndOfBuffer SlidesHide 135 | hi! link WinSeparator SlidesHide 136 | hi Visual guifg=bg guibg=fg 137 | 138 | nnoremap :keeppatterns /\v^(#[^#]\=\=+)zt50:call v:lua.show_cur_slide() 139 | nnoremap :keeppatterns ?\v^(#[^#]\=\=+)zt50:call v:lua.show_cur_slide() 140 | let old_ctrl_l = substitute(maparg('', 'n', 0), '|', '', 'g') 141 | exe "nnoremap ':call v:lua.slides_clear()'.."..old_ctrl_l 142 | ]] 143 | end 144 | 145 | vim.cmd[[ 146 | command! -nargs=? Slides lua Slides() 147 | ]] 148 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/vscode-neovim.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[[ 2 | set shadafile=NONE 3 | 4 | nnoremap gd lua require('vscode-neovim').call(vim.v.count > 0 and 'typescript.goToSourceDefinition' or 'editor.action.revealDefinition') 5 | nnoremap gD lua require('vscode-neovim').call('editor.action.goToImplementation') 6 | nnoremap gri lua require('vscode-neovim').call('references-view.findImplementations') 7 | nnoremap lua require('vscode-neovim').call('editor.debug.action.toggleBreakpoint') 8 | nnoremap gO lua require('vscode-neovim').call('workbench.action.gotoSymbol') 9 | "nnoremap gO lua require('vscode-neovim').call('outline.focus') 10 | nnoremap gr/ lua require('vscode-neovim').call('workbench.action.showAllSymbols') 11 | nnoremap - lua require('vscode-neovim').call('workbench.files.action.showActiveFileInExplorer') 12 | nnoremap lua require('vscode-neovim').call('workbench.action.showAllEditorsByMostRecentlyUsed') 13 | nnoremap lua require('vscode-neovim').call('workbench.action.editor.nextChange') 14 | nnoremap lua require('vscode-neovim').call('workbench.action.editor.previousChange') 15 | 16 | nnoremap UD lua require('vscode-neovim').call('git.openChange') 17 | nnoremap UW lua require('vscode-neovim').call('git.stage') 18 | nnoremap UB lua require('vscode-neovim').call('git.blame.toggleEditorDecoration') 19 | 20 | nnoremap lua require('vscode-neovim').call('git.blame.toggleEditorDecoration') 21 | ]] 22 | -------------------------------------------------------------------------------- /.config/nvim/lua/my/winning.lua: -------------------------------------------------------------------------------- 1 | vim.cmd[[ 2 | " go to the previous window (or any other window if there is no 'previous' window). 3 | func! s:switch_to_alt_win() abort 4 | let currwin = winnr() 5 | wincmd p 6 | if winnr() == currwin "window didn't change; no previous window. 7 | wincmd w 8 | endif 9 | endf 10 | 11 | " manage windows 12 | " [count]s and [count]v create a [count]-sized split 13 | " [count]| and [count]_ resize the current window 14 | " user recommendation: 15 | " eip 16 | " available: 17 | " {motion} 18 | " () 19 | nnoremap 20 | nnoremap 21 | nnoremap 22 | nnoremap 23 | inoremap 24 | inoremap 25 | inoremap 26 | inoremap 27 | tnoremap 28 | tnoremap 29 | tnoremap 30 | tnoremap 31 | nnoremap 32 | nnoremap (v:count > 0 ? 'w' : ':call switch_to_alt_win()') 33 | nnoremap 34 | " inoremap :call switch_to_alt_win()let g:prev_win_buf=@%gi=g:prev_win_buf 35 | 36 | " Fit current window (vertically) to the buffer text. 37 | nnoremap exe min([winheight('%'),line('$')]).'wincmd _'setlocal winfixheight 38 | " Fit current window (vertically) to the selected text. 39 | xnoremap exe (line("'>") - line("'<") + 1).'wincmd _'setlocal winfixheight 40 | 41 | " manage tabs 42 | nnoremap :tab split 43 | nnoremap ZT :tabclose 44 | " move tab to Nth position 45 | nnoremap ':tabmove '.(v:count ? (v:count - 1) : '+1').'' 46 | nnoremap ':tabmove '.(v:count ? (v:count - 1) : '-1').'' 47 | 48 | " quickfix window (in quickfix: toggles between qf & loc list) 49 | nnoremap '@_:'.(&bt!=#'quickfix'!empty(getloclist(0))?'lclosebotright copen':'cclosebotright lopen') 50 | \.(v:count ? 'wincmd L' : '').'' 51 | 52 | nnoremap zt (v:count > 0 ? '@_zt'.v:count.'' : 'zt') 53 | nnoremap zb (v:count > 0 ? '@_zb'.v:count.'' : 'zb') 54 | 55 | nnoremap (v:count ? ':confirm qa' : '') 56 | nnoremap q (v:count ? ':confirm qa' : '') 57 | nnoremap ZZ (v:count ? ':xa!' : '@_ZZ') 58 | nnoremap ZQ (v:count ? ':qa!' : '@_ZQ') 59 | nnoremap = (v:count ? ':windo setlocal nowinfixheight nowinfixwidth=' : '@_=') 60 | 61 | func! s:zoom_toggle(cnt) abort 62 | if a:cnt " Fallback to default '|' behavior if count was provided. 63 | exe 'norm! '.v:count.'|' 64 | endif 65 | 66 | if 1 == winnr('$') 67 | return 68 | endif 69 | let restore_cmd = winrestcmd() 70 | wincmd | 71 | wincmd _ 72 | if exists('t:zoom_restore') 73 | exe t:zoom_restore 74 | unlet t:zoom_restore 75 | elseif winrestcmd() !=# restore_cmd 76 | let t:zoom_restore = restore_cmd 77 | endif 78 | endfunc 79 | nnoremap + :call zoom_toggle(v:count) 80 | nnoremap :call zoom_toggle(v:count) 81 | 82 | augroup config_winning 83 | autocmd! 84 | 85 | autocmd CmdwinEnter * nnoremap q c 86 | 87 | " Closes the current quickfix list and returns to the alternate window. 88 | func! s:close_qflist() 89 | let altwin = winnr('#') 90 | wincmd c 91 | exe altwin.'wincmd w' 92 | endf 93 | autocmd FileType qf nnoremap 94 | \|nnoremap 95 | \|nnoremap q :call close_qflist() 96 | \|setlocal nolist 97 | augroup END 98 | 99 | " 100 | " Highlight current window 101 | " 102 | func! s:focusable_wins() abort 103 | return filter(nvim_tabpage_list_wins(0), {k,v-> !!nvim_win_get_config(v).focusable}) 104 | endf 105 | augroup config_curwin_border 106 | autocmd! 107 | " highlight Normal guibg=NvimDarkGrey1 108 | " highlight NormalNC guibg=NvimDarkGrey2 109 | highlight CursorLineNC cterm=underdashed gui=underdashed ctermfg=gray guisp=NvimLightGrey4 ctermbg=NONE guibg=NONE 110 | highlight link WinBorder Statusline 111 | 112 | " Dim non-current cursorline. 113 | autocmd VimEnter,WinEnter,TabEnter,BufEnter * setlocal winhighlight-=CursorLine:CursorLineNC 114 | 115 | " Highlight curwin WinSeparator/SignColumn for "border" effect. 116 | "let s:winborder_hl = 'WinSeparator:WinBorder,SignColumn:WinBorder' 117 | autocmd WinLeave * exe 'setlocal winhighlight+=CursorLine:CursorLineNC' 118 | "autocmd WinEnter * if len(s:focusable_wins()) > 1 | exe 'setlocal winhighlight+='..s:winborder_hl | endif 119 | " Disable effect if there is only 1 window. 120 | "autocmd WinResized * if 1 == len(s:focusable_wins()) | exe 'setlocal winhighlight-='..s:winborder_hl | endif 121 | augroup END 122 | ]] 123 | -------------------------------------------------------------------------------- /.config/z/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinmk/config/06e5d73f9f4670186ada0d67293a06c9b0176757/.config/z/.gitignore -------------------------------------------------------------------------------- /.emacs.d/elisp/init-bindings.el: -------------------------------------------------------------------------------- 1 | ;; https://github.com/cofi/dotfiles/blob/master/emacs.d/config/cofi-evil.el 2 | 3 | (require 'evil) 4 | (require 'evil-args) 5 | (require 'clojure-mode) 6 | 7 | (defmacro bind (&rest commands) 8 | "Convenience macro which creates a lambda interactive command." 9 | `(lambda () 10 | (interactive) 11 | ,@commands)) 12 | 13 | (after 'smex 14 | (global-set-key (kbd "M-x") 'smex)) 15 | 16 | (after 'evil 17 | (with-package* key-chord 18 | (key-chord-mode 1) 19 | (setq key-chord-two-keys-delay 0.5) 20 | (key-chord-define evil-insert-state-map "jk" 'evil-normal-state)) 21 | 22 | ; exclusive line selection, like Vim. http://dnquark.com/blog/2012/02/emacs-evil-ecumenicalism/ 23 | (setq evil-want-visual-char-semi-exclusive t) 24 | 25 | (define-key evil-normal-state-map "ZQ" (lambda () (interactive) (evil-quit-all t))) 26 | (define-key evil-normal-state-map "Zq" 'evil-quit-all) 27 | (define-key evil-normal-state-map "ZZ" 'evil-save-and-quit) 28 | (define-key evil-normal-state-map "Zb" 'kill-this-buffer) 29 | 30 | ;; obliterate unwanted default key bindings. 31 | (define-key evil-normal-state-map (kbd "U") nil) 32 | (define-key evil-normal-state-map (kbd "g/") nil) 33 | (define-key evil-normal-state-map (kbd "gw") nil) 34 | (define-key evil-normal-state-map (kbd "") nil) 35 | (define-key evil-visual-state-map (kbd "") nil) 36 | (define-key evil-normal-state-map (kbd "C-p") nil) 37 | (global-unset-key (kbd "M-v")) 38 | (global-unset-key (kbd "C-l")) 39 | 40 | (define-key evil-normal-state-map (kbd "C-l") 'evil-ex-nohighlight) 41 | (define-key evil-normal-state-map (kbd "M-v") 42 | (bind (start-process "vim" nil 43 | (if (executable-find "gvim") 44 | "gvim" 45 | (if (executable-find "nvim") "nvim" "vim")) 46 | buffer-file-name))) 47 | (define-key evil-normal-state-map (kbd "z.") 'evil-write) 48 | 49 | (after 'evil-matchit 50 | (define-key evil-normal-state-map "%" 'evilmi-jump-items)) 51 | 52 | (after 'evil-args 53 | ;; bind evil-args text objects 54 | (define-key evil-inner-text-objects-map "a" 'evil-inner-arg) 55 | (define-key evil-outer-text-objects-map "a" 'evil-outer-arg)) 56 | 57 | (after 'git-gutter+-autoloads 58 | (define-key evil-normal-state-map (kbd "[c") 'git-gutter+-previous-hunk) 59 | (define-key evil-normal-state-map (kbd "]c") 'git-gutter+-next-hunk) 60 | (define-key evil-normal-state-map (kbd ",va") 'git-gutter+-stage-hunks) 61 | (define-key evil-normal-state-map (kbd ",vr") 'git-gutter+-revert-hunks)) 62 | 63 | (after 'smex 64 | (define-key evil-visual-state-map (kbd "SPC") 'smex) 65 | (define-key evil-normal-state-map (kbd "SPC") 'smex)) 66 | 67 | (after 'helm 68 | (define-key evil-normal-state-map (kbd "M-o") 'helm-imenu) ;'ido-goto-symbol 69 | (define-key evil-normal-state-map (kbd "C-p") 'helm-projectile) 70 | (define-key evil-normal-state-map (kbd "g/F") 'helm-recentf) 71 | (define-key evil-normal-state-map (kbd "g/.") 'helm-find-files) 72 | (define-key evil-normal-state-map (kbd "g/l") 'helm-occur) ;search lines 73 | (define-key evil-normal-state-map (kbd "g/*") 'helm-swoop) 74 | (define-key evil-normal-state-map (kbd "g//") 75 | (lambda (regexp) 76 | (interactive "sSearch: ") 77 | (pt-regexp regexp default-directory))) 78 | (define-key evil-normal-state-map (kbd "gl") 'helm-buffers-list) ;'switch-to-buffer 79 | (define-key evil-normal-state-map (kbd "M-t") 'helm-etags-select) 80 | (define-key evil-normal-state-map (kbd "M-y") 'helm-show-kill-ring) 81 | (define-key evil-insert-state-map (kbd "M-y") 'helm-show-kill-ring)) 82 | 83 | (define-key evil-motion-state-map (kbd "gw") 'evil-window-map) 84 | (define-key evil-motion-state-map (kbd "gwN") 'make-frame) 85 | (define-key evil-normal-state-map (kbd "") 86 | (bind 87 | (cond 88 | ((eq (count-windows) 1) (other-frame 1)) 89 | (t (evil-window-mru))))) 90 | 91 | (define-key evil-normal-state-map (kbd "g/r") (bind (evil-ex "%s/"))) ;search/replace 92 | (define-key evil-normal-state-map (kbd "s") 'evil-ace-jump-char-mode) 93 | (define-key evil-normal-state-map (kbd "S") 'evil-ace-jump-char-mode) 94 | 95 | (define-key evil-normal-state-map (kbd "[ SPC") (bind (evil-insert-newline-above) (forward-line))) 96 | (define-key evil-normal-state-map (kbd "] SPC") (bind (evil-insert-newline-below) (forward-line -1))) 97 | (define-key evil-normal-state-map (kbd "[ b") 'previous-buffer) 98 | (define-key evil-normal-state-map (kbd "] b") 'next-buffer) 99 | (define-key evil-normal-state-map (kbd "[ q") 'previous-error) 100 | (define-key evil-normal-state-map (kbd "] q") 'next-error) 101 | 102 | (define-key evil-normal-state-map (kbd "gV") (kbd "` [ v ` ]")) 103 | 104 | (define-key evil-normal-state-map (kbd "C-q") 'universal-argument) 105 | 106 | (define-key evil-motion-state-map "j" 'evil-next-visual-line) 107 | (define-key evil-motion-state-map "k" 'evil-previous-visual-line) 108 | (define-key evil-normal-state-map (kbd "-") 'evil-last-non-blank) 109 | (define-key evil-normal-state-map (kbd "Y") (kbd "y$")) 110 | 111 | ;; version control 112 | (define-key evil-normal-state-map (kbd "Ud") 'vc-diff) 113 | (define-key evil-normal-state-map (kbd "Us") 'magit-status) 114 | (define-key evil-normal-state-map (kbd "Ul") 'magit-log) 115 | (define-key evil-normal-state-map (kbd "UB") 'magit-blame-mode) 116 | (define-key evil-normal-state-map (kbd "Ub") 'git-messenger:popup-message) 117 | (define-key evil-normal-state-map (kbd "Ur") 'my-vc-git-reset) 118 | (define-key evil-normal-state-map (kbd "UW") 'my-vc-git-add) 119 | (define-key evil-normal-state-map (kbd "UG") (bind (call-process-shell-command "git gui" nil 0))) 120 | (define-key evil-normal-state-map (kbd "UL") (bind (call-process-shell-command "gitk --all" nil 0))) 121 | 122 | ;; "The end user almost never has to use defadvice despite what the wiki tells you" 123 | ;; http://stackoverflow.com/questions/14606037/advising-an-emacs-interactive-function-before 124 | ;; (define-key evil-normal-state-map (kbd "cow") 'toggle-truncate-lines) 125 | ;; 126 | ;; Based on the approach used by evil-surround (note the use of 127 | ;; evil-inhibit-operator): 128 | ;; (evil-define-command my-thing () 129 | ;; (interactive) 130 | ;; (setq evil-inhibit-operator t) 131 | ;; (cond 132 | ;; ((eq 'evil-change evil-this-operator) 133 | ;; (message "cow was typed!")) 134 | ;; ((eq 'evil-delete evil-this-operator) 135 | ;; (message "dow was typed!")) 136 | ;; ;; ... 137 | ;; )) 138 | ;; (define-key evil-operator-state-map "ow" 'my-thing) 139 | ;; 140 | ;; This may not be exhaustive but here is a list of standard operators: 141 | ;; evil-change (c) 142 | ;; evil-delete (d) 143 | ;; evil-yank (y) 144 | ;; evil-shift-right (>) 145 | ;; evil-shift-left (<) 146 | ;; evil-downcase (gu) 147 | ;; evil-upcase (gU) 148 | ;; evil-invert-case (g~) 149 | ;; evil-shell-command (!) 150 | ;; evil-indent (=) 151 | ;; evil-fill-and-move (gq) 152 | ;; evil-rot13 (g?) 153 | 154 | (define-key evil-normal-state-map (kbd "gof") 155 | (bind (call-process-shell-command (concat "start explorer /select," 156 | (shell-quote-argument (replace-regexp-in-string "/" "\\\\" (buffer-file-name))))))) 157 | (define-key evil-normal-state-map (kbd "got") 158 | (bind 159 | (evil-window-split) 160 | (shell))) 161 | 162 | ;; file management 163 | (define-key evil-normal-state-map "^" nil) 164 | (after 'speedbar 165 | (define-key evil-normal-state-map (kbd "^") 166 | (bind 167 | (speedbar-get-focus) 168 | (speedbar-refresh))) 169 | ;; unbind default 'g' binding in speedbar 170 | (define-key speedbar-mode-map (kbd "g") nil) 171 | (evil-define-key 'normal speedbar-mode-map 172 | (kbd "-") 'speedbar-up-directory 173 | (kbd "o") 'speedbar-edit-line)) 174 | 175 | (define-key evil-normal-state-map (kbd "gx") 'browse-url-at-point) 176 | (define-key evil-visual-state-map (kbd "gx") 'my-google) 177 | 178 | ;; sexp manipulation 179 | (define-key evil-normal-state-map (kbd "g ") nil) 180 | (define-key evil-normal-state-map "gs" nil) 181 | (dolist (pair '("(" "[" "{")) 182 | (define-key evil-normal-state-map (kbd (concat "gs" pair)) 183 | `(lambda () 184 | (interactive) 185 | (sp-select-next-thing) 186 | (sp-wrap-with-pair ,pair) 187 | (sp-beginning-of-sexp) 188 | (evil-insert 1) 189 | (insert " ") 190 | (left-char 1)))) 191 | (define-key evil-normal-state-map (kbd "gs)") 192 | (bind (sp-select-next-thing) (sp-wrap-with-pair "(") (sp-end-of-sexp 1) (evil-insert 1))) 193 | (define-key evil-normal-state-map (kbd "gs]") 194 | (bind (sp-select-next-thing) (sp-wrap-with-pair "[") (sp-end-of-sexp 1) (evil-insert 1))) 195 | (define-key evil-normal-state-map (kbd "gs}") 196 | (bind (sp-select-next-thing) (sp-wrap-with-pair "{") (sp-end-of-sexp 1) (evil-insert 1))) 197 | (define-key evil-normal-state-map (kbd "gss") 'sp-slurp-hybrid-sexp) 198 | (define-key evil-normal-state-map (kbd "gsS") 'sp-backward-slurp-sexp) 199 | (define-key evil-normal-state-map (kbd "gsb") 'sp-forward-barf-sexp) 200 | (define-key evil-normal-state-map (kbd "gsB") 'sp-backward-barf-sexp) 201 | (define-key evil-normal-state-map (kbd "gst") 'transpose-sexps) 202 | ;; for lisps, use non-hybrid commands. 203 | (dolist (modemap '(clojure-mode-map lisp-mode-shared-map elisp-slime-nav-mode-map emacs-lisp-mode-map lisp-interaction-mode-map lisp-mode-map)) 204 | (evil-define-key 'normal modemap 205 | (kbd "gss") 'sp-forward-slurp-sexp)) 206 | 207 | ;; sexp motion 208 | (global-unset-key (kbd "M-j")) 209 | (global-unset-key (kbd "M-k")) 210 | (global-unset-key (kbd "M-h")) 211 | (global-unset-key (kbd "M-l")) 212 | (define-key evil-normal-state-map (kbd ")") (bind 213 | (evil-append 1) 214 | (sp-beginning-of-next-sexp) 215 | (evil-normal-state))) 216 | (define-key evil-normal-state-map (kbd "(") (bind 217 | (evil-append 1) 218 | (sp-beginning-of-previous-sexp) 219 | (evil-normal-state))) 220 | (define-key evil-normal-state-map (kbd "M-j") (bind 221 | (evil-append 1) 222 | (sp-down-sexp) 223 | (evil-normal-state))) 224 | (define-key evil-normal-state-map (kbd "M-k") (bind 225 | (sp-backward-up-sexp))) 226 | ;; (define-key evil-normal-state-map (kbd "< I") (bind 227 | ;; (sp-beginning-of-sexp) 228 | ;; (evil-insert 1))) 229 | ;; (evil-define-key 'normal evil-normal-state-map 230 | ;; (kbd "< I") (bind (sp-beginning-of-sexp) 231 | ;; (evil-insert 1))) 232 | 233 | ;; expression evaluation 234 | 235 | ;; emacs lisp 236 | (after 'elisp-slime-nav-autoloads 237 | (evil-define-key 'normal emacs-lisp-mode-map 238 | (kbd "gd") 'elisp-slime-nav-find-elisp-thing-at-point 239 | (kbd "K") 'elisp-slime-nav-describe-elisp-thing-at-point 240 | (kbd "") 'eval-defun 241 | (kbd "gX") 'eval-buffer) 242 | (evil-define-key 'visual emacs-lisp-mode-map 243 | (kbd "") 'eval-region)) 244 | 245 | ;; clojure / cider 246 | (evil-define-key 'normal clojure-mode-map 247 | (kbd "gd") 'cider-jump 248 | (kbd "K") 'cider-doc 249 | (kbd "gK") 'cider-javadoc 250 | ;Evaluate the current toplevel form. PREFIX => print in buffer. 251 | (kbd "") 'cider-eval-defun-at-point 252 | (kbd "gX") 'cider-eval-buffer) 253 | (evil-define-key 'visual clojure-mode-map 254 | (kbd "") 'cider-eval-region) 255 | (evil-define-key 'normal cider-repl-mode-map (kbd "gK") 'cider-javadoc) 256 | (evil-define-key 'normal cider-mode-map (kbd "gK") 'cider-javadoc) 257 | 258 | (after 'company 259 | (define-key evil-insert-state-map (kbd "") 'company-complete-common) 260 | (define-key evil-insert-state-map (kbd "") 'company-complete-common) 261 | (define-key company-active-map (kbd "") 'company-complete-common) 262 | (define-key company-active-map (kbd "C-n") 'company-select-next) 263 | (define-key company-active-map (kbd "C-p") 'company-select-previous)) 264 | 265 | (define-key evil-visual-state-map "m" 'er/expand-region) 266 | (define-key evil-visual-state-map (kbd "M-m") nil) 267 | (define-key evil-visual-state-map (kbd "M-m") (lambda () 268 | (interactive) 269 | (er/expand-region -1))) 270 | 271 | (after 'magit 272 | (evil-add-hjkl-bindings magit-status-mode-map 'emacs 273 | "l" 'magit-key-mode-popup-logging 274 | "h" 'magit-toggle-diff-refine-hunk) 275 | (evil-define-key 'normal magit-status-mode-map 276 | (kbd "[ c") 'magit-goto-previous-section 277 | (kbd "] c") 'magit-goto-next-section)) 278 | (evil-define-key 'normal diff-mode-map 279 | (kbd "[ c") 'diff-hunk-prev 280 | (kbd "] c") 'diff-hunk-next) 281 | 282 | ;; minibuffer keymaps 283 | ;; esc key 284 | (define-key minibuffer-local-map [escape] 'my-minibuffer-keyboard-quit) 285 | (define-key minibuffer-local-ns-map [escape] 'my-minibuffer-keyboard-quit) 286 | (define-key minibuffer-local-completion-map [escape] 'my-minibuffer-keyboard-quit) 287 | (define-key minibuffer-local-must-match-map [escape] 'my-minibuffer-keyboard-quit) 288 | (define-key minibuffer-local-isearch-map [escape] 'my-minibuffer-keyboard-quit)) 289 | 290 | ;; other 291 | (define-key minibuffer-local-map (kbd "C-w") 'backward-kill-word) 292 | (define-key minibuffer-local-map (kbd "C-u") 'backward-kill-sentence) 293 | 294 | (after 'comint 295 | (define-key comint-mode-map [up] 'comint-previous-input) 296 | (define-key comint-mode-map [down] 'comint-next-input)) 297 | 298 | ;; mouse scrolling in terminal 299 | (unless (display-graphic-p) 300 | (global-set-key [mouse-4] (lambda () (interactive) (scroll-down 1))) 301 | (global-set-key [mouse-5] (lambda () (interactive) (scroll-up 1)))) 302 | 303 | 304 | ;; have no use for these default bindings 305 | (global-unset-key (kbd "C-x m")) 306 | (global-set-key (kbd "C-x C-c") (bind (message "Thou shall not quit!"))) 307 | (global-set-key (kbd "C-x r q") 'save-buffers-kill-terminal) 308 | 309 | (provide 'init-bindings) 310 | -------------------------------------------------------------------------------- /.emacs.d/elisp/init-core.el: -------------------------------------------------------------------------------- 1 | (setq inhibit-splash-screen t 2 | inhibit-startup-echo-area-message t 3 | inhibit-startup-message t 4 | suggest-key-bindings nil) 5 | 6 | ;; relax the GC frequency 7 | (setq gc-cons-threshold 20000000) 8 | 9 | (setq load-prefer-newer t) 10 | 11 | (setq custom-file (concat user-emacs-directory "custom.el")) 12 | (when (file-exists-p custom-file) 13 | (load custom-file)) 14 | 15 | 16 | ;; move cursor to the last position upon open 17 | (require 'saveplace) 18 | (setq save-place-file (concat user-emacs-directory ".cache/places")) 19 | (setq-default save-place t) 20 | 21 | 22 | ;; minibuffer history 23 | (require 'savehist) 24 | (setq savehist-file (concat user-emacs-directory ".cache/savehist") 25 | savehist-additional-variables '(search ring regexp-search-ring) 26 | savehist-autosave-interval 60) 27 | (savehist-mode +1) 28 | 29 | 30 | ;; recent files 31 | (require 'recentf) 32 | (setq recentf-save-file (concat user-emacs-directory ".cache/recentf") 33 | recentf-max-saved-items 1000 34 | recentf-max-menu-items 500) 35 | (recentf-mode +1) 36 | 37 | 38 | ;; eshell 39 | (setq eshell-directory-name (concat user-emacs-directory ".cache/eshell")) 40 | (setq eshell-aliases-file (concat user-emacs-directory ".eshell-aliases")) 41 | 42 | 43 | ;; erc 44 | (setq erc-log-channels-directory (concat user-emacs-directory ".cache/erc/logs")) 45 | 46 | 47 | ;; vc 48 | (setq vc-make-backup-files t) 49 | 50 | ;; narrowing 51 | (put 'narrow-to-region 'disabled nil) 52 | 53 | ;; dired 54 | (require 'dired-x) 55 | 56 | ;; ediff 57 | (setq ediff-split-window-function 'split-window-horizontally) 58 | 59 | 60 | ;; store most files in the cache 61 | (setq backup-directory-alist 62 | `((".*" . ,(concat user-emacs-directory ".cache/backups"))) 63 | auto-save-file-name-transforms 64 | `((".*" ,(concat user-emacs-directory ".cache/backups") t)) 65 | auto-save-list-file-prefix 66 | (concat user-emacs-directory ".cache/auto-save-list/.saves-")) 67 | 68 | 69 | ;; better scrolling 70 | (setq scroll-conservatively 9999 71 | scroll-preserve-screen-position t) 72 | 73 | ;; better buffer names for duplicates 74 | (require 'uniquify) 75 | (setq uniquify-buffer-name-style 'forward 76 | uniquify-separator "/" 77 | uniquify-ignore-buffers-re "^\\*" ; leave special buffers alone 78 | uniquify-after-kill-buffer-p t) 79 | 80 | 81 | (defalias 'yes-or-no-p 'y-or-n-p) 82 | (xterm-mouse-mode t) 83 | 84 | 85 | (set-terminal-coding-system 'utf-8) 86 | (set-keyboard-coding-system 'utf-8) 87 | (set-selection-coding-system 'utf-8) 88 | (prefer-coding-system 'utf-8) 89 | 90 | (setq sentence-end-double-space nil 91 | mark-ring-max 64 92 | global-mark-ring-max 128 93 | save-interprogram-paste-before-kill t) 94 | 95 | ;; highlight entire sexp instead of just the parens. 96 | (show-paren-mode t) 97 | (setq show-paren-style 'expression) 98 | 99 | ;; layout 100 | (which-function-mode t) 101 | (global-visual-line-mode) 102 | (global-auto-revert-mode 1) 103 | (electric-indent-mode t) 104 | (blink-cursor-mode -1) 105 | (line-number-mode) 106 | (column-number-mode) 107 | (setq-default indent-tabs-mode nil) 108 | 109 | ;; editing 110 | (setq fill-column 80) 111 | 112 | (setq x-select-enable-clipboard t 113 | save-interprogram-paste-before-kill t 114 | ;; search everything, including noninteractive functions, non-customizable variables, ... 115 | apropos-do-all t 116 | ;; paste at cursor location instead of click location. 117 | mouse-yank-at-point t) 118 | 119 | ;; defer font-lock (improves scrolling speed, esp. for large files) 120 | (setq jit-lock-defer-time 0.05) 121 | 122 | (add-hook 'find-file-hook 123 | (lambda () 124 | ;; disable word-wrap by default 125 | (setq truncate-lines t) 126 | (setq truncate-partial-width-windows nil) 127 | ;; highlight trailing whitespace in files _only_ 128 | (setq show-trailing-whitespace t))) 129 | 130 | ;; disable expensive features for very large files 131 | ;; http://stackoverflow.com/a/18317181/152142 132 | (defun my-large-file-on_enter-hook () 133 | "If a file is over a given size, make the buffer read only." 134 | (when (> (buffer-size) (* 1024 1024)) 135 | (setq buffer-read-only t) 136 | (buffer-disable-undo) 137 | ;; (fundamental-mode) 138 | )) 139 | 140 | (add-hook 'find-file-hook 'my-large-file-on_enter-hook) 141 | 142 | 143 | (provide 'init-core) 144 | -------------------------------------------------------------------------------- /.emacs.d/elisp/init-util.el: -------------------------------------------------------------------------------- 1 | (defmacro after (feature &rest body) 2 | "After FEATURE (usually from a file 'FEATURE.el')is loaded, evaluate BODY." 3 | (declare (indent defun)) 4 | `(eval-after-load ,feature 5 | '(progn ,@body))) 6 | 7 | 8 | (defun describe-thing-in-popup () 9 | (interactive) 10 | (let* ((thing (symbol-at-point)) 11 | (help-xref-following t) 12 | (description (with-temp-buffer 13 | (help-mode) 14 | (help-xref-interned thing) 15 | (buffer-string)))) 16 | (pos-tip-show description 17 | :timeout -1))) 18 | 19 | (defun narrow-to-region-indirect (start end) ; http://demonastery.org/2013/04/emacs-narrow-to-region-indirect/ 20 | ; http://demonastery.org/2013/04/emacs-evil-narrow-region/ 21 | "Restrict editing in this buffer to the current region, indirectly." 22 | (interactive "r") 23 | (deactivate-mark) 24 | (let ((buf (clone-indirect-buffer nil nil))) 25 | (with-current-buffer buf 26 | (narrow-to-region start end)) 27 | (switch-to-buffer buf))) 28 | 29 | (defun my-minibuffer-keyboard-quit () 30 | "Abort recursive edit. 31 | In Delete Selection mode, if the mark is active, just deactivate it; 32 | then it takes a second \\[keyboard-quit] to abort the minibuffer." 33 | (interactive) 34 | (if (and delete-selection-mode transient-mark-mode mark-active) 35 | (setq deactivate-mark t) 36 | (when (get-buffer "*Completions*") (delete-windows-on "*Completions*")) 37 | (abort-recursive-edit))) 38 | 39 | (defun my-google () 40 | "Google the selected region if any, display a query prompt otherwise." 41 | (interactive) 42 | (browse-url 43 | (concat 44 | "http://www.google.com/search?ie=utf-8&oe=utf-8&q=" 45 | (url-hexify-string (if mark-active 46 | (buffer-substring (region-beginning) (region-end)) 47 | (read-string "Search Google: ")))))) 48 | 49 | (defun my-show-current-active-minor-modes () 50 | "List the current active minor modes." 51 | (interactive) 52 | (print (mapcar (lambda(x)(car(rassq x minor-mode-map-alist)))(current-minor-mode-maps)))) 53 | 54 | (defun my-eval-and-replace () 55 | "Replace the preceding sexp with its value." 56 | (interactive) 57 | (backward-kill-sexp) 58 | (condition-case nil 59 | (prin1 (eval (read (current-kill 0))) 60 | (current-buffer)) 61 | (error (message "Invalid expression") 62 | (insert (current-kill 0))))) 63 | 64 | (defun my-rename-current-buffer-file () 65 | "Renames current buffer and file it is visiting." 66 | (interactive) 67 | (let ((name (buffer-name)) 68 | (filename (buffer-file-name))) 69 | (if (not (and filename (file-exists-p filename))) 70 | (error "Buffer '%s' is not visiting a file!" name) 71 | (let ((new-name (read-file-name "New name: " filename))) 72 | (if (get-buffer new-name) 73 | (error "A buffer named '%s' already exists!" new-name) 74 | (rename-file filename new-name 1) 75 | (rename-buffer new-name) 76 | (set-visited-file-name new-name) 77 | (set-buffer-modified-p nil) 78 | (message "File '%s' successfully renamed to '%s'" 79 | name (file-name-nondirectory new-name))))))) 80 | 81 | 82 | (defun my-delete-current-buffer-file () 83 | "Removes file connected to current buffer and kills buffer." 84 | (interactive) 85 | (let ((filename (buffer-file-name)) 86 | (buffer (current-buffer)) 87 | (name (buffer-name))) 88 | (if (not (and filename (file-exists-p filename))) 89 | (ido-kill-buffer) 90 | (when (yes-or-no-p "Are you sure you want to remove this file? ") 91 | (delete-file filename) 92 | (kill-buffer buffer) 93 | (message "File '%s' successfully removed" filename))))) 94 | 95 | ;; https://snarfed.org/emacs-vc-git-tweaks 96 | (defun my-vc-git-command (verb fn) 97 | (let* ((fileset-arg (or vc-fileset (vc-deduce-fileset nil t))) 98 | (backend (car fileset-arg)) 99 | (files (nth 1 fileset-arg))) 100 | (if (eq backend 'Git) 101 | (progn (funcall fn files) 102 | (message (concat verb " " (number-to-string (length files)) 103 | " file(s)."))) 104 | (message "Not in a vc git buffer.")))) 105 | (defun my-vc-git-add (&optional revision vc-fileset comment) 106 | (interactive "P") 107 | (my-vc-git-command "Staged" 'vc-git-register)) 108 | (defun my-vc-git-reset (&optional revision vc-fileset comment) 109 | (interactive "P") 110 | (my-vc-git-command "Unstaged" 111 | (lambda (files) (vc-git-command nil 0 files "reset" "-q" "--")))) 112 | 113 | (provide 'init-util) 114 | -------------------------------------------------------------------------------- /.emacs.d/elisp/package-helper.el: -------------------------------------------------------------------------------- 1 | ;;; package-helper.el --- nice macros/functions for use with package 2 | ;;; https://github.com/skeeto/.emacs.d 3 | 4 | ;;; Commentary: 5 | 6 | ;; The two important macros are `with-package' and `with-package*'. 7 | ;; Package names given to these are automatically installed by 8 | ;; `package-install' and the body of these macros are not evaluated 9 | ;; until the listed packages are actually loaded, similar to 10 | ;; `eval-after-load'. The latter macro will automatically `require' 11 | ;; the listed packages. 12 | 13 | ;; Examples: 14 | 15 | ;; (with-package skewer-mode 16 | ;; ... ...) 17 | 18 | ;; (with-package (js2-mode less-css-mode) 19 | ;; ... ...) 20 | 21 | ;; To set up configuration after package has been activated but before 22 | ;; it has been loaded, append a * to the package name. It's useful for 23 | ;; adding keybindings to autoloaded functions. The macros provided 24 | ;; here are smart enough to find the real package name from the 25 | ;; special name. 26 | 27 | ;; Remember to call `package-initialize' in your config *before* 28 | ;; making use of these macros. 29 | 30 | ;;; Code: 31 | 32 | (require 'cl) 33 | (require 'package) 34 | 35 | (defvar package-blacklist () 36 | "List of packages that should never be installed.") 37 | 38 | (defun packagep (name) 39 | "Return t if NAME is an available package." 40 | (unless package-archive-contents 41 | (package-refresh-contents)) 42 | (not (null (assoc name package-archive-contents)))) 43 | 44 | (defun package-real-name (package) 45 | "PACKAGE may be the name of an autoloads; return the actual package name." 46 | (intern (replace-regexp-in-string "\\*$" "" (symbol-name package)))) 47 | 48 | (defun package-preload-p (package) 49 | "Return non-nil if PACKAGE is marked for preloading." 50 | (not (null (string-match-p "\\*$" (symbol-name package))))) 51 | 52 | (defmacro with-package (packages &rest body) 53 | "Like `eval-after-load', but also automatically register 54 | PACKAGES for installation by `package-install'. PACKAGES can be 55 | either a single symbol or a list of symbols. 56 | 57 | BODY is only ever evaluated once, and only after all PACKAGES 58 | have been loaded. This means if any of the listed packages are 59 | loaded, the others will be immediately loaded as well. 60 | 61 | The body is wrapped in a function so that it gets properly 62 | compiled. Normally with `eval-after-load' it gets quoted for a 63 | literal future `eval', so it appears as data to the compiler." 64 | (declare (indent defun)) 65 | (let ((has-run-sym (make-symbol "has-run-p")) 66 | (f-sym (make-symbol "f"))) 67 | (when (symbolp packages) 68 | (setf packages (list packages))) 69 | `(progn 70 | (setq ,has-run-sym nil) 71 | (fset ',f-sym (lambda () 72 | (unless ,has-run-sym 73 | (setq ,has-run-sym t) 74 | ,@(loop for package in packages collect 75 | `(require ',(package-real-name package))) 76 | ,@body))) 77 | ,@(loop for package in packages 78 | for real-name = (package-real-name package) 79 | collect `(when (and (not (member ',real-name package-blacklist)) 80 | (packagep ',real-name) 81 | (not (package-installed-p ',real-name))) 82 | (package-install ',real-name))) 83 | ,@(loop for package in packages 84 | when (package-preload-p package) 85 | collect `(eval-after-load 'emacs '(,f-sym)) 86 | else 87 | collect `(eval-after-load ',package '(,f-sym)))))) 88 | 89 | (defmacro with-package* (packages &rest body) 90 | "Like `with-package*' but also `require' all of the packages. 91 | This is mostly for code organization purposes." 92 | (declare (indent defun)) 93 | (when (symbolp packages) 94 | (setf packages (list packages))) 95 | `(progn 96 | (with-package ,packages ,@body) 97 | ,@(loop for package in packages 98 | collect `(require ',(package-real-name package))))) 99 | 100 | (font-lock-add-keywords 101 | 'emacs-lisp-mode 102 | '(("(\\(with-package\\*?\\)\\(?:\\s-+(?\\([^()]+\\))?\\)?" 103 | (1 'font-lock-keyword-face) 104 | (2 'font-lock-constant-face nil t)))) 105 | 106 | (provide 'package-helper) 107 | 108 | ;; Local Variables: 109 | ;; byte-compile-warnings: (not cl-functions) 110 | ;; End: 111 | 112 | ;;; package-helper.el ends here 113 | -------------------------------------------------------------------------------- /.emacs.d/init.el: -------------------------------------------------------------------------------- 1 | ;; Windows build (includes libxml2, gnutls, etc): 2 | ;; http://emacsbinw64.sourceforge.net/ 3 | ;; http://semantic.supelec.fr/popineau/programming-emacs.html 4 | ;; 5 | ;; use-package: https://github.com/vermiculus/dotfiles/blob/de9deb57317c7a10dd533e0e80a1d90a9b97f640/.emacs.d/init.el#L313 6 | ;; TODO: https://github.com/skeeto/.emacs.d#skewer 7 | 8 | (when (fboundp 'tool-bar-mode) (tool-bar-mode -1)) 9 | (when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1)) 10 | ;; disable menu except on Mac OS X 11 | (when (fboundp 'menu-bar-mode) (unless (and (window-system) (eq system-type 'darwin)) (menu-bar-mode -1))) 12 | 13 | (add-to-list 'load-path (concat user-emacs-directory "elisp")) 14 | 15 | (require 'package) 16 | (require 'package-helper) 17 | (setq package-archives 18 | '(("melpa" . "http://melpa.org/packages/") 19 | ("org" . "http://orgmode.org/elpa/") 20 | ("gnu" . "http://elpa.gnu.org/packages/"))) 21 | (setq package-enable-at-startup nil) 22 | (package-initialize) 23 | 24 | (require 'init-util) 25 | (require 'init-core) 26 | 27 | ;; VCS 28 | (with-package* (magit git-messenger) 29 | (setq magit-diff-options '("--histogram")) 30 | (setq git-messenger:show-detail t)) 31 | (if (display-graphic-p) 32 | (progn 33 | (with-package* git-gutter-fringe+ 34 | (git-gutter+-toggle-fringe))) 35 | (with-package git-gutter+* 36 | (after 'git-gutter+-autoloads 37 | (global-git-gutter+-mode)))) 38 | 39 | (with-package* (smart-mode-line moe-theme) 40 | ;; (with 'color-theme-sanityinc-tomorrow) 41 | ;; (with 'zenburn-theme) 42 | 43 | (moe-dark) 44 | (moe-theme-set-color 'w/b) 45 | 46 | (custom-set-faces 47 | ;; init file should contain only one custom-set-faces. If there is more than one, they won't work right. 48 | '(ac-selection-face ((t (:foreground "white" :background "DodgerBlue")))) 49 | '(cursor ((t (:foreground "white" :background "DodgerBlue")))) ;'(cursor ((t (:background "chartreuse")))) 50 | '(hl-line ((t (:inherit highlight :background "#333333")))) 51 | '(show-paren-match ((t (:background "#4e4e4e")))) 52 | '(sp-show-pair-match-face ((t (:underline "Green")))) 53 | '(vertical-border ((t (:background "#8a8a8a" :foreground "lemon chiffon"))))) 54 | 55 | ;; fight the "low contrast" fad. 56 | (set-face-attribute 'default nil 57 | :background "#1B1D1E" 58 | :foreground "white") 59 | 60 | (pcase (window-system) 61 | (`ns (set-face-attribute 'default nil :height 135)) 62 | (`w32 (set-face-attribute 'default nil 63 | :family "Consolas" :height 110))) 64 | 65 | (global-hl-line-mode +1) 66 | ) 67 | 68 | ;; shell 69 | ;; (with-package multi-term) 70 | ;; (setq multi-term-program "cmd.exe") 71 | 72 | (with-package exec-path-from-shell ;; make sure $PATH is set correctly 73 | (ignore-errors ;; windows 74 | (exec-path-from-shell-initialize))) 75 | 76 | ;; editor 77 | (with-package* undo-tree 78 | (setq undo-tree-auto-save-history t) 79 | (setq undo-tree-history-directory-alist 80 | `((,(concat user-emacs-directory ".cache/undo") . "."))) 81 | (global-undo-tree-mode)) 82 | 83 | (add-hook 'text-mode-hook 84 | '(lambda () 85 | (setq indent-tabs-mode nil) 86 | (setq tab-width 4) 87 | (setq indent-line-function 'insert-tab))) 88 | 89 | (with-package expand-region 90 | (setq expand-region-fast-keys-enabled nil)) 91 | 92 | (with-package highlight-parentheses 93 | (define-globalized-minor-mode global-highlight-parentheses-mode 94 | highlight-parentheses-mode 95 | (lambda () 96 | (highlight-parentheses-mode t))) 97 | (global-highlight-parentheses-mode t) 98 | ;; (add-hook 'find-file-hook 99 | ;; 'highlight-parentheses-mode 100 | ) 101 | 102 | (with-package* smartparens 103 | 104 | (setq sp-autoskip-closing-pair 'always 105 | sp-show-pair-delay 0 106 | sp-show-pair-from-inside t) 107 | 108 | (smartparens-global-mode t) 109 | (show-smartparens-global-mode) 110 | (show-paren-mode -1) ; not needed with smartparens 111 | 112 | (defun my-open-block-c-mode (id action context) 113 | (when (eq action 'insert) 114 | (newline) 115 | (indent-according-to-mode) 116 | (forward-line -1) ;(previous-line) 117 | (indent-according-to-mode))) 118 | 119 | ;; auto-pair {} and [] everywhere 120 | (sp-pair "{" nil :post-handlers '(:add (my-open-block-c-mode "RET"))) 121 | (sp-pair "[" nil :post-handlers '(:add (my-open-block-c-mode "RET"))) 122 | 123 | ;; http://stackoverflow.com/a/2665369/152142 124 | (add-hook 'minibuffer-setup-hook 'conditionally-enable-smartparens) 125 | (defun conditionally-enable-smartparens () 126 | "enable smartparens-mode during eval-expression" 127 | (if (eq this-command 'eval-expression) 128 | (smartparens-mode 1))) 129 | ) 130 | 131 | (with-package* (company pos-tip company-cider) 132 | (setq company-auto-complete t) 133 | (setq company-global-modes t) 134 | (setq company-idle-delay 0.2) 135 | (setq company-minimum-prefix-length 1) 136 | (setq company-show-numbers t) 137 | (setq company-tooltip-limit 30) 138 | (setq company-dabbrev-downcase nil) 139 | (setq company-dabbrev-ignore-case nil) 140 | 141 | (add-hook 'cider-repl-mode-hook (add-to-list 'company-backends 'company-cider)) 142 | (add-hook 'cider-mode-hook (add-to-list 'company-backends 'company-cider)) 143 | (after 'ac-js2-autoloads 144 | (add-to-list 'company-backends 'ac-js2-company)) 145 | 146 | (add-hook 'after-init-hook 'global-company-mode) 147 | 148 | (set-face-attribute 'company-tooltip nil :background "black" :foreground "white") 149 | (set-face-attribute 'company-tooltip-selection nil :inherit 'company-tooltip :background "DodgerBlue" :foreground "white") 150 | (set-face-attribute 'company-preview nil :background "black") 151 | (set-face-attribute 'company-preview-common nil :inherit 'company-preview :foreground "white") 152 | (set-face-attribute 'company-tooltip-common nil :inherit 'company-tooltip :foreground "green") 153 | (set-face-attribute 'company-tooltip-common-selection nil :inherit 'company-tooltip-selection :foreground "white") 154 | (set-face-attribute 'company-scrollbar-bg nil :inherit 'company-tooltip :background "gray20") 155 | (set-face-attribute 'company-scrollbar-fg nil :background "gray40") 156 | ) 157 | 158 | (with-package* (helm helm-config helm-swoop pt) 159 | ;; enable partial matches separated by SPC 160 | (helm-match-plugin-mode) 161 | 162 | (setq helm-command-prefix-key "C-c h") 163 | (setq helm-quick-update t) 164 | (setq helm-buffers-fuzzy-matching t)) 165 | 166 | ;; ido-mode 167 | (with-package* ido 168 | (setq ido-enable-prefix nil) 169 | (setq ido-use-virtual-buffers t) 170 | (setq ido-enable-flex-matching t) 171 | (setq ido-create-new-buffer 'prompt) 172 | (setq ido-use-filename-at-point 'guess) 173 | (setq ido-save-directory-list-file (concat user-emacs-directory ".cache/ido.last")) 174 | (ido-mode t) 175 | (ido-everywhere t)) 176 | (with-package ido-ubiquitous 177 | (ido-ubiquitous-mode t)) 178 | (with-package flx-ido 179 | (flx-ido-mode t)) 180 | (with-package* ido-vertical-mode 181 | (ido-vertical-mode)) 182 | (with-package* smex 183 | (setq smex-save-file (concat user-emacs-directory ".cache/smex-items")) 184 | (smex-initialize) 185 | (setq smex-history-length 100)) 186 | 187 | (with-package* speedbar 188 | (setq speedbar-show-unknown-files t) 189 | (add-hook 'speedbar-mode-hook 190 | (lambda () (setq truncate-lines t)))) 191 | 192 | (with-package flycheck* 193 | (after 'flycheck 194 | (setq flycheck-check-syntax-automatically '(save mode-enabled)) 195 | (setq flycheck-checkers (delq 'emacs-lisp-checkdoc flycheck-checkers)) 196 | (setq flycheck-checkers (delq 'html-tidy flycheck-checkers))) 197 | 198 | (global-flycheck-mode t)) 199 | 200 | (with-package (js2-mode* ac-js2 tern* tern-auto-complete jade-mode skewer-mode web-mode) 201 | (setq js2-highlight-level 3) 202 | (setq-default js2-basic-offset 2) 203 | (after 'js2-mode-autoloads 204 | (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))) 205 | (add-hook 'js2-mode-hook (lambda () (tern-mode t))) 206 | (after 'tern 207 | (after 'auto-complete 208 | (require 'tern-auto-complete) 209 | (tern-ac-setup))) 210 | 211 | (skewer-setup) 212 | 213 | (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))) 214 | 215 | (with-package (lua-mode flymake-lua)) 216 | 217 | (with-package* (elisp-slime-nav clojure-mode cider ac-cider) 218 | 219 | (defun my-lisp-hook () 220 | (progn 221 | (elisp-slime-nav-mode) 222 | (turn-on-eldoc-mode))) 223 | 224 | (add-hook 'emacs-lisp-mode-hook 'my-lisp-hook) 225 | (add-hook 'lisp-interaction-mode-hook 'my-lisp-hook) 226 | (add-hook 'ielm-mode-hook 'my-lisp-hook) 227 | (add-hook 'cider-mode-hook 'cider-turn-on-eldoc-mode) 228 | (add-hook 'cider-mode-hook 'ac-cider-setup) 229 | (add-hook 'cider-repl-mode-hook 'ac-cider-setup) 230 | 231 | (setq nrepl-buffer-name-show-port t) 232 | (setq cider-repl-history-file "~/.emacs.d/var/cider-repl-history") 233 | (setq cider-repl-history-size 2000) 234 | (setq cider-repl-popup-stacktraces t)) 235 | 236 | ; alternative: https://github.com/linktohack/evil-commentary 237 | (setq evilnc-hotkey-comment-operator "gc") ;must happen before (require 'evil-nerd-commenter) 238 | (with-package* (evil evil-rsi evil-visualstar evil-nerd-commenter evil-args evil-matchit evil-surround evil-jumper) 239 | (setq evil-want-C-u-scroll t) 240 | (setq evil-want-C-w-in-emacs-state t) 241 | 242 | (setq evil-search-module 'evil-search) 243 | (setq evil-magic 'very-magic) 244 | 245 | (setq evil-emacs-state-cursor '("red" box)) 246 | ;; (setq evil-normal-state-cursor '("green" box)) 247 | ;; (setq evil-insert-state-cursor '("orange" bar)) 248 | 249 | (evil-mode t) 250 | (global-evil-surround-mode 1) 251 | 252 | ;; enable evil-mode everywhere! 253 | ;; TODO: this is probably more reasonable: https://github.com/prooftechnique/.emacs.d/blob/master/config/jhenahan-evil.el 254 | ;; also: https://github.com/edwtjo/evil-org-mode 255 | (setq evil-normal-state-modes (append evil-emacs-state-modes evil-motion-state-modes)) 256 | (setq evil-emacs-state-modes nil) 257 | 258 | ;;remove RET and SPC from evil-motion-state-map so they are available directly for modes that define them. 259 | (defun my-move-key (keymap-from keymap-to key) 260 | "Moves key binding from one keymap to another and delete from the old location. " 261 | (define-key keymap-to key (lookup-key keymap-from key)) 262 | (define-key keymap-from key nil)) 263 | (my-move-key evil-motion-state-map evil-normal-state-map (kbd "RET")) 264 | (my-move-key evil-motion-state-map evil-normal-state-map " ") 265 | 266 | (defun my-send-string-to-terminal (string) 267 | (unless (display-graphic-p) (send-string-to-terminal string))) 268 | 269 | ) 270 | 271 | (require 'init-bindings) 272 | 273 | (with-package (markdown-mode ace-jump-mode)) 274 | 275 | (with-package* (restclient company-restclient)) 276 | 277 | (setq ring-bell-function 'ignore) 278 | ;;; flash top/bottom line only 279 | ; (setq visible-bell 'top/bottom) 280 | 281 | ;; session save/restore 282 | ;; TODO: this always complains about the lock file it _just_ created... 283 | ;; (desktop-save-mode 1) 284 | -------------------------------------------------------------------------------- /.gdbinit: -------------------------------------------------------------------------------- 1 | set history save on 2 | set trace-commands on 3 | set logging on 4 | set print pretty on 5 | set confirm off 6 | set pagination off 7 | # homebrew caveat 8 | set startup-with-shell off 9 | 10 | define r0 11 | target remote :6666 12 | break mcursor_check 13 | end 14 | define n0 15 | #break normal_execute 16 | break normal.c:964 17 | #break getchar.c:295 18 | run 19 | end 20 | define n1 21 | display curwin->w_cursor 22 | display get_inserted() 23 | end 24 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # * text=auto 2 | 3 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | # TODO: git 1.8 + encrypted .netrc: https://stackoverflow.com/a/16164673 2 | # TODO: git 2.23 has git blame --ignore-revs-file (cf. git-hyper-blame) 3 | # - can ignore "noise" commits 4 | # - can ignore changes that split/join/add/remove lines 5 | # - .gitconfig: `blame.ignoreRevsFile` works with fugitive 6 | [user] 7 | name = Justin M. Keyes 8 | #email = foo@bar.com 9 | [core] 10 | #editor = /foo/bar/nvim 11 | ignorecase = false 12 | autocrlf = false 13 | excludesfile = ~/.gitexcludes 14 | # recommended SHA minimum length https://lkml.org/lkml/2013/9/30/365 15 | abbrev = 12 16 | # Enable parallel index preload for some operations (diff, status). 17 | preloadindex = true 18 | # improve performance (requires msysgit 1.9.4+) 19 | fscache = true 20 | # set tab width for pager (affects 'git diff') 21 | pager = less -x1,5 22 | trustctime = false 23 | askPass = 24 | [gui] 25 | gcwarning = false 26 | [branch] 27 | autosetuprebase = always 28 | [pull] 29 | rebase = true 30 | [push] 31 | default = current 32 | [diff] 33 | algorithm = patience 34 | [blame] 35 | markIgnoredLines = true 36 | markUnblamableLines = true 37 | [diff "sqlite3"] 38 | # To use this: 39 | # echo '*.db binary diff=sqlite3 merge=keepTheir' >> .gitattributes 40 | # https://stackoverflow.com/a/38271631 41 | textconv = "f() { sqlite3 -noheader -line \"$@\" .dump; }; f" 42 | binary = true 43 | [merge] 44 | tool = vimdiff 45 | [mergetool] 46 | prompt = false 47 | keepBackup = false 48 | [mergetool "vimdiff"] 49 | cmd = $EDITOR -d $BASE $LOCAL $REMOTE $MERGED -c '$wincmd w|only|diffoff!' 50 | [i18n] 51 | filesEncoding = utf-8 52 | [commit] 53 | status = false 54 | [alias] 55 | w = !git-when-merged --log 56 | rf = "!cd -- ${GIT_PREFIX:-.}; find . -maxdepth 3 -type d -name .git -exec echo 'repo: {}' \\; -exec git -C '{}' fetch --all --prune \\;" 57 | l = log -8 --graph --oneline --decorate 58 | ld = log -8 --graph --pretty=format:'%C(yellow)%h%C(bold black white)%d%Creset %s %C(bold green)%cr %Creset%C(white)%an' --abbrev-commit --date=relative 59 | ll = log --stat --decorate --source -p 60 | b = branch -vv 61 | # Recent branches. 62 | r = "!git branch --sort=-committerdate | head -n 10 ; git branch --sort=-committerdate -a | grep -E 'justinmk|origin' | grep -v 'HEAD' | sed 's,remotes/,,' | head -n 10" 63 | s = !git status -sb 64 | co = checkout 65 | rl = log --walk-reflogs --boundary --pretty=format:\"%ci %h %gd %gs\" 66 | ri = "!sh -c 't=\"${1:-master}\"; s=\"${2:-HEAD}\"; mb=\"$(git merge-base \"$t\" \"$s\")\"; if test \"x$mb\" = x ; then o=\"$t\"; else lm=\"$(git log -n1 --merges \"$t..$s\" --pretty=%H)\"; if test \"x$lm\" = x ; then o=\"$mb\"; else o=\"$lm\"; fi; fi; test $# -gt 0 && shift; test $# -gt 0 && shift; git rebase --interactive --keep-empty --autosquash \"$o\" \"$@\"'" 67 | [fetch] 68 | writeCommitGraph = true 69 | [advice] 70 | detachedHead = false 71 | statusHints = false 72 | skippedCherryPicks = false 73 | [feature] 74 | manyFiles = true 75 | [color] 76 | # default in Git ≥ 1.8.4 77 | ui = auto 78 | [color "branch"] 79 | current = bold white green 80 | local = bold yellow 81 | remote = bold magenta 82 | upstream = bold cyan 83 | [color "status"] 84 | # staged changes 85 | added = bold green 86 | updated = bold white green 87 | # un-staged changes 88 | changed = bold yellow 89 | untracked = bold cyan 90 | nobranch = bold red white 91 | [color "diff"] 92 | meta = bold cyan 93 | frag = bold magenta 94 | old = bold red 95 | new = bold green 96 | #NOTE: whitespace is highlighted only on new lines, not removed/old. 97 | #Use "git diff -R" to reverse the diff to see removed whitespace. 98 | whitespace = bold red white 99 | 100 | # See also: `includeIf` https://lobste.rs/s/dtrkna/#c_ipltmn 101 | # 102 | # ~/.gitconfig: 103 | # [includeIf "gitdir:~/foo/"] 104 | # path = .gitconfig_foo 105 | # 106 | # ~/.gitconfig_foo: 107 | # [user] 108 | # email = … 109 | # [core] 110 | # sshCommand = ssh -i ~/.ssh/id_…_foo -o 'IdentitiesOnly yes' 111 | [include] 112 | path = ~/.gitconfig.local 113 | -------------------------------------------------------------------------------- /.gitexcludes: -------------------------------------------------------------------------------- 1 | .gdb_history 2 | 3 | # Vim 4 | *.swp 5 | Session.vim 6 | 7 | # ignore ctags file, but not 'tags' directory 8 | tags 9 | !tags/ 10 | 11 | # OS-generated files 12 | .DS_Store 13 | .AppleDouble 14 | .LSOverride 15 | Thumbs.db 16 | Desktop.ini 17 | # Files that might appear on external disk 18 | .Spotlight-V100 19 | .Trashes 20 | # Directories potentially created on remote AFP share 21 | .AppleDB 22 | .AppleDesktop 23 | Network Trash Folder 24 | Temporary Items 25 | .apdisk 26 | 27 | # Visual Studio 28 | bin 29 | obj 30 | *.suo 31 | *.csproj.user 32 | 33 | # Compiled 34 | *.class 35 | *.o 36 | *.pyc 37 | *.so 38 | 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | -------------------------------------------------------------------------------- /.ideavimrc: -------------------------------------------------------------------------------- 1 | " https://github.com/JetBrains/ideavim#executing-ide-actions 2 | " Find IDE actions by name pattern: 3 | " :actionlist [pattern] 4 | 5 | set ignorecase 6 | set smartcase 7 | set hlsearch 8 | 9 | nnoremap z,al :actionlist 10 | 11 | nnoremap gqal :action ReformatCode 12 | nnoremap [q :action GotoPreviousError 13 | nnoremap ]q :action GotoNextError 14 | nnoremap g; :action JumpToLastChange 15 | nnoremap g, :action JumpToNextChange 16 | nnoremap + :action ToggleDistractionFreeMode 17 | nnoremap Y y$ 18 | 19 | " navigation 20 | " find actions... 21 | " SHIFT-SHIFT find anything 22 | nnoremap gO :action FileStructurePopup 23 | nnoremap gr :action ShowUsages 24 | nnoremap gD :action GotoImplementation 25 | nnoremap - :action SelectInProjectView 26 | 27 | " build/test 28 | nnoremap !t :action ShowRecentTests 29 | 30 | " debugger 31 | nnoremap :action EvaluateExpression 32 | nnoremap :action ToggleLineBreakpoint 33 | nnoremap :action StepOut 34 | nnoremap :action StepOver 35 | nnoremap :action Resume 36 | nnoremap :action Resume 37 | nnoremap :action Debugger.FramePanelPopup 38 | nnoremap :action StepInto 39 | nnoremap :action SmartStepInto 40 | nnoremap :action JavaDebuggerActions 41 | -------------------------------------------------------------------------------- /.lldbinit: -------------------------------------------------------------------------------- 1 | # NOTE: Use lldb from homebrew: 2 | # /usr/local/opt/llvm/bin/lldb 3 | 4 | # Give ~/bin/*.py precedence in Python path: 5 | # script import os, sys 6 | # script sys.path[:0] = [os.path.expanduser('~/bin/')] 7 | # script import lldb_nvim 8 | 9 | # Example "pwd" command that runs Python: 10 | # command alias pwd script print os.getcwd() 11 | 12 | # Nvim 13 | # 14 | # Run nvim in separate terminal, then attach to its TUI process: 15 | # Terminal 1: 16 | # VIMRUNTIME=$HOME/dev/neovim/runtime/ ~/dev/neovim/build/bin/nvim --luamod-dev -c "call writefile([nvim_get_proc(getpid()).ppid], expand('/tmp/nvim.ppid'))" 17 | # Terminal 2: 18 | # /usr/local/opt/llvm/bin/lldb --attach-pid "$(cat /tmp/nvim.ppid)" ; kill "$(cat /tmp/nvim.ppid)"^C 19 | # 20 | # Run nvim when LLDB starts: 21 | # process launch -X true -- nvim --luamod-dev 22 | # 23 | # "runnvim" command 24 | command script import ~/bin/lldb_nvim.py 25 | command script add -f lldb_nvim.runnvim runnvim 26 | 27 | # 28 | # breakpoints: 29 | # 30 | # breakpoint set --name main 31 | # breakpoint set --name ex_detach 32 | -------------------------------------------------------------------------------- /.lynxrc: -------------------------------------------------------------------------------- 1 | accept_all_cookies=on 2 | force_ssl_cookies_secure=on 3 | 4 | case_sensitive_searching=off 5 | character_set=UNICODE (UTF-8) 6 | # If emacs_keys is to "on" then the normal EMACS movement keys: 7 | # ^N = down ^P = up 8 | # ^B = left ^F = right 9 | # will be enabled. 10 | emacs_keys=on 11 | 12 | file_editor=nvim 13 | 14 | # lineedit_mode specifies the key binding used for inputting strings in 15 | # prompts and forms. Current lineedit modes are: 16 | # Default Binding 17 | # Alternate Bindings 18 | # Bash-like Bindings 19 | lineedit_mode=Bash-like Bindings 20 | 21 | # preferred_charset specifies the character set in MIME notation (e.g., 22 | # ISO-8859-2, ISO-8859-5) which Lynx will indicate you prefer in requests 23 | # to http servers using an Accept-Charset header. The value should NOT 24 | # include ISO-8859-1 or US-ASCII, since those values are always assumed 25 | # by default. May be a comma-separated list. 26 | # If a file in that character set is available, the server will send it. 27 | # If no Accept-Charset header is present, the default is that any 28 | # character set is acceptable. If an Accept-Charset header is present, 29 | # and if the server cannot send a response which is acceptable 30 | # according to the Accept-Charset header, then the server SHOULD send 31 | # an error response, though the sending of an unacceptable response 32 | # is also allowed. 33 | preferred_charset= 34 | 35 | # preferred_language specifies the language in MIME notation (e.g., en, 36 | # fr, may be a comma-separated list in decreasing preference) 37 | # which Lynx will indicate you prefer in requests to http servers. 38 | # If a file in that language is available, the server will send it. 39 | # Otherwise, the server will send the file in its default language. 40 | preferred_language=en 41 | 42 | # select_popups specifies whether the OPTIONs in a SELECT block which 43 | # lacks a MULTIPLE attribute are presented as a vertical list of radio 44 | # buttons or via a popup menu. Note that if the MULTIPLE attribute is 45 | # present in the SELECT start tag, Lynx always will create a vertical list 46 | # of checkboxes for the OPTIONs. A value of "on" will set popup menus 47 | # as the default while a value of "off" will set use of radio boxes. 48 | # The default can be overridden via the -popup command line toggle. 49 | select_popups=on 50 | 51 | # show_color specifies how to set the color mode at startup. A value of 52 | # "never" will force color mode off (treat the terminal as monochrome) 53 | # at startup even if the terminal appears to be color capable. A value of 54 | # "always" will force color mode on even if the terminal appears to be 55 | # monochrome, if this is supported by the library used to build lynx. 56 | # A value of "default" will yield the behavior of assuming 57 | # a monochrome terminal unless color capability is inferred at startup 58 | # based on the terminal type, or the -color command line switch is used, or 59 | # the COLORTERM environment variable is set. The default behavior always is 60 | # used in anonymous accounts or if the "option_save" restriction is set. 61 | show_color=default 62 | 63 | show_cursor=on 64 | 65 | # user_mode specifies the users level of knowledge with Lynx. The 66 | # default is "NOVICE" which displays two extra lines of help at the 67 | # bottom of the screen to aid the user in learning the basic Lynx 68 | # commands. Set user_mode to "INTERMEDIATE" to turn off the extra info. 69 | # Use "ADVANCED" to see the URL of the currently selected link at the 70 | # bottom of the screen. 71 | user_mode=ADVANCED 72 | 73 | # If verbose_images is "on", lynx will print the name of the image 74 | # source file in place of [INLINE], [LINK] or [IMAGE] 75 | # See also VERBOSE_IMAGES in lynx.cfg 76 | verbose_images=on 77 | 78 | vi_keys=on 79 | 80 | visited_links=LAST_REVERSED 81 | 82 | -------------------------------------------------------------------------------- /.profile: -------------------------------------------------------------------------------- 1 | # .profile: for cases where .bash_profile is skipped 2 | 3 | if >/dev/null 2>&1 command -v nvim ; then 4 | export EDITOR=nvim 5 | export MANPAGER="nvim +Man!" 6 | elif >/dev/null 2>&1 command -v vim ; then 7 | export EDITOR=vim 8 | else 9 | export EDITOR=vi 10 | fi 11 | 12 | # msysgit bash runs .bashrc _and_ .bash_profile, so avoid redundant run. 13 | if ! [ "$MSYSTEM" = MINGW32 ] ; then 14 | # always run .bashrc; it checks the actual environment and reacts appropriately. 15 | [ -f "$HOME/.bashrc" ] && . "$HOME/.bashrc" 16 | fi 17 | 18 | -------------------------------------------------------------------------------- /.tmux.conf: -------------------------------------------------------------------------------- 1 | # Keymap quick-reference: 2 | # ! Break the current pane out of the window. 3 | # , Rename the current window. 4 | # M-Up/Down/Left/Right 5 | # Resize the current pane by 5 lines/columns. 6 | 7 | # Use "tmux-256color" if available, to enable more capabilities. 8 | if-shell 'infocmp tmux-256color' 'set -g default-terminal "tmux-256color"' 'set -g default-terminal "screen-256color"' 9 | 10 | set-option -g escape-time 2 11 | 12 | # Change prefix key to ALT-s. 13 | unbind-key C-b 14 | set-option -g prefix M-s 15 | 16 | # Toggle previous window. 17 | bind-key M-s last-window 18 | 19 | bind-key -n M-Left swap-window -t -1 20 | bind-key -n M-Right swap-window -t +1 21 | 22 | bind-key -n M-1 select-window -t :1 23 | bind-key -n M-2 select-window -t :2 24 | bind-key -n M-3 select-window -t :3 25 | bind-key -n M-4 select-window -t :4 26 | bind-key -n M-5 select-window -t :5 27 | bind-key -n M-6 select-window -t :6 28 | bind-key -n M-7 select-window -t :7 29 | bind-key -n M-8 select-window -t :8 30 | bind-key -n M-9 select-window -t :9 31 | 32 | bind-key -n M-h run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys M-h) || tmux select-pane -L" 33 | bind-key -n M-j run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys M-j) || tmux select-pane -D" 34 | bind-key -n M-k run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys M-k) || tmux select-pane -U" 35 | bind-key -n M-l run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys M-l) || tmux select-pane -R" 36 | 37 | set-option -g base-index 1 38 | 39 | set-option -g status-bg black 40 | set-option -g status-fg white 41 | 42 | set-window-option -g window-status-current-style bg=white,fg=black 43 | # Let programs like Vim try to set the terminal title. 44 | set-window-option -g set-titles on 45 | set-option -g status-right-length 120 46 | 47 | # tmux 1.7+: rename window to current directory tail. 48 | set-option -g status-interval 5 49 | set-option -g automatic-rename on 50 | set-option -g automatic-rename-format '#{b:pane_current_path}' 51 | 52 | # tmux 1.9+ 53 | set-option -g focus-events on 54 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | " Needed when running as `vi`. {{{ 2 | set nocp 3 | set hidden 4 | set background=dark 5 | set showcmd 6 | " }}} 7 | 8 | if has('vim_starting') 9 | " required for alt/meta mappings https://github.com/tpope/vim-sensible/issues/69 10 | set encoding=utf-8 11 | endif 12 | 13 | " win32 gvim 14 | if &rtp !~? '\v(('.escape(expand('~'), '/\').')|\~)[/\\]\.nvim' 15 | set runtimepath+=~/.config/nvim 16 | endif 17 | 18 | if 1 19 | let s:is_msysgit = (has('win32') || has('win64')) && $TERM ==? 'cygwin' 20 | let s:plugins = filereadable(expand("~/.config/nvim/autoload/plug.vim", 1)) 21 | let s:is_gui = has('gui_running') || strlen(&term) == 0 || &term ==? 'builtin_gui' 22 | endif 23 | 24 | 25 | " To map a 'meta' escape sequence in a terminal, you must map the literal control character. 26 | " insert-mode, type ctrl-v, then press alt+ (while in a terminal, not gvim). 27 | " http://vim.wikia.com/wiki/Mapping_fast_keycodes_in_terminal_Vim 28 | " http://stackoverflow.com/a/10633069/152142 29 | if 1 && !s:is_msysgit && !s:is_gui 30 | "avoid: m-b m-d m-f 31 | set =g =h =i =j =k =l =m =n =o =p =q =r =s =t =w =x =y =z =] =; 32 | endif 33 | 34 | if has('win32') 35 | autocmd GUIEnter * simalt ~x " always maximize initial GUI window 36 | 37 | set guifont=Consolas:h11 38 | if has("directx") 39 | set renderoptions=type:directx 40 | endif 41 | endif 42 | 43 | " sensible.vim {{{ 44 | 45 | " may affect performance: https://github.com/tpope/vim-sensible/issues/57 46 | " let &listchars = "tab:\u21e5 ,trail:\u2423,extends:\u21c9,precedes:\u21c7,nbsp:\u00b7" 47 | " let &showbreak="\u21aa" " precedes line wrap 48 | set listchars=tab:>\ ,trail:-,nbsp:+ 49 | 50 | "transient dirs 51 | if 1 52 | let s:dir = '~/.local/share/vim' 53 | let &directory = expand(s:dir, 1).'/swap//,'.&directory 54 | if has("persistent_undo") 55 | let &undodir = expand(s:dir, 1).'/undo//,'.&undodir 56 | endif 57 | endif 58 | 59 | set hidden 60 | set ttimeout 61 | set ttimeoutlen=100 62 | set backspace=eol,start,indent 63 | set wildmenu 64 | set display+=lastline 65 | set viminfo^=! 66 | set sessionoptions-=options 67 | 68 | if v:version > 703 || v:version == 703 && has("patch541") 69 | set formatoptions+=j " Delete comment character when joining commented lines 70 | endif 71 | setglobal tags-=./tags tags-=./tags; tags^=./tags; 72 | 73 | set autoindent " Note: 'smartindent' is deprecated by 'cindent' and 'indentexpr'. 74 | set complete-=i " Don't scan includes (tags file is more performant). 75 | set smarttab " Use 'shiftwidth' when using in front of a line. 76 | 77 | set incsearch 78 | set hlsearch " highlight search matches 79 | 80 | set autoread 81 | 82 | " Load matchit.vim, but only if the user hasn't installed a newer version. 83 | if 1 && !exists('g:loaded_matchit') && findfile('plugin/matchit.vim', &rtp) ==# '' 84 | runtime! macros/matchit.vim 85 | endif 86 | 87 | " Allow color schemes to do bright colors without forcing bold. 88 | if &t_Co == 8 && $TERM !~# '^linux' 89 | set t_Co=16 90 | endif 91 | 92 | set nrformats-=octal 93 | set laststatus=2 94 | set history=10000 95 | 96 | if !s:plugins 97 | if has('syntax') && !exists('g:syntax_on') 98 | syntax enable 99 | endif 100 | filetype plugin indent on 101 | endif 102 | 103 | " }}} sensible.vim 104 | 105 | -------------------------------------------------------------------------------- /.vrapperrc: -------------------------------------------------------------------------------- 1 | " vrapper 2 | " set global shortcut in Eclipse options: 3 | " Activate Editor => Esc 4 | " syntax colors: "MoonRise UI Theme" 5 | " http://guari.github.io/eclipse-ui-theme/ 6 | 7 | set ignorecase 8 | set smartcase 9 | set incsearch 10 | set tabstop=4 11 | set shiftwidth=4 12 | 13 | inoremap z, 14 | inoremap z,p " 15 | 16 | nnoremap \ , 17 | nnoremap gj ik$ 18 | nnoremap s / 19 | nnoremap S ? 20 | nnoremap zy zt5 21 | nnoremap gw 22 | nnoremap d :bdelete 23 | nnoremap 24 | nnoremap 25 | nnoremap z. :w 26 | 27 | nnoremap vd "_d 28 | vnoremap x "_d 29 | nnoremap vD "_D 30 | vnoremap P "0p 31 | nnoremap =p op== 32 | nnoremap =P Op== 33 | vnoremap Y "+y 34 | 35 | nnoremap :nohlsearch 36 | vnoremap - $ 37 | nnoremap - $ 38 | nnoremap gl :ls 39 | " select last inserted text 40 | nnoremap gV `[v`] 41 | 42 | nnoremap n. 43 | nnoremap Q @@ 44 | 45 | nnoremap ]e :.,.m.+1 46 | nnoremap [e :.,.m.-2 47 | vnoremap ]e :m.+1gv 48 | vnoremap [e :m.-2kgv 49 | 50 | eclipseaction eclipsenextitem org.eclipse.ui.navigate.next 51 | nnoremap ]q :eclipsenextitem 52 | eclipseaction eclipsepreviousitem org.eclipse.ui.navigate.previous 53 | nnoremap [q :eclipsepreviousitem 54 | 55 | nnoremap Y y$ 56 | 57 | " vrapper 58 | " http://evans-stuff.blogspot.com/2007/10/it-seems-that-im-not-only-one-still.html 59 | " https://github.com/vrapper/vrapper/issues/265#issuecomment-22112349 60 | 61 | " expand region / doesn't work, the 'selection' is not a vrapper visual-selection 62 | " eclipseuiaction eclipseexpandregion org.eclipse.jdt.ui.edit.text.java.select.enclosing 63 | " vnoremap m :eclipseexpandregion 64 | 65 | " https://github.com/vrapper/vrapper/issues/352 66 | eclipseaction eclipsenextmember org.eclipse.jdt.ui.edit.text.java.goto.next.member 67 | nnoremap ]] :eclipsenextmember 68 | eclipseaction eclipseprevmember org.eclipse.jdt.ui.edit.text.java.goto.previous.member 69 | nnoremap [[ :eclipseprevmember 70 | 71 | " sexp motion 72 | " nice try but... no. 73 | " eclipseaction eclipsenextelement org.eclipse.jdt.ui.edit.text.java.select.next 74 | " nnoremap :eclipsenextelement 75 | " eclipseaction eclipseprevelement org.eclipse.jdt.ui.edit.text.java.select.previous 76 | " nnoremap :eclipseprevelement 77 | 78 | "version control 79 | eclipseaction eclipsecomparehead org.eclipse.egit.ui.team.CompareWithHead 80 | nnoremap Ud :eclipsecomparehead 81 | 82 | eclipseaction eclipsefindref org.eclipse.jdt.ui.edit.text.java.search.references.in.workspace 83 | nnoremap gr :eclipsefindref 84 | 85 | eclipseuiaction eclipsegotoimpl org.eclipse.jdt.ui.edit.text.java.open.implementation 86 | nnoremap gI :eclipsegotoimpl 87 | 88 | " show type hierarchy relative to current type 89 | eclipseuiaction eclipsetypehier org.eclipse.jdt.ui.edit.text.java.open.hierarchy 90 | nnoremap :eclipsetypehier 91 | 92 | " go to type 93 | eclipseuiaction eclipsegototype org.eclipse.jdt.ui.navigate.open.type 94 | nnoremap g/t :eclipsegototype 95 | 96 | " show documentation for current symbol 97 | eclipseuiaction eclipseshowdoc org.eclipse.ui.edit.text.showInformation 98 | nnoremap K :eclipseshowdoc 99 | 100 | " go to super implementation 101 | eclipseaction eclipsegotosuper org.eclipse.jdt.ui.edit.text.java.open.super.implementation 102 | nnoremap gzi :eclipsegotosuper 103 | 104 | "show refactor menu 105 | eclipseaction eclipserefactormenu org.eclipse.jdt.ui.edit.text.java.refactor.quickMenu 106 | nnoremap crr :eclipserefactormenu 107 | vnoremap :eclipserefactormenugv 108 | 109 | "show code-generation menu 110 | eclipseaction eclipsesrcgenmenu org.eclipse.jdt.ui.edit.text.java.source.quickMenu 111 | nnoremap crs :eclipsesrcgenmenu 112 | vnoremap :eclipsesrcgenmenugv 113 | 114 | " rename current symbol 115 | eclipseaction eclipserename org.eclipse.jdt.ui.edit.text.java.rename.element 116 | au "Dart Editor" eclipseaction eclipserename com.google.dart.tools.ui.edit.text.dart.rename.element 117 | nnoremap crn :eclipserename 118 | 119 | "show quickfix menu 120 | eclipseuiaction eclipsequickfix org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals 121 | au "Dart Editor" eclipseuiaction eclipsequickfix com.google.dart.tools.ui.specific_content_assist.command 122 | nnoremap :eclipsequickfix 123 | vnoremap :eclipsequickfix 124 | 125 | au "Dart Editor" eclipseaction eclipsetogglecomment com.google.dart.tools.ui.edit.text.dart.toggle.comment 126 | au "Dart Editor" nnoremap gcc :eclipsetogglecomment 127 | au "Dart Editor" vnoremap gc :eclipsetogglecomment 128 | 129 | eclipseaction eclipsetogglebp org.eclipse.debug.ui.commands.ToggleBreakpoint 130 | nnoremap :eclipsetogglebp 131 | 132 | eclipseaction eclipseopenresource org.eclipse.ui.navigate.openResource 133 | nnoremap :eclipseopenresource 134 | 135 | " amazing 'omnibox' that searches buffers, commands, views, menus, preferences, etc. 136 | eclipseaction eclipsecmdsearch org.eclipse.ui.window.quickAccess 137 | nnoremap :eclipsecmdsearch 138 | 139 | " TODO: doesn't work, probably needs an argument 140 | " eclipseaction eclipseshowinpkgexplorer org.eclipse.ui.navigate.showIn 141 | " nnoremap ^ :eclipseshowinpkgexplorer 142 | 143 | " open file manager here (requires Eclipse 4.4/Luna) 144 | eclipseaction openfmhere org.eclipse.ui.ide.showInSystemExplorer 145 | nnoremap gof :openfmhere 146 | 147 | " open terminal here 148 | eclipseaction opentermhere com.tetrade.eclipse.plugins.easyshell.command.shellOpen 149 | nnoremap got :opentermhere 150 | 151 | nnoremap :vim 152 | set autochdir 153 | set cleanindent 154 | set contentassistmode 155 | set gvimpath=/usr/local/bin/mvim 156 | 157 | source .vrapperrc.local 158 | 159 | " vim: ft=vim 160 | -------------------------------------------------------------------------------- /.vsvimrc: -------------------------------------------------------------------------------- 1 | " Set global shortcut in Visual Studio options: 2 | " Window.ActivateDocumentWindow => Esc 3 | " External tool to open new Vim at current line: 4 | " gvim.exe $(ItemPath) +$(CurLine) 5 | " External tool to open in Vim server: 6 | " gvim.exe --servername vsvim --remote-silent $(ItemPath) 7 | " 8 | " nnoremap yx :vsc OtherContextMenus.FSIConsoleContext.ResetInteractiveSession 9 | " nnoremap !m :vsc OtherContextMenus.FSIConsoleContext.ResetInteractiveSessionvsc Build.BuildSelection 10 | 11 | set ignorecase 12 | set smartcase 13 | set incsearch 14 | set tabstop=4 15 | set shiftwidth=4 16 | set backspace=eol,start,indent 17 | set nostartofline 18 | set hlsearch 19 | set autoindent 20 | set expandtab 21 | set ttimeout 22 | set ttimeoutlen=50 23 | 24 | inoremap z, 25 | inoremap z,p " 26 | 27 | "horrible hack because VsVim refuses to fix this bug 28 | nnoremap g; u 29 | 30 | nnoremap \ , 31 | nnoremap gj ik$ 32 | nnoremap s / 33 | nnoremap S ? 34 | nnoremap zy zt5 35 | 36 | nnoremap gwo :vsc FullScreen 37 | nnoremap gws :vsc Window.Split 38 | nnoremap gwc :vsc Window.Split 39 | nnoremap d :vsc Window.CloseDocumentWindow 40 | nnoremap gwC :vsc Window.CloseDocumentWindow 41 | nnoremap gwH :vsc Window.MovetoPreviousTabGroup 42 | nnoremap gwL :vsc Window.MovetoNextTabGroup 43 | nnoremap gwS :vsc Window.NewHorizontalTabGroup 44 | nnoremap gwv :vsc Window.NewVerticalTabGroup 45 | nnoremap gwT :vsc Window.Float 46 | nnoremap gwj :vsc Window.NextSplitPane 47 | nnoremap gwk :vsc Window.PreviousSplitPane 48 | 49 | nnoremap 50 | nnoremap 51 | nnoremap z. :w 52 | 53 | nnoremap vd "_d 54 | xnoremap x "_d 55 | nnoremap vD "_D 56 | xnoremap P "0p 57 | nnoremap =p op== 58 | nnoremap =P Op== 59 | xnoremap Y "+y 60 | 61 | nnoremap :nohlsearch 62 | xnoremap - $ 63 | nnoremap - $ 64 | 65 | nnoremap n. 66 | nnoremap Q @@ 67 | 68 | nnoremap ]e :m+1 69 | nnoremap [e :m-2j 70 | xnoremap ]e :m'>+1gv 71 | xnoremap [e :m'<-2jgv 72 | 73 | nnoremap Y y$ 74 | 75 | nnoremap :vsc View.NavigateBackward 76 | nnoremap :vsc View.NavigateForward 77 | xnoremap gc :vsc Edit.CommentSelection 78 | nnoremap gcc V:vsc Edit.CommentSelection 79 | 80 | "version control 81 | nnoremap Ud :vsc Team.Git.CompareWithUnmodified 82 | nnoremap Us :vsc Team.Git.GoToGitChanges 83 | nnoremap ]c :vsc Diff.NextDifference 84 | nnoremap [c :vsc Diff.PreviousDifference 85 | 86 | " gs => expression manipulation 87 | " cr => refactor 88 | " g/ => navigation (search for files/symbols) 89 | " gk => inspection 90 | " g] => peek current symbol 91 | " ]I 92 | " ]d 93 | " debugging 94 | 95 | nnoremap gr :vsc Edit.FindAllReferences 96 | " go to the type of the current symbol 97 | nnoremap gD :vsc ReSharper.ReSharper_GotoTypeDeclaration 98 | nnoremap gI :vsc ReSharper.ReSharper_GotoImplementation 99 | nnoremap gI :vsc Edit.GoToImplementation 100 | " go to class member ("outline") 101 | nnoremap :vsc ReSharper.ReSharper_GotoFileMember 102 | 103 | " go to file 104 | nnoremap :vsc ReSharper.ReSharper_GotoFile 105 | " go to anything ("tags"/types/symbols/files) 106 | nnoremap g/t :vsc ReSharper.ReSharper_GotoType 107 | " grep everything 108 | nnoremap g// :vsc Edit.FindinFiles 109 | " find/replace in current buffer 110 | nnoremap g/r :vsc Edit.Replace 111 | nnoremap gl :vsc ReSharper.ReSharper_GotoRecentFiles 112 | 113 | nnoremap :vsc ReSharper.ReSharper_TypeHierarchy_Browse 114 | nnoremap K :vsc Edit.QuickInfo 115 | nnoremap :vsc ReSharper.ReSharper_InspectThis 116 | nnoremap gk :vsc Edit.PeekDefinition 117 | 118 | "show refactor menu 119 | nnoremap crr :vsc ReSharper.ReSharper_RefactorThis 120 | xnoremap :vsc ReSharper.ReSharper_RefactorThis 121 | nnoremap crn :vsc Refactor.Rename 122 | nnoremap cri :vsc EditorContextMenus.CodeWindow.OrganizeUsings.RemoveAndSort 123 | "show quickfix menu 124 | nnoremap :vsc ReSharper_AltEnter 125 | xnoremap :vsc ReSharper_AltEnter 126 | 127 | " expression manipulation 128 | nnoremap gst :vsc Edit.WordTranspose 129 | nnoremap gsh :vsc ReSharper.ReSharper_MoveLeft 130 | nnoremap gsl :vsc ReSharper.ReSharper_MoveRight 131 | nnoremap gsk :vsc ReSharper.ReSharper_MoveUp 132 | nnoremap gsj :vsc ReSharper.ReSharper_MoveDown 133 | 134 | " evaluate F# 135 | xnoremap :vsc EditorContextMenus.CodeWindow.ExecuteInInteractive 136 | nnoremap yxx ggVG:vsc EditorContextMenus.CodeWindow.ExecuteInInteractive 137 | nnoremap :vsc EditorContextMenus.CodeWindow.ExecuteLineInInteractive 138 | 139 | nnoremap ]q :vsc Edit.GoToNextLocation 140 | nnoremap [q :vsc Edit.GoToPrevLocation 141 | nnoremap ]l :vsc Edit.NextHighlightedReference 142 | nnoremap [l :vsc Edit.PreviousHighlightedReference 143 | 144 | " 'omnibox' 145 | nnoremap :vsc Window.QuickLaunch 146 | 147 | nnoremap :vsc Debug.ToggleBreakpoint 148 | nnoremap [o :vsc Debug.EnableAllBreakpoints 149 | nnoremap ]o :vsc Debug.DisableAllBreakpoints 150 | nnoremap da :vsc Debug.DeleteAllBreakpoints 151 | 152 | nnoremap @T :vsc TestExplorer.RepeatLastRun 153 | 154 | nnoremap q; :vsc View.C#Interactive 155 | nnoremap q: :vsc View.CommandWindow 156 | nnoremap q[ :vsc TestExplorer.ShowTestExplorer 157 | nnoremap q] :vsc View.ErrorList 158 | 159 | nnoremap gof :vsc File.OpenContainingFolder 160 | nnoremap got :vsc Tools.ExternalCommand2 161 | " toggle 'Track Active Item in Solution Explorer' option 162 | nnoremap cos :vsc View.TrackActivityinSolutionExplorer 163 | " highlight active file in Solution Explorer (VS 2012+) 164 | nnoremap ^ :vsc SolutionExplorer.SyncWithActiveDocument 165 | 166 | nnoremap cow :vsc Edit.ToggleWordWrap 167 | 168 | -------------------------------------------------------------------------------- /AppData/Local/nvim/init.vim: -------------------------------------------------------------------------------- 1 | source ~\.config\nvim\init.vim 2 | -------------------------------------------------------------------------------- /Library/Application Support/Code/User/keybindings.json: -------------------------------------------------------------------------------- 1 | // Place your key bindings in this file to override the defaultsauto[] 2 | [ 3 | { 4 | "key": "ctrl+[", 5 | "command": "workbench.action.focusActiveEditorGroup", 6 | "when": "!editorFocus" 7 | }, 8 | { 9 | "key": "Escape", 10 | "command": "workbench.action.focusActiveEditorGroup", 11 | "when": "!editorFocus" 12 | }, 13 | { 14 | "key": "down", 15 | "command": "workbench.action.debug.stepInto", 16 | "when": "debugState != 'inactive'" 17 | }, 18 | { 19 | "key": "up", 20 | "command": "workbench.action.debug.stepOut", 21 | "when": "debugState == 'stopped'" 22 | }, 23 | { 24 | "key": "right", 25 | "command": "workbench.action.debug.stepOver", 26 | "when": "debugState == 'stopped'" 27 | }, 28 | { 29 | "key": "left", 30 | "command": "workbench.action.debug.stepBack" 31 | }, 32 | { 33 | "key": "ctrl+=", 34 | "command": "workbench.action.toggleMaximizedPanel" 35 | }, 36 | { 37 | "key": "alt+q", 38 | "command": "workbench.actions.view.problems", 39 | "when": "workbench.panel.markers.view.active" 40 | }, 41 | { 42 | "key": "cmd+d", 43 | "command": "aws.dev.openMenu" 44 | }, 45 | { 46 | "key": "cmd+t", 47 | "command": "workbench.action.terminal.new", 48 | "when": "terminalProcessSupported || terminalWebExtensionContributedProfile" 49 | }, 50 | { 51 | "key": "cmd+l", 52 | "command": "aws.toolkit.viewLogs" 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /Library/Application Support/Code/User/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.minimap.enabled": false, 3 | "terminal.integrated.rendererType": "dom", 4 | "terminal.integrated.macOptionIsMeta": true, 5 | "files.insertFinalNewline": true, 6 | "vscode-neovim.revealCursorScrollLine": true, 7 | "vscode-neovim.neovimExecutablePaths.darwin": "/usr/local/bin/nvim", 8 | "vscode-neovim.mouseSelectionStartVisualMode": true, 9 | "vscode-neovim.mouseSelectionVisualMode": true, 10 | "editor.cursorBlinking": "expand", 11 | "editor.stickyScroll.enabled": true, 12 | "workbench.tree.enableStickyScroll": true, 13 | "window.zoomLevel": 1, 14 | "extensions.experimental.affinity": { 15 | "asvetliakov.vscode-neovim": 1 16 | }, 17 | "explorer.confirmDelete": false, 18 | "explorer.autoReveal": false, 19 | "editor.tokenColorCustomizations": { 20 | "comments": "#9f9f9f" 21 | }, 22 | "javascript.preferences.importModuleSpecifier": "relative", 23 | "typescript.preferences.importModuleSpecifier": "relative", 24 | "editor.renderWhitespace": "none", 25 | "githubPullRequests.remotes": [ 26 | "origin", 27 | "upstream", 28 | "public" 29 | ], 30 | "files.exclude": { 31 | "**/.classpath": true, 32 | "**/.project": true, 33 | "**/.settings": true, 34 | "**/.factorypath": true 35 | }, 36 | "search.exclude": { 37 | "**/.vscode-test-web/": true, 38 | "**/.vscode-test/": true, 39 | "**/aws-sam-cli-src/": true, 40 | "**/testFixtures/workspaceFolder/": true 41 | }, 42 | "go.toolsManagement.autoUpdate": true, 43 | "notebook.cellToolbarLocation": { 44 | "default": "right", 45 | "jupyter-notebook": "left" 46 | }, 47 | "redhat.telemetry.enabled": false, 48 | "editor.inlineSuggest.suppressSuggestions": true, 49 | "editor.inlineSuggest.showToolbar": "always", 50 | "window.density.editorTabHeight": "compact", 51 | "window.commandCenter": false, 52 | "diffEditor.hideUnchangedRegions.enabled": true, 53 | "terminal.integrated.shellIntegration.enabled": true, 54 | "git.openRepositoryInParentFolders": "never", 55 | "extensions.ignoreRecommendations": true, 56 | "remote.SSH.defaultExtensions": [ 57 | "amazonwebservices.aws-toolkit-vscode" 58 | ], 59 | "yaml.customTags": [ 60 | "!And", 61 | "!And sequence", 62 | "!If", 63 | "!If sequence", 64 | "!Not", 65 | "!Not sequence", 66 | "!Equals", 67 | "!Equals sequence", 68 | "!Or", 69 | "!Or sequence", 70 | "!FindInMap", 71 | "!FindInMap sequence", 72 | "!Base64", 73 | "!Join", 74 | "!Join sequence", 75 | "!Cidr", 76 | "!Ref", 77 | "!Sub", 78 | "!Sub sequence", 79 | "!GetAtt", 80 | "!GetAZs", 81 | "!ImportValue", 82 | "!ImportValue sequence", 83 | "!Select", 84 | "!Select sequence", 85 | "!Split", 86 | "!Split sequence" 87 | ], 88 | "aws.dev.forceDevMode": true, 89 | "_aws.dev.devenvTimeoutMs": 200, 90 | "_aws.dev.logfile": "~/awstoolkit.log", 91 | "_aws.dev.forceInstallTools": true, 92 | "aws.suppressPrompts": { 93 | "remoteConnected": true 94 | }, 95 | "_aws.suppressPrompts": { 96 | "remoteConnected": true, 97 | "ecsRunCommand": true, 98 | "codeWhispererNewWelcomeMessageKey": true, 99 | "codeWhispererNewWelcomeMessage": true, 100 | "amazonQWelcomePage": true 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Library/Preferences/kitty/kitty.conf: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=utf-8:ft=conf 2 | 3 | # https://sw.kovidgoyal.net/kitty/conf/ 4 | # https://sw.kovidgoyal.net/kitty/actions/#action-edit_config_file 5 | # 6 | # Reload config: ctrl+super+, 7 | 8 | # Allow "kitten @ foo" commands to work. 9 | # 10 | # Not needed, use printf to set the title: 11 | # printf "\033]0;xxx\007" 12 | # 13 | allow_remote_control no 14 | 15 | # On macOS kitty uses a non-interactive? shell which does not source .profile nor .bashrc. 16 | shell /usr/bin/env bash -l 17 | shell_integration no-cursor 18 | 19 | # Fix/augment $PATH. 20 | # Kitty always uses a "login shell" thus we need to append our extras here. 21 | # This especially matters for LAUNCH ACTIONS (`kitty/launch-actions.conf`). 22 | # exe_search_path +$HOME/bin 23 | # exe_search_path +/usr/local/bin 24 | env PATH=${PATH}:$HOME/bin:/usr/local/bin 25 | 26 | # Hide the kitty window's title bar on macOS. 27 | hide_window_decorations yes 28 | 29 | # Font family. You can also specify different fonts for the 30 | # bold/italic/bold-italic variants. By default they are derived automatically, 31 | # by the OSes font system. Setting them manually is useful for font families 32 | # that have many weight variants like Book, Medium, Thick, etc. For example: 33 | # font_family Operator Mono Book 34 | # bold_font Operator Mono Thick 35 | # bold_italic_font Operator Mono Medium 36 | # or 37 | # font_family SF Mono Medium 38 | # bold_font SF Mono Semibold 39 | # bold_italic_font SF Mono Semibold 40 | # Note that you should use the full family name but do not add Bold or Italic qualifiers 41 | # to the name. 42 | font_family Menlo Regular 43 | italic_font Menlo Italic 44 | bold_font Menlo Bold 45 | bold_italic_font Menlo Bold Italic 46 | 47 | # Font size (in pts) 48 | font_size 14.0 49 | 50 | 51 | # Adjust the line height. 52 | # You can use either numbers, which are interpreted as pixels or percentages 53 | # (number followed by %), which are interpreted as percentages of the 54 | # unmodified line height. You can use negative pixels or percentages less than 55 | # 100% to reduce line height (but this might cause rendering artifacts). 56 | adjust_line_height 0 57 | 58 | # The foreground color 59 | foreground #dddddd 60 | 61 | # The background color 62 | background #000000 63 | 64 | # The foreground for selections 65 | selection_foreground #000000 66 | 67 | # The background for selections 68 | selection_background #FFFACD 69 | 70 | # The color for highlighting URLs on mouse-over 71 | url_color #0087BD 72 | 73 | # Cursor color. none="reverse video" 74 | cursor green 75 | cursor_shape block 76 | cursor_shape_unfocused hollow 77 | # Blink interval (seconds). Zero=none. 78 | cursor_blink_interval 0 79 | # Stop blinking after the many seconds of keyboard inactivity. 80 | cursor_stop_blinking_after 15.0 81 | 82 | # Number of lines of history to keep in memory for scrolling back 83 | scrollback_lines 2000 84 | 85 | # Use Nvim to view kitty scrollback. 86 | scrollback_pager nvim --cmd 'set eventignore=FileType' +'nnoremap q ZQ' +'call nvim_open_term(0, {})' +'set nomodified nolist' +'$' - 87 | 88 | # Wheel scroll multiplier (modify the amount scrolled by the mouse wheel). Use negative 89 | # numbers to change scroll direction. 90 | wheel_scroll_multiplier 5.0 91 | 92 | # The interval between successive clicks to detect double/triple clicks (in seconds) 93 | click_interval 0.5 94 | 95 | # Characters considered part of a word when double clicking. In addition to these characters 96 | # any character that is marked as an alpha-numeric character in the unicode 97 | # database will be matched. 98 | select_by_word_characters :@-./_~?&=%+# 99 | 100 | # Hide mouse cursor after the specified number of seconds of the mouse not being used. Set to 101 | # zero to disable mouse cursor hiding. 102 | mouse_hide_wait 3.0 103 | 104 | # Set the active window to the window under the mouse when moving the mouse around 105 | focus_follows_mouse no 106 | 107 | # The enabled window layouts. A comma separated list of layout names. The special value * means 108 | # all layouts. The first listed layout will be used as the startup layout. 109 | # For a list of available layouts, see the file layouts.py 110 | enabled_layouts * 111 | 112 | # If enabled, the window size will be remembered so that new instances of kitty will have the same 113 | # size as the previous instance. If disabled, the window will initially have size configured 114 | # by initial_window_width/height, in pixels. 115 | remember_window_size yes 116 | initial_window_width 640 117 | initial_window_height 400 118 | 119 | # Delay (in milliseconds) between screen updates. Decreasing it, increases 120 | # frames-per-second (FPS) at the cost of more CPU usage. The default value 121 | # yields ~100 FPS which is more than sufficient for most uses. 122 | repaint_delay 10 123 | 124 | # Delay (in milliseconds) before input from the program running in the terminal 125 | # is processed. Note that decreasing it will increase responsiveness, but also 126 | # increase CPU usage and might cause flicker in full screen programs that 127 | # redraw the entire screen on each loop, because kitty is so fast that partial 128 | # screen updates will be drawn. 129 | input_delay 3 130 | 131 | # Visual bell duration. Flash the screen when a bell occurs for the specified number of 132 | # seconds. Set to zero to disable. 133 | visual_bell_duration 0.0 134 | 135 | # Enable/disable the audio bell. Useful in environments that require silence. 136 | enable_audio_bell yes 137 | 138 | # The program with which to open URLs that are clicked on. The special value "default" means to 139 | # use the operating system's default URL handler. 140 | open_url_with default 141 | 142 | # The value of the TERM environment variable to set 143 | term xterm-kitty 144 | 145 | # The width (in pts) of window borders. Will be rounded to the nearest number of pixels based on screen resolution. 146 | # Note that borders are displayed only when more than one window is visible. They are meant to separate multiple windows. 147 | window_border_width 1 148 | 149 | # The window margin (in pts) (blank area outside the border) 150 | window_margin_width 0 151 | 152 | # The window padding (in pts) (blank area between the text and the window border) 153 | window_padding_width 0 154 | 155 | # The color for the border of the active window 156 | active_border_color #00ff00 157 | 158 | # The color for the border of inactive windows 159 | inactive_border_color #cccccc 160 | 161 | # The 16 terminal colors. There are 8 basic colors, each color has a dull and 162 | # bright version. 163 | 164 | # black 165 | color0 #000000 166 | color8 #4d4d4d 167 | 168 | # red 169 | color1 #cc0403 170 | color9 #f2201f 171 | 172 | # green 173 | color2 #19cb00 174 | color10 #23fd00 175 | 176 | # yellow 177 | color3 #cecb00 178 | color11 #fffd00 179 | 180 | # blue 181 | color4 #0d73cc 182 | color12 #1a8fff 183 | 184 | # magenta 185 | color5 #cb1ed1 186 | color13 #fd28ff 187 | 188 | # cyan 189 | color6 #0dcdcd 190 | color14 #14ffff 191 | 192 | # white 193 | color7 #dddddd 194 | color15 #ffffff 195 | 196 | 197 | # Key mapping 198 | # For a list of key names, see: http://www.glfw.org/docs/latest/group__keys.html 199 | # For a list of modifier names, see: http://www.glfw.org/docs/latest/group__mods.html 200 | # 201 | # You can use the special action no_op to unmap a keyboard shortcut that is 202 | # assigned in the default configuration. 203 | # 204 | # You can combine multiple actions to be triggered by a single shortcut, using the 205 | # syntax below: 206 | # map key combine action1 action2 action3 ... 207 | # For example: 208 | # map ctrl+shift+e combine : new_window : next_layout 209 | # this will create a new window and switch to the next available layout 210 | 211 | # Clipboard 212 | map ctrl+shift+v paste_from_clipboard 213 | map ctrl+shift+c copy_to_clipboard 214 | 215 | # Clipboard (macOS) 216 | map super+v paste_from_clipboard 217 | map super+c copy_to_clipboard 218 | 219 | map shift+insert paste_from_selection 220 | # You can also pass the contents of the current selection to any program using 221 | # pass_selection_to_program. By default, the system's open program is used, but 222 | # you can specify your own, for example: 223 | # map ctrl+shift+o pass_selection_to_program firefox 224 | # map ctrl+shift+o pass_selection_to_program 225 | 226 | # Scrolling 227 | map page_up scroll_page_up 228 | map page_down scroll_page_down 229 | map super+home scroll_home 230 | map super+end scroll_end 231 | map super+/ show_scrollback 232 | 233 | # Window management 234 | map super+n new_window 235 | map cmd+w close_window_with_confirmation 236 | map super+j next_window 237 | map super+k previous_window 238 | # map ctrl+shift+1 first_window 239 | # map ctrl+shift+2 second_window 240 | # map ctrl+shift+3 third_window 241 | # map super+t launch --type=tab 242 | map super+shift+] next_layout 243 | map super+shift+[ last_used_layout 244 | map super+shift+. move_tab_forward 245 | map super+shift+, move_tab_backward 246 | # "zoom". https://sw.kovidgoyal.net/kitty/conf/#layout-managemene 247 | map super+z toggle_layout stack 248 | map super+left resize_window narrower 249 | map super+right resize_window wider 250 | map super+up resize_window taller 251 | map super+down resize_window shorter 252 | map super+shift+- start_resizing_window 253 | # reset all windows in the tab to default sizes 254 | map super+shift+= resize_window reset 255 | # Return to last-used tab. 256 | map ctrl+tab goto_tab -1 257 | map super+t new_tab 258 | # map super+` next_tab 259 | map super+] next_tab 260 | map super+[ previous_tab 261 | map super+1 goto_tab 1 262 | map super+2 goto_tab 2 263 | map super+3 goto_tab 3 264 | map super+4 goto_tab 4 265 | map super+5 goto_tab 5 266 | map super+6 goto_tab 6 267 | map super+7 goto_tab 7 268 | map super+8 goto_tab 8 269 | map super+9 goto_tab 9 270 | 271 | # Tabline/tabbar 272 | active_tab_foreground #000 273 | active_tab_background #eee 274 | inactive_tab_foreground #444 275 | inactive_tab_background #999 276 | tab_bar_style separator 277 | # tab_separator │ 278 | tab_title_template "{'Z' if layout_name == 'stack' else ''}{index}:{title[title.rfind('/')+1:]}" 279 | active_tab_font_style bold 280 | inactive_tab_foreground #999999 281 | inactive_tab_background black 282 | map super+. set_tab_title 283 | 284 | # You can also open a new window running an arbitrary program, for example: 285 | # map ctrl+shift+y new_window mutt 286 | # You can also pass the current selection to the new program by using the @selection placeholder 287 | # map ctrl+shift+y new_window less @selection 288 | # Finally, you can even send the contents of the current screen + history buffer as stdin using 289 | # the placeholders @text (which is the plain text) and @ansi (which includes text styling escape codes) 290 | # For example, the following command opens the scrollback buffer in less in a new window. 291 | # map ctrl+shift+y new_window @ansi less +G -R 292 | 293 | 294 | 295 | 296 | # Miscellaneous 297 | map ctrl+shift+equal increase_font_size 298 | map ctrl+shift+minus decrease_font_size 299 | map ctrl+shift+backspace restore_font_size 300 | 301 | # Sending arbitrary text on shortcut key presses 302 | # You can tell kitty to send arbitrary (UTF-8) encoded text to 303 | # the client program when pressing specified shortcut keys. For example: 304 | # send_text all ctrl+alt+a Special text 305 | # This will send "Special text" when you press the Ctrl+Alt+a key combination. 306 | # The text to be sent is a python string literal so you can use escapes like 307 | # \x1b to send control codes or \u21fb to send unicode characters (or you can 308 | # just input the unicode characters directly as UTF-8 text). The first argument 309 | # to send_text is the keyboard modes in which to activate the shortcut. The possible 310 | # values are normal or application or kitty or a comma separated combination of them. 311 | # The special keyword all means all modes. The modes normal and application refer to 312 | # the DECCKM cursor key mode for terminals, and kitty refers to the special kitty 313 | # extended keyboard protocol. Another example, that outputs a word and then moves the cursor 314 | # to the start of the line (same as pressing the Home key): 315 | # send_text normal ctrl+alt+a Word\x1b[H 316 | # send_text application ctrl+alt+a Word\x1bOH 317 | 318 | 319 | # 320 | # OS specific tweaks 321 | # 322 | macos_option_as_alt yes 323 | -------------------------------------------------------------------------------- /Library/Preferences/kitty/launch-actions.conf: -------------------------------------------------------------------------------- 1 | # Open directories 2 | protocol file 3 | mime inode/directory 4 | action launch --type=tab --cwd -- $FILE_PATH 5 | 6 | # Open executable file 7 | # protocol file 8 | # mime inode/executable,application/vnd.microsoft.portable-executable 9 | # action launch --hold --type=os-window -- $FILE_PATH 10 | 11 | # Open text files without fragments in the editor 12 | protocol file 13 | mime text/* 14 | action launch --type=tab -- $EDITOR -- $FILE_PATH 15 | 16 | # Open text files without fragments in the editor 17 | protocol file 18 | action launch --type=tab -- $EDITOR -- $FILE_PATH 19 | 20 | # Open image files with icat 21 | # protocol file 22 | # mime image/* 23 | # action launch --type=os-window kitten icat --hold -- $FILE_PATH 24 | -------------------------------------------------------------------------------- /bin/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Load my environment, without actually installing my junk into $HOME. 3 | 4 | # set -x 5 | set -e 6 | set -u 7 | set -o pipefail 8 | 9 | _SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 10 | [ -z "$_SCRIPT_DIR" ] && { echo 'error: invalid $_SCRIPT_DIR'; exit 1; } 11 | 12 | _REPO_DIR="$(cd "$_SCRIPT_DIR"/.. && pwd)" 13 | 14 | if ! [ -d "$_REPO_DIR" ] || ! 2>&1 >/dev/null grep justinmk/config "$_REPO_DIR"/.git/config ; then 15 | echo 'expected justinmk/config repo' 16 | exit 1 17 | fi 18 | 19 | # Start bash+tmux with cleared environment. 20 | # 21 | # Invoke bash with explicit env vars because: 22 | # - If tmux is already running, new sessions inherit THAT environment! 23 | # - "tmux set update-environment …" doesn't work at runtime. 24 | tmux source-file "${_REPO_DIR}/.tmux.conf" || true 25 | env -i HOME="$_REPO_DIR" PATH="${PATH:-}" DISPLAY="${DISPLAY:-}" LC_ALL="${LC_ALL:-}" LC_CTYPE="${LC_CTYPE:-}" LANG="${LANG:-}" TERM="$TERM" \ 26 | tmux new-session -E "HOME='$_REPO_DIR' bash -l" 27 | 28 | -------------------------------------------------------------------------------- /bin/git-when-merged: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- mode: python; coding: utf-8 -*- 3 | 4 | # Copyright (c) 2013 Michael Haggerty 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see 18 | 19 | # Run "git when-merged --help for the documentation. 20 | # See https://github.com/mhagger/git-when-merged for the project. 21 | 22 | """Find when a commit was merged into one or more branches. 23 | 24 | Find the merge commit that brought COMMIT into the specified 25 | BRANCH(es). Specifically, look for the oldest commit on the 26 | first-parent history of each BRANCH that contains the COMMIT as an 27 | ancestor. 28 | 29 | """ 30 | 31 | USAGE = r"""git when-merged [OPTIONS] COMMIT [BRANCH...] 32 | """ 33 | 34 | EPILOG = r""" 35 | Examples: 36 | git when-merged 0a1b # Find the merge commit that brought 37 | # commit 0a1b into the current branch 38 | git when-merged 0a1b v1.10 v1.11 # Find merge into given tags/branches 39 | git when-merged 0a1b -p feature-[0-9]+ # Specify tags/branches by regex 40 | git when-merged 0a1b -n releases # Use whenmerged.releases.pattern 41 | git when-merged 0a1b -s # Use whenmerged.default.pattern 42 | 43 | git when-merged -r 0a1b # If the commit was merged indirectly, 44 | # show each intermediate merge. 45 | git when-merged -l 0a1b # Show the log for the merge commit 46 | git when-merged -lb 0a1b # Show log for the whole merged branch 47 | git when-merged -v 0a1b # Visualize the merge commit in gitk 48 | git when-merged -vb 0a1b # Visualize the whole merged branch 49 | git when-merged -d 0a1b # Show the diff for the merge commit 50 | git when-merged -c 0a1b # Print only the merge's SHA-1 51 | 52 | Configuration: 53 | whenmerged..pattern 54 | Regular expressions that match reference names for the pattern 55 | called . A regexp is sought in the full reference name, 56 | in the form "refs/heads/master". This option can be multivalued, in 57 | which case references matching any of the patterns are considered. 58 | Typically the pattern will be chosen to match master and/or significant 59 | release branches or tags, or perhaps their remote-tracking equivalents. 60 | For example, 61 | 62 | git config whenmerged.default.pattern '^refs/heads/master$' 63 | git config --add whenmerged.default.pattern '^refs/heads/maint$' 64 | 65 | or 66 | 67 | git config whenmerged.releases.pattern '^refs/tags/release-' 68 | 69 | whenmerged.abbrev 70 | If this value is set to a positive integer, then Git SHA-1s are 71 | abbreviated to this number of characters (or longer if needed to 72 | avoid ambiguity). This value can be overridden using --abbrev=N 73 | or --no-abbrev. 74 | 75 | Originally based on: 76 | http://stackoverflow.com/questions/8475448/find-merge-commit-which-include-a-specific-commit 77 | """ 78 | 79 | import sys 80 | import re 81 | import subprocess 82 | import argparse 83 | 84 | 85 | if not (0x02060000 <= sys.hexversion): 86 | sys.exit('Python version 2.6 or later is required') 87 | 88 | 89 | # Backwards compatibility: 90 | try: 91 | from subprocess import CalledProcessError 92 | except ImportError: 93 | # Use definition from Python 2.7 subprocess module: 94 | class CalledProcessError(Exception): 95 | def __init__(self, returncode, cmd, output=None): 96 | self.returncode = returncode 97 | self.cmd = cmd 98 | self.output = output 99 | def __str__(self): 100 | return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) 101 | 102 | try: 103 | from subprocess import check_output 104 | except ImportError: 105 | # Use definition from Python 2.7 subprocess module: 106 | def check_output(*popenargs, **kwargs): 107 | if 'stdout' in kwargs: 108 | raise ValueError('stdout argument not allowed, it will be overridden.') 109 | process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) 110 | output, unused_err = process.communicate() 111 | retcode = process.poll() 112 | if retcode: 113 | cmd = kwargs.get("args") 114 | if cmd is None: 115 | cmd = popenargs[0] 116 | try: 117 | raise CalledProcessError(retcode, cmd, output=output) 118 | except TypeError: 119 | # Python 2.6's CalledProcessError has no 'output' kw 120 | raise CalledProcessError(retcode, cmd) 121 | return output 122 | 123 | 124 | class Failure(Exception): 125 | pass 126 | 127 | 128 | def _decode_output(value): 129 | """Decodes Git output into a unicode string. 130 | 131 | On Python 2 this is a no-op; on Python 3 we decode the string as 132 | suggested by [1] since we know that Git treats paths as just a sequence 133 | of bytes and all of the output we ask Git for is expected to be a file 134 | system path. 135 | 136 | [1] http://docs.python.org/3/c-api/unicode.html#file-system-encoding 137 | 138 | """ 139 | if sys.hexversion < 0x3000000: 140 | return value 141 | return value.decode(sys.getfilesystemencoding(), 'surrogateescape') 142 | 143 | 144 | def check_git_output(*popenargs, **kwargs): 145 | return _decode_output(check_output(*popenargs, **kwargs)) 146 | 147 | 148 | def read_refpatterns(name): 149 | key = 'whenmerged.%s.pattern' % (name,) 150 | try: 151 | out = check_git_output(['git', 'config', '--get-all', '--null', key]) 152 | except CalledProcessError: 153 | raise Failure('There is no configuration setting for %r!' % (key,)) 154 | retval = [] 155 | for value in out.split('\0'): 156 | if value: 157 | try: 158 | retval.append(re.compile(value)) 159 | except re.error as e: 160 | sys.stderr.write( 161 | 'Error compiling branch pattern %r; ignoring: %s\n' 162 | % (value, e.message,) 163 | ) 164 | return retval 165 | 166 | 167 | def iter_commit_refs(): 168 | """Iterate over the names of references that refer to commits. 169 | 170 | (This includes references that refer to annotated tags that refer 171 | to commits.)""" 172 | 173 | process = subprocess.Popen( 174 | [ 175 | 'git', 'for-each-ref', 176 | '--format=%(refname) %(objecttype) %(*objecttype)', 177 | ], 178 | stdout=subprocess.PIPE, 179 | ) 180 | for line in process.stdout: 181 | words = _decode_output(line).strip().split() 182 | refname = words.pop(0) 183 | if words == ['commit'] or words == ['tag', 'commit']: 184 | yield refname 185 | 186 | retcode = process.wait() 187 | if retcode: 188 | raise Failure('git for-each-ref failed') 189 | 190 | 191 | def matches_any(refname, refpatterns): 192 | return any( 193 | refpattern.search(refname) 194 | for refpattern in refpatterns 195 | ) 196 | 197 | 198 | def rev_parse(arg, abbrev=None): 199 | if abbrev: 200 | cmd = ['git', 'rev-parse', '--verify', '-q', '--short=%d' % (abbrev,), arg] 201 | else: 202 | cmd = ['git', 'rev-parse', '--verify', '-q', arg] 203 | 204 | try: 205 | return check_git_output(cmd).strip() 206 | except CalledProcessError: 207 | raise Failure('%r is not a valid commit!' % (arg,)) 208 | 209 | 210 | def rev_list(*args): 211 | """Iterate over (commit, [parent,...]) for the selected commits. 212 | 213 | args are passed as arguments to "git rev-list" to select which 214 | commits should be iterated over. 215 | 216 | """ 217 | 218 | process = subprocess.Popen( 219 | ['git', 'rev-list'] + list(args) + ['--'], 220 | stdout=subprocess.PIPE, 221 | ) 222 | for line in process.stdout: 223 | yield _decode_output(line).strip() 224 | 225 | retcode = process.wait() 226 | if retcode: 227 | raise Failure('git rev-list %s failed' % (' '.join(args),)) 228 | 229 | 230 | def rev_list_with_parents(*args): 231 | cmd = ['git', 'log', '--format=%H %P'] + list(args) + ['--'] 232 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE) 233 | for line in process.stdout: 234 | words = _decode_output(line).strip().split() 235 | yield (words[0], words[1:]) 236 | 237 | retcode = process.wait() 238 | if retcode: 239 | raise Failure('command "%s" failed' % (' '.join(cmd),)) 240 | 241 | 242 | class CommitGraph: 243 | def __init__(self, *args): 244 | self.commits = dict(rev_list_with_parents(*args)) 245 | 246 | def __contains__(self, commit): 247 | return commit in self.commits 248 | 249 | def __getitem__(self, commit): 250 | return self.commits[commit] 251 | 252 | def first_parent_path(self, commit): 253 | """Iterate over the commits in the first-parent ancestry of commit. 254 | 255 | Iterate over the commits that are within this CommitGraph that 256 | are also in the first-parent ancestry of the specified commit. 257 | commit must be a full 40-character SHA-1. 258 | 259 | """ 260 | 261 | while True: 262 | try: 263 | parents = self[commit] 264 | except KeyError: 265 | return 266 | yield commit 267 | if not parents: 268 | return 269 | commit = parents[0] 270 | 271 | 272 | class MergeNotFoundError(Exception): 273 | def __init__(self, refname): 274 | self.refname = refname 275 | 276 | 277 | class InvalidCommitError(MergeNotFoundError): 278 | msg = 'Is not a valid commit!' 279 | 280 | 281 | class DoesNotContainCommitError(MergeNotFoundError): 282 | msg = 'Does not contain commit.' 283 | 284 | 285 | class DirectlyOnBranchError(MergeNotFoundError): 286 | msg = 'Commit is directly on this branch.' 287 | 288 | 289 | class MergedViaMultipleParentsError(MergeNotFoundError): 290 | def __init__(self, refname, parents): 291 | MergeNotFoundError.__init__(self, refname) 292 | self.msg = 'Merged via multiple parents: %s' % (' '.join(parents),) 293 | 294 | 295 | def find_merge(commit, branch): 296 | """Return the SHA-1 of the commit that merged commit into branch. 297 | 298 | It is assumed that content is always merged in via the second or 299 | subsequent parents of a merge commit.""" 300 | 301 | try: 302 | branch_sha1 = rev_parse('%s^{commit}' % (branch,)) 303 | except Failure: 304 | raise InvalidCommitError(branch) 305 | 306 | commit_graph = CommitGraph('--ancestry-path', '%s..%s' % (commit, branch_sha1)) 307 | 308 | while True: 309 | branch_commits = list(commit_graph.first_parent_path(branch_sha1)) 310 | 311 | if not branch_commits: 312 | raise DoesNotContainCommitError(branch) 313 | 314 | # The last entry in branch_commits is the one that merged in 315 | # commit. 316 | last = branch_commits[-1] 317 | parents = commit_graph[last] 318 | 319 | if parents[0] == commit: 320 | raise DirectlyOnBranchError(branch) 321 | 322 | yield last 323 | 324 | if commit in parents: 325 | # The commit was merged in directly: 326 | return 327 | 328 | # Find which parent(s) merged in the commit: 329 | parents = [ 330 | parent 331 | for parent in parents 332 | if parent in commit_graph 333 | ] 334 | assert(parents) 335 | if len(parents) > 1: 336 | raise MergedViaMultipleParentsError(branch, parents) 337 | 338 | [branch_sha1] = parents 339 | 340 | 341 | def get_full_name(branch): 342 | """Return the full name of the specified commit. 343 | 344 | If branch is a symbolic reference, return the name of the 345 | reference that it refers to. If it is an abbreviated reference 346 | name (e.g., "master"), return the full reference name (e.g., 347 | "refs/heads/master"). Otherwise, just verify that it is valid, 348 | but return the original value.""" 349 | 350 | try: 351 | full = check_git_output( 352 | ['git', 'rev-parse', '--verify', '-q', '--symbolic-full-name', branch] 353 | ).strip() 354 | # The above call exits successfully, with no output, if branch 355 | # is not a reference at all. So only use the value if it is 356 | # not empty. 357 | if full: 358 | return full 359 | except CalledProcessError: 360 | pass 361 | 362 | # branch was not a reference, so just verify that it is valid but 363 | # leave it in its original form: 364 | rev_parse('%s^{commit}' % (branch,)) 365 | return branch 366 | 367 | 368 | FIRST_FORMAT = '%(refname)-38s %(sha1)s' 369 | OTHER_FORMAT = FIRST_FORMAT % dict(refname='', sha1='via %(sha1)s') 370 | 371 | COMMIT_FORMAT = '%(sha1)s' 372 | BRANCH_FORMAT = '%(sha1)s^1..%(sha1)s' 373 | 374 | WARN_FORMAT = '%(refname)-38s %(msg)s' 375 | 376 | 377 | def main(args): 378 | parser = argparse.ArgumentParser( 379 | prog='git when-merged', 380 | formatter_class=argparse.RawDescriptionHelpFormatter, 381 | description=__doc__, 382 | usage=USAGE, 383 | epilog=EPILOG, 384 | ) 385 | 386 | try: 387 | default_abbrev = int( 388 | check_git_output(['git', 'config', '--int', 'whenmerged.abbrev']).strip() 389 | ) 390 | except CalledProcessError: 391 | default_abbrev = None 392 | 393 | parser.add_argument( 394 | '--pattern', '-p', metavar='PATTERN', 395 | action='append', dest='patterns', default=[], 396 | help=( 397 | 'Show when COMMIT was merged to the references matching ' 398 | 'the specified regexp. If the regexp has parentheses for ' 399 | 'grouping, then display in the output the part of the ' 400 | 'reference name matching the first group.' 401 | ), 402 | ) 403 | parser.add_argument( 404 | '--name', '-n', metavar='NAME', 405 | action='append', dest='names', default=[], 406 | help=( 407 | 'Show when COMMIT was merged to the references matching the ' 408 | 'configured pattern(s) with the given name (see ' 409 | 'whenmerged..pattern below under CONFIGURATION).' 410 | ), 411 | ) 412 | parser.add_argument( 413 | '--default', '-s', 414 | action='append_const', dest='names', const='default', 415 | help='Shorthand for "--name=default".', 416 | ) 417 | parser.add_argument( 418 | '--recursive', '-r', 419 | action='store_true', 420 | help='Follow merges back recursively.', 421 | ) 422 | group = parser.add_mutually_exclusive_group() 423 | group.add_argument( 424 | '--show-commit', '-c', action='store_true', 425 | help=( 426 | 'Display only the SHA-1 of the merge commit. ' 427 | 'Exit with a nonzero exit code if the commit was not merged ' 428 | 'via a merge commit.' 429 | ), 430 | ) 431 | group.add_argument( 432 | '--show-branch', '-b', action='store_true', 433 | help=( 434 | 'Display the range of commits that were merged ' 435 | 'at the same time as the specified commit. ' 436 | 'Exit with a nonzero exit code if the commit was not merged ' 437 | 'via a merge commit. ' 438 | 'This option also affects the behavior of --log and ' 439 | '--visualize.' 440 | ), 441 | ) 442 | parser.add_argument( 443 | '--abbrev', metavar='N', 444 | action='store', type=int, default=default_abbrev, 445 | help=( 446 | 'Abbreviate commit SHA-1s to the specified number of characters ' 447 | '(or more if needed to avoid ambiguity). ' 448 | 'See also whenmerged.abbrev below under CONFIGURATION.' 449 | ), 450 | ) 451 | parser.add_argument( 452 | '--no-abbrev', dest='abbrev', action='store_const', const=None, 453 | help='Do not abbreviate commit SHA-1s.', 454 | ) 455 | parser.add_argument( 456 | '--log', '-l', action='store_true', default=False, 457 | help=( 458 | 'Show the log for the merge commit. ' 459 | 'When used with "--show-branch/-b", show the log for all of ' 460 | 'the commits that were merged at the same time as the specified ' 461 | 'commit.' 462 | ), 463 | ) 464 | parser.add_argument( 465 | '--diff', '-d', action='store_true', default=False, 466 | help='Show the diff for the merge commit.', 467 | ) 468 | parser.add_argument( 469 | '--visualize', '-v', action='store_true', default=False, 470 | help=( 471 | 'Visualize the merge commit using gitk. ' 472 | 'When used with "--show-branch/-b", only show the branch(es) ' 473 | 'that were merged at the same time as the specified commit.' 474 | ), 475 | ) 476 | parser.add_argument( 477 | 'commit', 478 | help='The commit whose destiny you would like to determine.', 479 | ) 480 | parser.add_argument( 481 | 'branch', nargs='*', 482 | help=( 483 | 'The destination branch(es) into which might have been ' 484 | 'merged. (Actually, BRANCH can be an arbitrary commit, specified ' 485 | 'in any way that is understood by git-rev-parse(1).) If neither ' 486 | ' nor --pattern/-p nor --default/-s is specified, then ' 487 | 'HEAD is used.' 488 | ), 489 | ) 490 | 491 | options = parser.parse_args(args) 492 | 493 | if options.abbrev is not None and options.abbrev <= 0: 494 | options.abbrev = None 495 | 496 | if options.show_commit: 497 | first_format = other_format = COMMIT_FORMAT 498 | warn = sys.exit 499 | elif options.show_branch: 500 | first_format = other_format = BRANCH_FORMAT 501 | warn = sys.exit 502 | else: 503 | first_format = FIRST_FORMAT 504 | other_format = OTHER_FORMAT 505 | warn = lambda msg: sys.stdout.write(msg + '\n') 506 | 507 | # Convert commit into a SHA-1: 508 | try: 509 | commit = rev_parse('%s^{commit}' % (options.commit,)) 510 | except Failure as e: 511 | sys.exit(e.message) 512 | 513 | refpatterns = [] 514 | 515 | for value in options.patterns: 516 | try: 517 | refpatterns.append(re.compile(value)) 518 | except re.error as e: 519 | sys.stderr.write( 520 | 'Error compiling pattern %r; ignoring: %s\n' 521 | % (value, e.message,) 522 | ) 523 | 524 | for value in options.names: 525 | try: 526 | refpatterns.extend(read_refpatterns(value)) 527 | except Failure as e: 528 | sys.exit(e.message) 529 | 530 | branches = set() 531 | 532 | if refpatterns: 533 | branches.update( 534 | refname 535 | for refname in iter_commit_refs() 536 | if matches_any(refname, refpatterns) 537 | ) 538 | 539 | for branch in options.branch: 540 | try: 541 | branches.add(get_full_name(branch)) 542 | except Failure as e: 543 | sys.exit(e.message) 544 | 545 | if not branches: 546 | branches.add(get_full_name('HEAD')) 547 | 548 | for branch in sorted(branches): 549 | first = True 550 | try: 551 | for sha1 in find_merge(commit, branch): 552 | if options.abbrev is not None: 553 | sha1 = rev_parse(sha1, abbrev=options.abbrev) 554 | 555 | if first: 556 | format = first_format 557 | else: 558 | format = other_format 559 | 560 | sys.stdout.write(format % dict(refname=branch, sha1=sha1) + '\n') 561 | 562 | if options.log: 563 | cmd = ['git', '--no-pager', 'log'] 564 | if options.show_branch: 565 | cmd += ['--topo-order', '%s^1..%s' % (sha1, sha1)] 566 | else: 567 | cmd += ['--no-walk', sha1] 568 | subprocess.check_call(cmd) 569 | 570 | if options.diff: 571 | cmd = ['git', '--no-pager', 'diff', '%s^1..%s' % (sha1, sha1)] 572 | subprocess.check_call(cmd) 573 | 574 | if options.visualize: 575 | cmd = ['gitk'] 576 | 577 | if options.show_branch: 578 | cmd += ['%s^1..%s' % (sha1, sha1)] 579 | cmd += ['--select-commit=%s' % (commit,)] 580 | else: 581 | cmd += ['--all'] 582 | cmd += ['--select-commit=%s' % (sha1,)] 583 | 584 | subprocess.check_call(cmd) 585 | 586 | if options.recursive: 587 | first = False 588 | else: 589 | break 590 | 591 | except DirectlyOnBranchError as e: 592 | if first: 593 | warn(WARN_FORMAT % dict(refname=e.refname, msg=e.msg)) 594 | except MergedViaMultipleParentsError as e: 595 | if first: 596 | warn(WARN_FORMAT % dict(refname=e.refname, msg=e.msg)) 597 | else: 598 | warn(WARN_FORMAT % dict(refname='', msg=e.msg)) 599 | except MergeNotFoundError as e: 600 | warn(WARN_FORMAT % dict(refname=e.refname, msg=e.msg)) 601 | except Failure as e: 602 | sys.exit('%s' % (e.message,)) 603 | 604 | 605 | main(sys.argv[1:]) 606 | 607 | -------------------------------------------------------------------------------- /bin/lldb_nvim.py: -------------------------------------------------------------------------------- 1 | import lldb 2 | import os 3 | 4 | def runnvim(debugger, command, exe_ctx, result, internal_dict): 5 | target = debugger.GetSelectedTarget() 6 | if target: 7 | process = target.GetProcess() 8 | if not process.IsValid(): # Check if a process is *already* associated 9 | # If not, create the process (launch nvim). 10 | launch_info = target.GetLaunchInfo() 11 | executable = target.GetExecutable() 12 | if executable.IsValid(): 13 | launch_info.SetExecutableFile(executable, True) 14 | else: 15 | print('Error: Invalid executable found') 16 | return 17 | 18 | # Set arguments. 19 | launch_info.SetArguments(['--luamod-dev'], False) 20 | 21 | # Set env vars. 22 | environment = lldb.SBEnvironment() 23 | environment.Set('VIMRUNTIME', os.path.expanduser('~/dev/neovim/runtime/'), True) 24 | launch_info.SetEnvironment(environment, True) 25 | 26 | error = lldb.SBError() 27 | process = debugger.GetSelectedTarget().Launch(launch_info, error) 28 | 29 | if error.Fail(): 30 | print(f'Process launch failed: {error.GetCString()}') 31 | return 32 | 33 | # print("nvim launched") 34 | 35 | # Now that the process is guaranteed to exist, set the breakpoint. 36 | bp = target.BreakpointCreateByName('os_exit') 37 | if not bp.IsValid(): 38 | print('Failed to set breakpoint.') 39 | 40 | process.Continue() 41 | 42 | else: 43 | print('No target found') 44 | -------------------------------------------------------------------------------- /bin/z.sh: -------------------------------------------------------------------------------- 1 | # https://github.com/rupa/z 2 | # Copyright (c) 2009 rupa deadwyler. Licensed under the WTFPL license, Version 2 3 | 4 | # maintains a jump-list of the directories you actually use 5 | # 6 | # INSTALL: 7 | # * put something like this in your .bashrc/.zshrc: 8 | # . /path/to/z.sh 9 | # * cd around for a while to build up the db 10 | # * PROFIT!! 11 | # * optionally: 12 | # set $_Z_CMD in .bashrc/.zshrc to change the command (default z). 13 | # set $_Z_DATA in .bashrc/.zshrc to change the datafile (default ~/.z). 14 | # set $_Z_MAX_SCORE lower to age entries out faster (default 9000). 15 | # set $_Z_NO_RESOLVE_SYMLINKS to prevent symlink resolution. 16 | # set $_Z_NO_PROMPT_COMMAND if you're handling PROMPT_COMMAND yourself. 17 | # set $_Z_EXCLUDE_DIRS to an array of directories to exclude. 18 | # set $_Z_OWNER to your username if you want use z while sudo with $HOME kept 19 | # 20 | # USE: 21 | # * z foo # cd to most frecent dir matching foo 22 | # * z foo bar # cd to most frecent dir matching foo and bar 23 | # * z -r foo # cd to highest ranked dir matching foo 24 | # * z -t foo # cd to most recently accessed dir matching foo 25 | # * z -l foo # list matches instead of cd 26 | # * z -e foo # echo the best match, don't cd 27 | # * z -c foo # restrict matches to subdirs of $PWD 28 | # * z -x # remove the current directory from the datafile 29 | # * z -h # show a brief help message 30 | 31 | [ -d "${_Z_DATA:-$HOME/.z}" ] && { 32 | echo "ERROR: z.sh's datafile (${_Z_DATA:-$HOME/.z}) is a directory." 33 | } 34 | 35 | _z() { 36 | 37 | local datafile="${_Z_DATA:-$HOME/.z}" 38 | 39 | # if symlink, dereference 40 | [ -h "$datafile" ] && datafile=$(readlink "$datafile") 41 | 42 | # bail if we don't own ~/.z and $_Z_OWNER not set 43 | [ -z "$_Z_OWNER" -a -f "$datafile" -a ! -O "$datafile" ] && return 44 | 45 | _z_dirs () { 46 | [ -f "$datafile" ] || return 47 | 48 | local line 49 | while read line; do 50 | # only count directories 51 | [ -d "${line%%\|*}" ] && echo "$line" 52 | done < "$datafile" 53 | return 0 54 | } 55 | 56 | # add entries 57 | if [ "$1" = "--add" ]; then 58 | shift 59 | 60 | # $HOME and / aren't worth matching 61 | [ "$*" = "$HOME" -o "$*" = '/' ] && return 62 | 63 | # don't track excluded directory trees 64 | if [ ${#_Z_EXCLUDE_DIRS[@]} -gt 0 ]; then 65 | local exclude 66 | for exclude in "${_Z_EXCLUDE_DIRS[@]}"; do 67 | case "$*" in "$exclude"*) return;; esac 68 | done 69 | fi 70 | 71 | # maintain the data file 72 | local tempfile="$datafile.$RANDOM" 73 | local score=${_Z_MAX_SCORE:-9000} 74 | _z_dirs | awk -v path="$*" -v now="$(date +%s)" -v score=$score -F"|" ' 75 | BEGIN { 76 | rank[path] = 1 77 | time[path] = now 78 | } 79 | $2 >= 1 { 80 | # drop ranks below 1 81 | if( $1 == path ) { 82 | rank[$1] = $2 + 1 83 | time[$1] = now 84 | } else { 85 | rank[$1] = $2 86 | time[$1] = $3 87 | } 88 | count += $2 89 | } 90 | END { 91 | if( count > score ) { 92 | # aging 93 | for( x in rank ) print x "|" 0.99*rank[x] "|" time[x] 94 | } else for( x in rank ) print x "|" rank[x] "|" time[x] 95 | } 96 | ' 2>/dev/null >| "$tempfile" 97 | # do our best to avoid clobbering the datafile in a race condition. 98 | if [ $? -ne 0 -a -f "$datafile" ]; then 99 | env rm -f "$tempfile" 100 | else 101 | [ "$_Z_OWNER" ] && chown $_Z_OWNER:"$(id -ng $_Z_OWNER)" "$tempfile" 102 | env mv -f "$tempfile" "$datafile" || env rm -f "$tempfile" 103 | fi 104 | 105 | # tab completion 106 | elif [ "$1" = "--complete" -a -s "$datafile" ]; then 107 | _z_dirs | awk -v q="$2" -F"|" ' 108 | BEGIN { 109 | q = substr(q, 3) 110 | if( q == tolower(q) ) imatch = 1 111 | gsub(/ /, ".*", q) 112 | } 113 | { 114 | if( imatch ) { 115 | if( tolower($1) ~ q ) print $1 116 | } else if( $1 ~ q ) print $1 117 | } 118 | ' 2>/dev/null 119 | 120 | else 121 | # list/go 122 | local echo fnd last list opt typ 123 | while [ "$1" ]; do case "$1" in 124 | --) while [ "$1" ]; do shift; fnd="$fnd${fnd:+ }$1";done;; 125 | -*) opt=${1:1}; while [ "$opt" ]; do case ${opt:0:1} in 126 | c) fnd="^$PWD $fnd";; 127 | e) echo=1;; 128 | h) echo "${_Z_CMD:-z} [-cehlrtx] args" >&2; return;; 129 | l) list=1;; 130 | r) typ="rank";; 131 | t) typ="recent";; 132 | x) sed -i -e "\:^${PWD}|.*:d" "$datafile";; 133 | esac; opt=${opt:1}; done;; 134 | *) fnd="$fnd${fnd:+ }$1";; 135 | esac; last=$1; [ "$#" -gt 0 ] && shift; done 136 | [ "$fnd" -a "$fnd" != "^$PWD " ] || list=1 137 | 138 | # if we hit enter on a completion just go there 139 | case "$last" in 140 | # completions will always start with / 141 | /*) [ -z "$list" -a -d "$last" ] && builtin cd "$last" && return;; 142 | esac 143 | 144 | # no file yet 145 | [ -f "$datafile" ] || return 146 | 147 | local cd 148 | cd="$( < <( _z_dirs ) awk -v t="$(date +%s)" -v list="$list" -v typ="$typ" -v q="$fnd" -F"|" ' 149 | function frecent(rank, time) { 150 | # relate frequency and time 151 | dx = t - time 152 | return int(10000 * rank * (3.75/((0.0001 * dx + 1) + 0.25))) 153 | } 154 | function output(matches, best_match, common) { 155 | # list or return the desired directory 156 | if( list ) { 157 | if( common ) { 158 | printf "%-10s %s\n", "common:", common > "/dev/stderr" 159 | } 160 | cmd = "sort -n >&2" 161 | for( x in matches ) { 162 | if( matches[x] ) { 163 | printf "%-10s %s\n", matches[x], x | cmd 164 | } 165 | } 166 | } else { 167 | if( common && !typ ) best_match = common 168 | print best_match 169 | } 170 | } 171 | function common(matches) { 172 | # find the common root of a list of matches, if it exists 173 | for( x in matches ) { 174 | if( matches[x] && (!short || length(x) < length(short)) ) { 175 | short = x 176 | } 177 | } 178 | if( short == "/" ) return 179 | for( x in matches ) if( matches[x] && index(x, short) != 1 ) { 180 | return 181 | } 182 | return short 183 | } 184 | BEGIN { 185 | gsub(" ", ".*", q) 186 | hi_rank = ihi_rank = -9999999999 187 | } 188 | { 189 | if( typ == "rank" ) { 190 | rank = $2 191 | } else if( typ == "recent" ) { 192 | rank = $3 - t 193 | } else rank = frecent($2, $3) 194 | if( $1 ~ q ) { 195 | matches[$1] = rank 196 | } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank 197 | if( matches[$1] && matches[$1] > hi_rank ) { 198 | best_match = $1 199 | hi_rank = matches[$1] 200 | } else if( imatches[$1] && imatches[$1] > ihi_rank ) { 201 | ibest_match = $1 202 | ihi_rank = imatches[$1] 203 | } 204 | } 205 | END { 206 | # prefer case sensitive 207 | if( best_match ) { 208 | output(matches, best_match, common(matches)) 209 | exit 210 | } else if( ibest_match ) { 211 | output(imatches, ibest_match, common(imatches)) 212 | exit 213 | } 214 | exit(1) 215 | } 216 | ')" 217 | 218 | if [ "$?" -eq 0 ]; then 219 | if [ "$cd" ]; then 220 | if [ "$echo" ]; then echo "$cd"; else builtin cd "$cd"; fi 221 | fi 222 | else 223 | return $? 224 | fi 225 | fi 226 | } 227 | 228 | alias ${_Z_CMD:-z}='_z 2>&1' 229 | 230 | [ "$_Z_NO_RESOLVE_SYMLINKS" ] || _Z_RESOLVE_SYMLINKS="-P" 231 | 232 | if type compctl >/dev/null 2>&1; then 233 | # zsh 234 | [ "$_Z_NO_PROMPT_COMMAND" ] || { 235 | # populate directory list, avoid clobbering any other precmds. 236 | if [ "$_Z_NO_RESOLVE_SYMLINKS" ]; then 237 | _z_precmd() { 238 | (_z --add "${PWD:a}" &) 239 | : $RANDOM 240 | } 241 | else 242 | _z_precmd() { 243 | (_z --add "${PWD:A}" &) 244 | : $RANDOM 245 | } 246 | fi 247 | [[ -n "${precmd_functions[(r)_z_precmd]}" ]] || { 248 | precmd_functions[$(($#precmd_functions+1))]=_z_precmd 249 | } 250 | } 251 | _z_zsh_tab_completion() { 252 | # tab completion 253 | local compl 254 | read -l compl 255 | reply=(${(f)"$(_z --complete "$compl")"}) 256 | } 257 | compctl -U -K _z_zsh_tab_completion _z 258 | elif type complete >/dev/null 2>&1; then 259 | # bash 260 | # tab completion 261 | complete -o filenames -C '_z --complete "$COMP_LINE"' ${_Z_CMD:-z} 262 | [ "$_Z_NO_PROMPT_COMMAND" ] || { 263 | # populate directory list. avoid clobbering other PROMPT_COMMANDs. 264 | grep "_z --add" <<< "$PROMPT_COMMAND" >/dev/null || { 265 | PROMPT_COMMAND="$PROMPT_COMMAND"$'\n''(_z --add "$(command pwd '$_Z_RESOLVE_SYMLINKS' 2>/dev/null)" 2>/dev/null &);' 266 | } 267 | } 268 | fi 269 | --------------------------------------------------------------------------------