Merge git://git.kernel.org/pub/scm/gitk/gitk
[gitweb.git] / git-gui / lib / blame.tcl
index 827c85d67f0b0f18d22b1399624e6819cf93f23f..c1cd7f3b92fddb60be9fe261d7b75c5df85b60c1 100644 (file)
@@ -21,9 +21,11 @@ field w_amov     ; # text column: annotations + move tracking
 field w_asim     ; # text column: annotations (simple computation)
 field w_file     ; # text column: actual file data
 field w_cviewer  ; # pane showing commit message
+field finder     ; # find mini-dialog frame
 field status     ; # status mega-widget instance
 field old_height ; # last known height of $w.file_pane
 
+
 # Tk UI colors
 #
 variable active_color #c0edc5
@@ -59,7 +61,7 @@ field tooltip_timer     {} ; # Current timer event for our tooltip
 field tooltip_commit    {} ; # Commit(s) in tooltip
 
 constructor new {i_commit i_path i_jump} {
-       global cursor_ptr
+       global cursor_ptr M1B M1T have_tk85
        variable active_color
        variable group_colors
 
@@ -69,6 +71,8 @@ constructor new {i_commit i_path i_jump} {
        make_toplevel top w
        wm title $top [append "[appname] ([reponame]): " [mc "File Viewer"]]
 
+       set font_w [font measure font_diff "0"]
+
        frame $w.header -background gold
        label $w.header.commit_l \
                -text [mc "Commit:"] \
@@ -114,9 +118,9 @@ constructor new {i_commit i_path i_jump} {
        pack $w_path -fill x -side right
        pack $w.header.path_l -side right
 
-       panedwindow $w.file_pane -orient vertical
-       frame $w.file_pane.out
-       frame $w.file_pane.cm
+       panedwindow $w.file_pane -orient vertical -borderwidth 0 -sashwidth 3
+       frame $w.file_pane.out -relief flat -borderwidth 1
+       frame $w.file_pane.cm -relief sunken -borderwidth 1
        $w.file_pane add $w.file_pane.out \
                -sticky nsew \
                -minsize 100 \
@@ -197,6 +201,11 @@ constructor new {i_commit i_path i_jump} {
                -width 80 \
                -xscrollcommand [list $w.file_pane.out.sbx set] \
                -font font_diff
+       if {$have_tk85} {
+               $w_file configure -inactiveselectbackground darkblue
+       }
+       $w_file tag conf found \
+               -background yellow
 
        set w_columns [list $w_amov $w_asim $w_line $w_file]
 
@@ -217,6 +226,11 @@ constructor new {i_commit i_path i_jump} {
                -weight 1
        grid rowconfigure $w.file_pane.out 0 -weight 1
 
+       set finder [::searchbar::new \
+               $w.file_pane.out.ff $w_file \
+               -column [expr {[llength $w_columns] - 1}] \
+               ]
+
        set w_cviewer $w.file_pane.cm.t
        text $w_cviewer \
                -background white \
@@ -256,9 +270,20 @@ constructor new {i_commit i_path i_jump} {
        $w.ctxm add command \
                -label [mc "Copy Commit"] \
                -command [cb _copycommit]
+       $w.ctxm add separator
+       $w.ctxm add command \
+               -label [mc "Find Text..."] \
+               -accelerator F7 \
+               -command [list searchbar::show $finder]
+       menu $w.ctxm.enc
+       build_encoding_menu $w.ctxm.enc [cb _setencoding]
+       $w.ctxm add cascade \
+               -label [mc "Encoding"] \
+               -menu $w.ctxm.enc
        $w.ctxm add command \
                -label [mc "Do Full Copy Detection"] \
                -command [cb _fullcopyblame]
+       $w.ctxm add separator
        $w.ctxm add command \
                -label [mc "Show History Context"] \
                -command [cb _gitkcommit]
@@ -271,9 +296,15 @@ constructor new {i_commit i_path i_jump} {
                        $i tag conf color$g -background [lindex $group_colors $g]
                }
 
+               if {$i eq $w_file} {
+                       $w_file tag raise found
+               }
+               $i tag raise sel
+
                $i conf -cursor $cursor_ptr
-               $i conf -yscrollcommand [list many2scrollbar \
-                       $w_columns yview $w.file_pane.out.sby]
+               $i conf -yscrollcommand \
+                       "[list ::searchbar::scrolled $finder]
+                        [list many2scrollbar $w_columns yview $w.file_pane.out.sby]"
                bind $i <Button-1> "
                        [cb _hide_tooltip]
                        [cb _click $i @%x,%y]
@@ -290,7 +321,7 @@ constructor new {i_commit i_path i_jump} {
                        tk_popup $w.ctxm %X %Y
                "
                bind $i <Shift-Tab> "[list focus $w_cviewer];break"
-               bind $i <Tab>       "[list focus $w_cviewer];break"
+               bind $i <Tab>       "[cb _focus_search $w_cviewer];break"
        }
 
        foreach i [concat $w_columns $w_cviewer] {
@@ -306,10 +337,15 @@ constructor new {i_commit i_path i_jump} {
                bind $i <Control-Key-f> {catch {%W yview scroll  1 pages};break}
        }
 
-       bind $w_cviewer <Shift-Tab> "[list focus $w_file];break"
+       bind $w_cviewer <Shift-Tab> "[cb _focus_search $w_file];break"
        bind $w_cviewer <Tab>       "[list focus $w_file];break"
-       bind $w_cviewer <Button-1> [list focus $w_cviewer]
-       bind $w_file    <Visibility> [list focus $w_file]
+       bind $w_cviewer <Button-1>   [list focus $w_cviewer]
+       bind $w_file    <Visibility> [cb _focus_search $w_file]
+       bind $top       <F7>         [list searchbar::show $finder]
+       bind $top       <Escape>     [list searchbar::hide $finder]
+       bind $top       <F3>         [list searchbar::find_next $finder]
+       bind $top       <Shift-F3>   [list searchbar::find_prev $finder]
+       catch { bind $top <Shift-Key-XF86_Switch_VT_3> [list searchbar::find_prev $finder] }
 
        grid configure $w.header -sticky ew
        grid configure $w.file_pane -sticky nsew
@@ -321,9 +357,14 @@ constructor new {i_commit i_path i_jump} {
 
        set req_w [winfo reqwidth  $top]
        set req_h [winfo reqheight $top]
-       set scr_h [expr {[winfo screenheight $top] - 100}]
-       if {$req_w < 600} {set req_w 600}
+       set scr_w [expr {[winfo screenwidth $top] - 40}]
+       set scr_h [expr {[winfo screenheight $top] - 120}]
+       set opt_w [expr {$font_w * (80 + 5*3 + 3)}]
+       if {$req_w < $opt_w} {set req_w $opt_w}
+       if {$req_w > $scr_w} {set req_w $scr_w}
+       set opt_h [expr {$req_w*4/3}]
        if {$req_h < $scr_h} {set req_h $scr_h}
+       if {$req_h > $opt_h} {set req_h $opt_h}
        set g "${req_w}x${req_h}"
        wm geometry $top $g
        update
@@ -331,16 +372,31 @@ constructor new {i_commit i_path i_jump} {
        set old_height [winfo height $w.file_pane]
        $w.file_pane sash place 0 \
                [lindex [$w.file_pane sash coord 0] 0] \
-               [expr {int($old_height * 0.70)}]
+               [expr {int($old_height * 0.80)}]
        bind $w.file_pane <Configure> \
        "if {{$w.file_pane} eq {%W}} {[cb _resize %h]}"
 
        wm protocol $top WM_DELETE_WINDOW "destroy $top"
-       bind $top <Destroy> [cb _kill]
+       bind $top <Destroy> [cb _handle_destroy %W]
 
        _load $this $i_jump
 }
 
+method _focus_search {win} {
+       if {[searchbar::visible $finder]} {
+               focus [searchbar::editor $finder]
+       } else {
+               focus $win
+       }
+}
+
+method _handle_destroy {win} {
+       if {$win eq $w} {
+               _kill $this
+               delete_this
+       }
+}
+
 method _kill {} {
        if {$current_fd ne {}} {
                kill_file_process $current_fd
@@ -399,7 +455,10 @@ method _load {jump} {
        } else {
                set fd [git_read cat-file blob "$commit:$path"]
        }
-       fconfigure $fd -blocking 0 -translation lf -encoding binary
+       fconfigure $fd \
+               -blocking 0 \
+               -translation lf \
+               -encoding [get_path_encoding $path]
        fileevent $fd readable [cb _read_file $fd $jump]
        set current_fd $fd
 }
@@ -500,7 +559,7 @@ method _read_file {fd jump} {
 } ifdeleted { catch {close $fd} }
 
 method _exec_blame {cur_w cur_d options cur_s} {
-       lappend options --incremental
+       lappend options --incremental --encoding=utf-8
        if {$commit eq {}} {
                lappend options --contents $path
        } else {
@@ -508,7 +567,7 @@ method _exec_blame {cur_w cur_d options cur_s} {
        }
        lappend options -- $path
        set fd [eval git_read --nice blame $options]
-       fconfigure $fd -blocking 0 -translation lf -encoding binary
+       fconfigure $fd -blocking 0 -translation lf -encoding utf-8
        fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d]
        set current_fd $fd
        set blame_lines 0
@@ -788,6 +847,16 @@ method _click {cur_w pos} {
        _showcommit $this $cur_w $lno
 }
 
+method _setencoding {enc} {
+       force_path_encoding $path $enc
+       _load $this [list \
+               $highlight_column \
+               $highlight_line \
+               [lindex [$w_file xview] 0] \
+               [lindex [$w_file yview] 0] \
+               ]
+}
+
 method _load_commit {cur_w cur_d pos} {
        upvar #0 $cur_d line_data
        set lno [lindex [split [$cur_w index $pos] .] 0]
@@ -846,6 +915,10 @@ method _showcommit {cur_w lno} {
                foreach i $w_columns {
                        $i tag conf g$cmit -background $active_color
                        $i tag raise g$cmit
+                       if {$i eq $w_file} {
+                               $w_file tag raise found
+                       }
+                       $i tag raise sel
                }
 
                set author_name {}
@@ -881,12 +954,6 @@ method _showcommit {cur_w lno} {
                                set enc [tcl_encoding $enc]
                                if {$enc ne {}} {
                                        set msg [encoding convertfrom $enc $msg]
-                                       set author_name [encoding convertfrom $enc $author_name]
-                                       set committer_name [encoding convertfrom $enc $committer_name]
-                                       set header($cmit,author) $author_name
-                                       set header($cmit,committer) $committer_name
-                                       set header($cmit,summary) \
-                                       [encoding convertfrom $enc $header($cmit,summary)]
                                }
                                set msg [string trim $msg]
                        }
@@ -942,9 +1009,20 @@ method _format_offset_date {base offset} {
 }
 
 method _gitkcommit {} {
+       global nullid
+
        set dat [_get_click_amov_info $this]
        if {$dat ne {}} {
                set cmit [lindex $dat 0]
+
+               # If the line belongs to the working copy, use HEAD instead
+               if {$cmit eq $nullid} {
+                       if {[catch {set cmit [git rev-parse --verify HEAD]} err]} {
+                               error_popup [strcat [mc "Cannot find HEAD commit:"] "\n\n$err"]
+                               return;
+                       }
+               }
+
                set radius [get_config gui.blamehistoryctx]
                set cmdline [list --select-commit=$cmit]
 
@@ -981,12 +1059,20 @@ method _gitkcommit {} {
 }
 
 method _blameparent {} {
+       global nullid
+
        set dat [_get_click_amov_info $this]
        if {$dat ne {}} {
                set cmit [lindex $dat 0]
                set new_path [lindex $dat 1]
 
-               if {[catch {set cparent [git rev-parse --verify "$cmit^"]}]} {
+               # Allow using Blame Parent on lines modified in the working copy
+               if {$cmit eq $nullid} {
+                       set parent_ref "HEAD"
+               } else {
+                       set parent_ref "$cmit^"
+               }
+               if {[catch {set cparent [git rev-parse --verify $parent_ref]} err]} {
                        error_popup [strcat [mc "Cannot find parent commit:"] "\n\n$err"]
                        return;
                }
@@ -996,8 +1082,12 @@ method _blameparent {} {
                # Generate a diff between the commit and its parent,
                # and use the hunks to update the line number.
                # Request zero context to simplify calculations.
-               if {[catch {set fd [eval git_read diff-tree \
-                               --unified=0 $cparent $cmit $new_path]} err]} {
+               if {$cmit eq $nullid} {
+                       set diffcmd [list diff-index --unified=0 $cparent -- $new_path]
+               } else {
+                       set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path]
+               }
+               if {[catch {set fd [eval git_read $diffcmd]} err]} {
                        $status stop [mc "Unable to display parent"]
                        error_popup [strcat [mc "Error loading diff:"] "\n\n$err"]
                        return