From: Richard Hartmann Date: Sun, 27 Aug 2017 19:23:01 +0000 (+0200) Subject: Merge branch 'master' into completion-set-context-foreach-dispatch-v1 X-Git-Url: https://git.madduck.net/code/vcsh.git/commitdiff_plain/d3ff85c0d7594234d13a5256adaa2d77d7a7a4d6?hp=1a4ff3158b1034b51d102e7253115d514325c430 Merge branch 'master' into completion-set-context-foreach-dispatch-v1 --- diff --git a/_vcsh b/_vcsh index 96ae612..6880f72 100644 --- a/_vcsh +++ b/_vcsh @@ -95,6 +95,9 @@ function _vcsh () { local state vcshcommand local -a args subcommands + local VCSH_REPO_D + : ${VCSH_REPO_D:="${XDG_CONFIG_HOME:-"$HOME/.config"}/vcsh/repo.d"} + subcommands=( "clone:clone an existing repository" "commit:commit in all repositories" @@ -136,7 +139,7 @@ function _vcsh () { # There is no handler function, so this is probably the name # of a repository. Act accordingly. # FIXME: this may want to use '_dispatch vcsh git' - _dispatch git git + GIT_DIR=$VCSH_REPO_D/$words[1].git _dispatch git git else curcontext="${curcontext%:*:*}:vcsh-${vcshcommand}:" _call_function ret _vcsh-${vcshcommand} diff --git a/_vcsh_bash b/_vcsh_bash new file mode 100644 index 0000000..3cfe88a --- /dev/null +++ b/_vcsh_bash @@ -0,0 +1,138 @@ +# bash completion for vcsh. + +# run git command +# based on bash_completion:_command_offset() +_vcsh_git_command () { + local word_offset=$1 + for (( i=0; i < $word_offset; i++ )); do + for (( j=0; j <= ${#COMP_LINE}; j++ )); do + [[ "$COMP_LINE" == "${COMP_WORDS[i]}"* ]] && break + COMP_LINE=${COMP_LINE:1} + ((COMP_POINT--)) + done + COMP_LINE=${COMP_LINE#"${COMP_WORDS[i]}"} + ((COMP_POINT-=${#COMP_WORDS[i]})) + done + COMP_LINE="git $COMP_LINE" + ((COMP_POINT+=4)) + + # shift COMP_WORDS elements and adjust COMP_CWORD + for (( i=1; i <= COMP_CWORD - $word_offset + 1; i++ )); do + COMP_WORDS[i]=${COMP_WORDS[i+$word_offset-1]} + done + for (( i; i <= COMP_CWORD; i++ )); do + unset 'COMP_WORDS[i]' + done + COMP_WORDS[0]=git + ((COMP_CWORD -= $word_offset - 1)) + + local cspec=$( complete -p git 2>/dev/null ) + if [[ -n $cspec ]]; then + if [[ ${cspec#* -F } != $cspec ]]; then + local func=${cspec#*-F } + func=${func%% *} + + if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then + $func git "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}" + else + $func git "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" + fi + + # restore initial compopts + local opt + while [[ $cspec == *" -o "* ]]; do + # FIXME: should we take "+o opt" into account? + cspec=${cspec#*-o } + opt=${cspec%% *} + compopt -o $opt + cspec=${cspec#$opt} + done + fi + fi +} + +_vcsh () { + local cur prev words cword OPTS + _init_completion -n = || return + + local repos cmds + repos=( $(command vcsh list) ) + cmds="clone delete enter foreach help init list list-tracked list-untracked + pull push rename run status upgrade version which write-gitignore" + + local subcword cmd subcmd + for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do + [[ -n $cmd && ${words[subcword]} != -* ]] && subcmd=${words[subcword]} && break + [[ ${words[subcword]} != -* ]] && cmd=${words[subcword]} + done + + if [[ -z $cmd ]]; then + case $prev in + -c) + COMPREPLY=( $(compgen -f -- $cur) ) + return + ;; + esac + + case $cur in + -*) + OPTS='-c -d -h -v' + COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) + return + ;; + esac + COMPREPLY=( $(compgen -W "${repos[*]} ${cmds[*]}" -- $cur) ) + return 0 + fi + + case $cmd in + help|init|list|pull|push|version|which) + return + ;; + + list-untracked) + [[ $cur == -* ]] && \ + COMPREPLY=( $(compgen -W '-a -r' -- $cur) ) && return + ;;& + + run) + if [[ -n $subcmd && -n "${repos[$subcmd]}" ]]; then + _command_offset $(( $subcword+1 )) + return + fi + ;;& + + delete|enter|list-tracked|list-untracked|rename|run|status|upgrade|write-gitignore) + # return repos + if [[ -z $subcmd ]]; then + COMPREPLY=( $(compgen -W "${repos[*]}" -- $cur) ) + return + fi + return + ;; + + clone) + [[ $cur == -* ]] && \ + COMPREPLY=( $(compgen -W '-b' -- $cur) ) + return + ;; + + foreach) + [[ $cur == -* ]] \ + && COMPREPLY=( $(compgen -W "-g" -- $cur) ) && return + _vcsh_git_command $subcword + return + ;; + + esac + + # git command on repository + if [[ -n "${repos[$cmd]}" ]]; then + _vcsh_git_command $subcword + fi + return 0 +} + +complete -F _vcsh vcsh + +# vim: ft=sh: diff --git a/doc/vcsh.1.ronn b/doc/vcsh.1.ronn index 45b8c83..a25bf65 100644 --- a/doc/vcsh.1.ronn +++ b/doc/vcsh.1.ronn @@ -98,7 +98,7 @@ an interactive user. Delete an existing repository. * enter: - Enter repository; spawn new <$SHELL>. + Enter repository; spawn new <$SHELL> with <$GIT_DIR> set. * foreach: Execute git command for every vcsh repository. diff --git a/t/100-init.t b/t/100-init.t index 74facc0..15ce922 100644 --- a/t/100-init.t +++ b/t/100-init.t @@ -18,7 +18,7 @@ ok $output eq "", 'No repos set up yet.'; $output = `./vcsh init test1`; -ok $output eq "Initialized empty shared Git repository in " . $ENV{'HOME'} . "/.config/vcsh/repo.d/test1.git/\n"; +ok $output eq "Initialized empty Git repository in " . $ENV{'HOME'} . "/.config/vcsh/repo.d/test1.git/\n"; $output = `./vcsh status`; diff --git a/vcsh b/vcsh index de1b419..ce6705d 100755 --- a/vcsh +++ b/vcsh @@ -22,6 +22,9 @@ VERSION='1.20141026' SELF=$(basename $0) +# Ensure all files created are accessible only to the current user. +umask 0077 + fatal() { echo "$SELF: fatal: $1" >&2 [ -z $2 ] && exit 1 @@ -106,6 +109,7 @@ help() { commit Commit in all repositories delete Delete an existing repository enter Enter repository; spawn new instance of \$SHELL + with \$GIT_DIR set. foreach [<-g>] Execute a command for every repository help Display this help text @@ -261,7 +265,7 @@ init() { [ ! -e "$GIT_DIR" ] || fatal "'$GIT_DIR' exists" 10 mkdir -p "$VCSH_BASE" || fatal "could not create '$VCSH_BASE'" 50 cd "$VCSH_BASE" || fatal "could not enter '$VCSH_BASE'" 11 - git init --shared=0600 + git init --shared=false upgrade hook post-init }