diff --git a/git-recall b/git-recall index ea0f5c4..1191c7f 100644 --- a/git-recall +++ b/git-recall @@ -22,8 +22,10 @@ FETCH=false GIT_FORMAT="" GIT_LOG="" COMMITS="" +COMMITS_UNCOL=() # commits without colors LESSKEY=false -VERSION="1.1.4" +SED_BIN="" # Sed option to use according OS. +VERSION="1.1.5" # Are we in a git repo? if [[ ! -d ".git" ]] && ! git rev-parse --git-dir &>/dev/null; then @@ -124,8 +126,10 @@ COMMITS=($(eval ${GIT_LOG} 2>/dev/null)) unset IFS NI=${#COMMITS[@]} # Total number of items. -SN=$(( `tput lines` - 1 )) # Screen number of lines. +SN=$(( `tput lines` - 1 )) # Screen's number of lines. +CN=$(tput cols) # Screen's number of columns. TN=$(( $NI < $((SN -1)) ? $NI : $((SN -1)))) # Number of lines that we will display. +OFFSET=0 #Incremented by one each time a commit's length is higher than teminal width. # If there is no items, exit. if [[ $NI = 0 ]]; then @@ -136,6 +140,27 @@ if [[ $NI = 0 ]]; then fi fi +# Set correct sed option according OS's type +case "$OSTYPE" in + darwin*) SED_BIN="sed -E" ;; + *) SED_BIN="sed -r" ;; +esac + +# Create array with uncolred commits (removing escape sequences using sed) +for elt in "${COMMITS[@]}" +do + ELT="$(echo "$elt" | $SED_BIN "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")" # remove colors escape codes + COMMITS_UNCOL+=("$ELT") +done + +# Add +1 to OFFSET if a commit's length is bigger than the current terminal session's width. (This is to fix a redraw issue) +for C in "${COMMITS_UNCOL[@]}" +do + if [[ ${#C} -gt $CN ]]; then + OFFSET=$(( OFFSET + 1 )) + fi +done + # Set keys. au="`echo -e '\e[A'`" # arrow up au_1="k" # arrow up @@ -151,16 +176,13 @@ fi ## Get commit's diff. function get_diff() { - case "$OSTYPE" in - darwin*) SED_BIN="sed -E" ;; - *) SED_BIN="sed -r" ;; - esac - - ELT="$(echo "${COMMITS[$CP-1]}" | $SED_BIN "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")" # remove colors escape codes + ELT="$(echo "${COMMITS_UNCOL[$CP-1]}")" DIFF_TIP=${ELT:0:7} DIFF_CMD="git show $DIFF_TIP --color=always" DIFF=$(eval ${DIFF_CMD} 2>/dev/null) + off=$(echo "$DIFF" | grep -c ".\{$CN\}") #Number of lines in the diff that are longer than terminal width. DIFF_LINES_NUMBER="$(echo "$DIFF" | wc -l)" + DIFF_LINES_NUMBER=$(( DIFF_LINES_NUMBER + off )) } ## This function will print the diff according the commit's tip. If the diff is too long, the result will be displayed using 'less'. @@ -168,12 +190,13 @@ function print_diff() { get_diff - if [[ $(( TN + DIFF_LINES_NUMBER )) -ge $(( `tput lines` - 1 )) ]]; then + if [[ $(( TN + DIFF_LINES_NUMBER + OFFSET )) -ge $(( `tput lines` - 1 )) ]]; then if [[ $LESSKEY = true ]]; then echo "$DIFF" | less -r -k $HOME/.lsh_less_keys_tmp else echo "$DIFF" | less -r fi + tput ed # Clear screen else stop=false tput ed @@ -201,11 +224,26 @@ function print_diff() { ;; esac done - [[ $END = false ]] && tput cuu $(( TN + DIFF_LINES_NUMBER )) && tput ed + [[ $END = false ]] && tput cuu $(( TN + DIFF_LINES_NUMBER + OFFSET )) && tput ed [[ $END = true ]] && tput cuu 1 fi } +# Calculate OFFSET to avoid bad redraw. +function calculate_offset { + tmp=1 + index=$(( SI -1 )) + while [[ $tmp -lt $SN ]] + do + el=${COMMITS_UNCOL[$index]} + if [[ ${#el} -gt $CN ]] && [[ $CP -lt $((SN -1)) ]]; then + OFFSET_2=$(( OFFSET_2 + 1 )) + tmp=$(( tmp + 1 )) + fi + tmp=$(( tmp + 1 )) + index=$(( index + 1 )) + done +} { # capture stdout to stderr @@ -213,12 +251,31 @@ tput civis # hide cursor. CP=1 # current position SI=1 # index END=false # end while loop +EXT=0 # Used to extend the number of lines to display. ## Loops, reads inputs and prints commits until user presses 'q' to exit or TAB to show the diff. while ! $END do + + END_INDEX=0 # Index for the last item to display - for i in `seq $SI $(( $TN + $SI -1 ))` + # When the number of item is higher than screen's number of lines, OFFSET_2 is recalculated each time we select a new item + # Set last index to print. (based on OFFSET) + if [[ $TN == $NI ]]; then + END_INDEX=$TN + OFFSET_2=$OFFSET + elif [[ $TN == $(( SN - 1 )) ]]; then + # Calculate new OFFSET. + if [[ $OFFSET != 0 ]]; then + [[ $CP -lt $((SN -1)) ]] && OFFSET_2=0 + EXT=1 + calculate_offset + fi + END_INDEX=$(( TN + SI -1 + EXT - OFFSET_2 )) + fi + + # Loop and echo commits + for i in `seq $SI $END_INDEX` do echo -n "$NORMAL" [[ $CP == $i ]] && echo -n "$REVERSE" @@ -236,35 +293,40 @@ do "$au" | "$au_1") CP=$(( CP - 1 )) - [[ $CP == 0 ]] && [[ $SI=1 ]] && [[ $TN == $(( SN - 1 )) ]] && CP=$NI && SI=$(( NI - SN + 2 )) + [[ $CP == 0 ]] && [[ $SI=1 ]] && [[ $TN == $(( SN - 1 )) ]] && CP=$NI && SI=$(( NI - SN + 2 + OFFSET_2 )) [[ $CP == 0 ]] && [[ $SI=1 ]] && [[ $TN == $NI ]] && CP=$TN [[ $CP == $(( SI - 1 )) ]] && [[ $SI != 1 ]] && SI=$(( SI - 1 )) - tput cuu $TN + + [[ $TN != $(( SN - 1 )) ]] && tput cuu $(( TN + OFFSET_2 )) + [[ $TN == $(( SN - 1 )) ]] && tput cuu $(( TN + EXT )) [[ $SI != 1 ]] && tput ed # clear screen ;; "$ad" | "$ad_1") CP=$(( CP + 1 )) [[ $CP == $(( NI + 1 )) ]] && CP=1 && SI=1 - [[ $CP == $(( SN + SI - 1)) ]] && [[ $TN == $(( SN - 1 )) ]] && SI=$(( SI + 1 )) - tput cuu $TN + [[ $CP == $(( SN + SI - 1 + EXT - OFFSET_2 )) ]] && [[ $TN == $(( SN - 1 )) ]] && SI=$(( SI + 1 )) + + [[ $TN != $(( SN - 1 )) ]] && tput cuu $(( TN + OFFSET_2 )) + [[ $TN == $(( SN - 1 )) ]] && tput cuu $(( TN + EXT )) [[ $SI != 1 ]] && tput ed # clear screen [[ $SI = 1 ]] && [[ $CP = 1 ]] && tput ed # clear screen ;; "$nl") - tput cuu $TN - print_diff + [[ $TN == $NI ]] && tput cuu $(( TN + OFFSET_2 )) + [[ $TN != $NI ]] && tput cuu $(( TN + EXT )) + print_diff ;; "q") si=false END=true - tput cuu 1 + tput cuu 1 #move cursor up one line. (remove extra line) ;; * ) - tput cuu $TN + tput cuu $(( TN + OFFSET_2 )) esac done