12 field ui_errs_width_max
14 field ui_warns_width
3
15 field ui_warns_width_max
20 field ui_lnos_width_max
34 field current_file_list
39 field current_path_label
{}
40 field current_path_lno_hits
41 field file_list_needs_update
0
43 field file_list_busy
0
54 field selected_configs
55 field buildconfig_config
56 field buildconfig_menu_id
0
60 field current_cmd_label
{}
61 field build_ref refs
/builds
/default
64 field output_hash_pipe
66 # static tree entries (cwd, environ)
67 field static_build_tree
68 # per run tree entries (output, exit status, worktree)
76 field cmd_history_pos
0
78 field build_history_pos
-1
80 constructor embed
{i_w
{i_vpath
{}} {i_ref
{}} {i_shell
{}} {i_envmods
{}} {i_configs
{}} {i_state_change_cb
{}}} {
84 if {[catch {_init
$this $i_vpath $i_ref $i_shell $i_envmods $i_configs $i_state_change_cb} err
]} {
85 return -code error $err
91 method _init
{i_vpath i_ref i_shell i_envmods i_configs i_state_change_cb
} {
101 {return -code error "Invalid build ref ending in /: $i_ref"}
103 {set build_ref
$i_ref}
105 {return -code error "Invalid build ref: $i_ref"}
107 {set build_ref refs
/$i_ref}
109 {set build_ref refs
/builds
/$i_ref}
112 set build_name
[string range
$build_ref [string length
{refs
/}] end
]
113 set build_index
$::GIT_INDEX_FILE.
[string map
{/ .
} $build_name].
[pid]
115 if {$i_shell eq
{}} {
116 set shell
[shellpath
]
122 foreach mod
$i_envmods {
123 if {[regexp {^
([A-Za-z0-9_
]+)\s
*((?
:[-+%].?
)?
=)\s
*(.
*)$} $mod match name op value
]} {
124 lappend envmods
$name $op $value
125 } elseif
{[regexp {^
!([A-Za-z0-9_
]+)$} $mod match name
]} {
126 lappend envmods
$name ! {}
131 -title {git-gui
: build
: invalid env mod
} \
132 -message "Invalid env mod command: $mod"
136 set configmods
$i_configs
137 array set selected_configs
{}
139 set state_change_cb
$i_state_change_cb
141 # base path for all grep widgets
143 set w_vpane
$w_hpane.v
145 set w_files
$w_vpane.f.l
146 set w_diags
$w_vpane.f.t.k
147 set w_errs
$w_vpane.f.e
148 set w_warns
$w_vpane.f.w
150 set w_lnos
$w_vpane.o.l
151 set w_hits
$w_vpane.o.d
153 set w_indicator
$w_hpane.f.l
154 set m_configs
$w_hpane.f.l.c
155 set w_output
$w_hpane.f.o
156 set w_entry
$w_hpane.f.e
158 ttk
::panedwindow $w_hpane -orient vertical
159 ttk
::panedwindow $w_vpane -orient horizontal
161 ttk
::frame $w_hpane.f
-borderwidth 0
162 pack $w_hpane -side top
-fill both
-expand 1
164 $w_hpane add
$w_vpane -weight 0
165 $w_hpane add
$w_hpane.f
-weight 1
167 ttk
::frame $w_vpane.f
-borderwidth 0
168 ttk
::frame $w_vpane.o
-borderwidth 0
169 $w_vpane add
$w_vpane.f
-weight 0
170 $w_vpane add
$w_vpane.o
-weight 1
172 ## list of files with errors and warnings
174 ttk
::frame $w_vpane.f.t
-borderwidth 0
176 ttk
::label $w_vpane.f.t.l
\
177 -style Color.TLabel
\
178 -text "Diagnosed Files" \
179 -background lightsalmon
\
182 set diag_list
[list "All"]
184 ttk
::combobox $w_diags \
185 -style Color.TCombobox
\
189 -exportselection false
\
190 -textvariable push_remote
\
191 -background lightsalmon
\
194 grid configure
$w_vpane.f.t.l
$w_diags \
197 grid columnconfigure
$w_vpane.f.t
\
206 -highlightthickness 0 \
212 -xscrollcommand [list $w_vpane.f.sbx
set]
213 $w_files tag conf
default -lmargin1 5 -rmargin 1
217 -highlightthickness 0 \
222 -width [expr $ui_errs_width + 1] \
226 $w_errs tag conf count
-justify right
-lmargin1 2 -rmargin 3 -foreground red
230 -highlightthickness 0 \
235 -width [expr $ui_warns_width + 1] \
239 $w_warns tag conf count
-justify right
-lmargin1 2 -rmargin 3 -foreground orange
241 set ui_files_cols
[list $w_files $w_errs $w_warns]
243 # simulate linespacing, as if it has an icon like the index/worktree
245 set fn
[$w_files cget
-font]
246 set ls
[font metrics
$fn -linespace]
248 set d
[expr 17 - $ls]
251 if {[expr $b + $t] != $d} {
254 foreach i
$ui_files_cols {
255 $i configure
-spacing1 $t -spacing3 $b
259 ttk
::scrollbar $w_vpane.f.sbx
\
261 -command [list $w_files xview
]
263 ttk
::scrollbar $w_vpane.f.sby
\
265 -command [list scrollbar2many
$ui_files_cols yview
]
267 grid configure
$w_vpane.f.t
\
272 grid $w_files $w_errs $w_warns $w_vpane.f.sby
-sticky nsew
274 grid configure
$w_vpane.f.sbx
\
279 grid columnconfigure
$w_vpane.f
\
282 grid rowconfigure
$w_vpane.f
\
286 foreach i
$ui_files_cols {
289 $i conf
-cursor arrow
290 $i conf
-yscrollcommand \
291 "[list many2scrollbar $ui_files_cols yview $w_vpane.f.sby]"
293 bind $i <Button-1
> "[cb _select_from_file_list %x %y]; break"
296 ## error/warning description from one file
298 ttk
::label $w_vpane.o.t
\
299 -style Color.TLabel
\
300 -textvariable @current_path_label
\
306 set ctxm
$w_vpane.o.t.ctxm
307 menu $ctxm -tearoff 0
310 -command [cb _copy_path
]
311 bind_button3
$w_vpane.o.t
"tk_popup $ctxm %X %Y"
315 -highlightthickness 0 \
320 -width [expr $ui_lnos_width + 1] \
325 $w_lnos tag conf normal
-justify right
-rmargin 5
326 $w_lnos tag conf warning
-justify right
-rmargin 5 -foreground orange
327 $w_lnos tag conf
error -justify right
-rmargin 5 -foreground red
331 -highlightthickness 0 \
339 -xscrollcommand [list $w_vpane.o.sbx
set] \
342 $w_hits tag conf normal
343 $w_hits tag conf warning
-foreground orange
344 $w_hits tag conf
error -foreground red
345 $w_hits tag conf jumpmark
-elide 1
346 $w_hits tag conf auxmark
-elide 1
348 delegate_sel_to
$w_hits [list $w_lnos]
350 set ui_hits_cols
[list $w_lnos $w_hits]
352 ttk
::scrollbar $w_vpane.o.sbx
\
354 -command [list $w_hits xview
]
356 ttk
::scrollbar $w_vpane.o.sby
\
358 -command [list scrollbar2many
$ui_hits_cols yview
]
360 grid configure
$w_vpane.o.t
\
365 grid $w_lnos $w_hits $w_vpane.o.sby
-sticky nsew
367 grid configure
$w_vpane.o.sbx
\
372 grid columnconfigure
$w_vpane.o
\
375 grid rowconfigure
$w_vpane.o
\
380 foreach i
$ui_hits_cols {
383 $i conf
-yscrollcommand \
384 "[list many2scrollbar $ui_hits_cols yview $w_vpane.o.sby]"
388 set bind_cmd delegator_bind
390 $bind_cmd $i <Button-1
> "[cb _jump_to_hit_in_output %x %y]"
391 bind $i <ButtonRelease-2
> "[cb _open_from_hits %x %y]; break"
394 ## command output and entry
396 ttk
::label $w_indicator \
397 -style Color.TLabel
\
398 -textvariable @current_cmd_label
\
402 menu $m_configs -tearoff 0
403 bind_button3
$w_indicator "[cb _popup_configs %X %Y]"
407 -highlightthickness 0 \
416 -xscrollcommand [list $w_hpane.f.sbx
set] \
419 $w_output tag conf out
420 $w_output tag conf note
-foreground blue
421 $w_output tag conf warning
-foreground orange
422 $w_output tag conf
error -foreground red
423 #$w_output tag conf path -underline 1
424 #$w_output tag conf pos -underline 1
425 $w_output tag conf path
-font font_diffitalic
426 $w_output tag conf pos
-font font_diffitalic
427 $w_output tag conf found
-background yellow
428 $w_output tag conf currenthit
-font font_diffbold
430 foreach {n c
} {0 black
1 red
2 green4
3 yellow4
4 blue4
5 magenta4
6 cyan4
7 grey60
} {
431 $w_output tag configure clr4
$n -background $c
432 $w_output tag configure clri4
$n -foreground $c
433 $w_output tag configure clr3
$n -foreground $c
434 $w_output tag configure clri3
$n -background $c
436 $w_output tag configure clr1
-font font_diffbold
437 $w_output tag configure clr4
-underline 1
438 $w_output tag
raise found
439 $w_output tag
raise sel
441 ttk
::scrollbar $w_hpane.f.sbx
\
443 -command [list $w_output xview
]
445 ttk
::scrollbar $w_hpane.f.sby
\
447 -command [list $w_output yview
]
450 -font TkDefaultFont
\
451 -disabledforeground white
\
452 -disabledbackground blue
\
453 -takefocus [cb _always_takefocus
]
455 grid configure
$w_indicator \
459 grid $w_output $w_hpane.f.sby
-sticky nsew
460 grid configure
$w_hpane.f.sbx
\
465 set ui_finder
[::searchbar::new \
466 $w_hpane.f.f
$w_output $w_entry \
473 "[list $ui_finder scrolled]
474 [list $w_hpane.f.sby set]"
476 grid configure
$w_entry \
481 grid columnconfigure
$w_hpane.f
\
484 grid rowconfigure
$w_hpane.f
\
488 bind $w_output <ButtonRelease-2
> [cb _open_from_output
%x
%y
]
490 foreach i
[list $w_output $w_entry [$ui_finder editor
]] {
491 bind $i <F7
> [list $ui_finder show
]
492 bind $i <$::M1B-Key
-f
> [list $ui_finder show
]
493 bind $i <Escape
> [list $ui_finder hide
]
494 bind $i <F3
> [list $ui_finder find_next
]
495 bind $i <Shift-F3
> [list $ui_finder find_prev
]
497 bind $i <Alt-Up
> "$w_output yview scroll -1 units; break"
498 bind $i <Alt-Down
> "$w_output yview scroll 1 units; break"
499 bind $i <Alt-Prior
> "$w_output yview scroll -1 pages; break"
500 bind $i <Alt-Next
> "$w_output yview scroll 1 pages; break"
503 bind $i <Alt-Shift-Up
> "[cb _files_scroll_line -1]; break"
504 bind $i <Alt-Shift-Down
> "[cb _files_scroll_line 1]; break"
505 bind $i <Alt-Shift-Prior
> "[cb _files_scroll_page -1]; break"
506 bind $i <Alt-Shift-Next
> "[cb _files_scroll_page 1]; break"
509 bind $w_entry <Return
> [cb _run
]
510 bind $w_entry <KP_Enter
> [cb _run
]
511 bind $w_entry <Key-Up
> [cb _prev_cmd
]
512 bind $w_entry <Key-Down
> [cb _next_cmd
]
513 bind $w_entry <$::M1B-Key
-Up
> [cb _prev_build
]
514 bind $w_entry <$::M1B-Key
-Down
> [cb _next_build
]
515 bind $w_entry <Key-Prior
> [cb _search_prev_cmd
]
516 bind $w_entry <Key-Next
> [cb _search_next_cmd
]
517 bind $w_entry <$::M1B-Key
-c
> [cb _cancel
]
518 bind $w_entry <Visibility
> [cb _visible
]
520 array set current_path_lno_hits
{}
521 trace add
variable current_path write
[cb _update_path_label
]
525 trace add
variable state write
[cb _update_cmd_label
]
526 trace add
variable current_cmd write
[cb _update_cmd_label
]
530 set current_file_list
[list]
531 array set file_info
{}
532 _reset_diag_list
$this
533 bind $w_diags <<ComboboxSelected
>> [cb _select_diagnostics
]
534 array set build_tree
{}
535 array set static_build_tree
{}
538 set vpath
[file normalize
[file join $::GIT_WORK_TREE $vpath]]
540 # make the vpath relative to gitwork_dir, when this is an ancestor
542 if {[string first
"$::GIT_WORK_TREE/" $cmd_dir] == 0} {
543 set cmd_dir
[string range
$cmd_dir [string length
"$::GIT_WORK_TREE/"]+1 end
]
545 if {$cmd_dir eq
$::GIT_WORK_TREE} {
548 set static_build_tree
(cwd
) [list \
551 [git hash-object
-w -t blob
--stdin <<$cmd_dir]]
554 set cmd_history
[list ""]
555 set build_history
[list]
557 set logfd
[git_read log
-g {--pretty=set hist_entry
[list %H
%T
%at
%ct
{%s
}]} $build_ref]
558 while {[gets $logfd entry] >= 0} {
560 foreach {build_c build_t build_start_s build_end_s cmd
} $hist_entry break
561 set hist_entry
[list $build_c $build_t [expr $build_end_s - $build_start_s] $cmd]
562 lappend build_history
$hist_entry
563 set cmd
[lindex $hist_entry 3]
564 if {[lindex $cmd_history end
] eq
$cmd} {
567 lappend cmd_history
$cmd
580 if {[string trim
[$w_entry get
]] eq
{}} {
584 set current_cmd
[$w_entry get
]
586 set build_history_pos
-1
593 set current_file_list
[list]
594 array unset file_info
595 set diag_list
[list "All" "Errors" "Warnings"]
598 array set build_tree
{}
600 foreach i
$ui_files_cols {
601 $i conf
-state normal
603 $i conf
-state disabled
605 $w_errs conf
-width [expr $ui_errs_width + 1]
606 set ui_errs_width_max
$ui_errs_width
607 $w_warns conf
-width [expr $ui_warns_width + 1]
608 set ui_warns_width_max
$ui_warns_width
610 foreach i
$ui_hits_cols {
611 $i conf
-state normal
613 $i conf
-state disabled
615 $w_lnos conf
-width [expr $ui_lnos_width + 1]
616 set ui_lnos_width_max
$ui_lnos_width
618 $w_output conf
-state normal
619 $w_output delete
0.0 end
620 $w_output conf
-state disabled
621 $w_output tag remove found
1.0 end
623 $w_errs conf
-width [expr $ui_errs_width + 1]
624 set ui_errs_width_max
$ui_warns_width
625 $w_warns conf
-width [expr $ui_warns_width + 1]
626 set ui_warns_width_max
$ui_warns_width
628 # record state of work tree
630 exec git read-tree
--index-output
=$build_index --reset HEAD
631 set ::GIT_INDEX_FILE $build_index
632 exec git ls-files
--exclude-standard
-d -m -o -z |
\
633 git update-index
-z --add --remove --stdin
634 set build_tree
(worktree
) [list \
638 file delete
$build_index
643 file delete
$build_index
649 -title {git-gui
: build
: can't record state of worktree
} \
655 set dir_stack
[list $vpath]
656 set env_args
[envargs
[_get_envmods
$this]]
660 # open pipe to git-hash-object
661 set e_pipe
[open "|cat" r
+]
664 set e_out
[git_write hash-object
-t blob
-w --stdin >@$e_pipe]
667 set cmd
[concat env
$env_args [list $shell -c "cd $vpath && env -0" >@$e_out]]
670 set build_tree
(environ
) [list \
677 catch {close $e_pipe}
684 -title {git-gui
: build
: can't record environment
} \
690 # open pipe to git-hash-object
691 set output_hash_pipe
[open "|cat" r
+]
692 fconfigure $output_hash_pipe \
694 set output_hash_out
[git_write hash-object
-t blob
-w --stdin >@$output_hash_pipe]
695 fconfigure $output_hash_out \
698 set build_start
[exec date
-R]
699 set build_start_s
[exec date
+%s
-d $build_start]
701 set build_timer
[after 250 [cb _update_runtime
]]
702 set cmd
[concat [list | env
] $env_args [list $shell -c "cd $vpath && $current_cmd" 2>@1]]
703 if {[catch {set current_fd
[open $cmd r
]} err
]} {
706 close $output_hash_pipe
707 close $output_hash_out
712 -title {git-gui
: build
: fatal
error} \
718 fconfigure $current_fd \
721 fileevent $current_fd readable
[cb _read
]
726 if {$build_history_pos < 0} {
738 foreach {build_c build_t build_run_s current_cmd
} [lindex $build_history $build_history_pos] break
739 $w_entry insert
0 $current_cmd
742 set current_file_list
[list]
743 array unset file_info
744 _reset_diag_list
$this
747 foreach i
$ui_files_cols {
748 $i conf
-state normal
750 $i conf
-state disabled
752 $w_errs conf
-width [expr $ui_errs_width + 1]
753 set ui_errs_width_max
$ui_errs_width
754 $w_warns conf
-width [expr $ui_warns_width + 1]
755 set ui_warns_width_max
$ui_warns_width
757 foreach i
$ui_hits_cols {
758 $i conf
-state normal
760 $i conf
-state disabled
762 $w_lnos conf
-width [expr $ui_lnos_width + 1]
763 set ui_lnos_width_max
$ui_lnos_width
765 $w_output conf
-state normal
766 $w_output delete
0.0 end
767 $w_output conf
-state disabled
768 $w_output tag remove found
1.0 end
769 $w_output tag remove currenthit
1.0 end
771 $w_errs conf
-width [expr $ui_errs_width + 1]
772 set ui_errs_width_max
$ui_warns_width
773 $w_warns conf
-width [expr $ui_warns_width + 1]
774 set ui_warns_width_max
$ui_warns_width
776 # load infos from build tree
777 set build_load_info
[list]
779 set fd
[git_read ls-tree
$build_t -- cwd exit_status output
]
780 while {[gets $fd entry] >= 0} {
781 foreach {infos path
} [split $entry "\t"] break
782 foreach {mode type sha1
} [split $infos " "] break
783 if {$type ne
{blob
}} {
786 switch -exact $path {
788 if {$mode eq
120000} {
789 lappend build_load_info
[git cat-file blob
$sha1]
793 if {$mode eq
100644} {
794 lappend build_load_info
[git cat-file blob
$sha1]
798 if {$mode eq
100644} {
799 lappend build_load_info
$sha1
806 if {$err ||
[llength $build_load_info] != 3} {
810 set dir_stack
[list [file normalize
[file join $::GIT_WORK_TREE [lindex $build_load_info 0]]]]
813 set current_fd
[git_read cat-file blob
[lindex $build_load_info 2]]
814 fconfigure $current_fd \
817 fileevent $current_fd readable
[cb _read
[lindex $build_load_info 1]]
820 method _read
{{exit_status
{}}} {
821 $w_output conf
-state normal
823 while {[gets $current_fd line
] >= 0} {
824 set scroll_pos
[lindex [$w_output yview
] 1]
828 set mark
[$w_output index end
]
831 # pass the original line to git-hash-object
832 if {$exit_status eq
{}} {
833 puts $output_hash_out $line
836 # parse color sequences and remove them
837 foreach {line markup
} [parse_color_line
$line] break
838 set line
[string map
{\033 ^
} $line]
839 regsub {\r$} $line {} line
847 if { [regexp -indices {^
(.
*?
): In
[^
]+ .
+:} $line imatch ipath
]
848 ||
[regexp -indices {^
(?
:In
file included|
) from
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
[:,]} $line imatch ipath ipos
]
849 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: the top level
} $line imatch ipath ipos
]
850 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: At top level
:} $line imatch ipath ipos
]
851 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: At
global scope
:} $line imatch ipath ipos
]
852 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: (?
:instantiated|required
) from .
*$} $line imatch ipath ipos
]
853 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: ((?
:fatal
)?
(note|warning|WARNING|
error): .
*)$} $line imatch ipath ipos imsg itype
]
854 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: .
*? is expanded from...
} $line imatch ipath ipos
]
855 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: installing
[`'
].
*'
} $line imatch ipath ipos
]
856 ||
[regexp -indices {^
(.
*?
):(?
:\(.
*?
\)): ((undefined reference to
) [`'
].
*'
)} $line imatch ipath imsg itype
]
857 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: ((undefined reference to
) [`'
].
*'
)} $line imatch ipath ipos imsg itype
]
858 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: ((required
file) [`'
].
*' not found
)} $line imatch ipath ipos imsg itype
]
859 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: ([^
\s
]*?
(multiply defined in condition
) .
* \.
\.
\.
)} $line imatch ipath ipos imsg itype
]
860 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: (\.
\.
\.
[`'
].
*'
(previously defined here
))} $line imatch ipath ipos imsg itype
]
861 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: (.
* (does not appear in AM_CONDITIONAL
))} $line imatch ipath ipos imsg itype
]
862 ||
[regexp -indices {^
(.
*?
)(?
::([0-9]+(?
::[0-9]+)?
))?
: ([`'
].
*'
(included from here
))} $line imatch ipath ipos imsg itype
]
864 #puts "work dir: $::GIT_WORK_TREE"
865 #puts "current stack: [lindex $dir_stack end]"
866 #puts "output: $line"
868 set path
[string range
$line [lindex $ipath 0] [lindex $ipath 1]]
869 set orig_path_len
[string length
$path]
871 set path
[file join [lindex $dir_stack end
] $path]
872 #puts "full path: $path"
873 set path
[file normalize
$path]
874 #puts "normalized path: $path"
876 # only remove the gitwork dir prefix, if the normalized path is
877 # actually under the git work tree
878 #puts "work dir prefix: [string range $path 0 [string length $::GIT_WORK_TREE]-1]"
879 if {[string first
$::GIT_WORK_TREE $path] == 0} {
880 set path
[string range
$path [string length
$::GIT_WORK_TREE]+1 end
]
882 #puts "final path: $path"
888 set type
[string tolower
[string range
$line [lindex $itype 0] [lindex $itype 1]]]
890 "undefined reference to" -
892 "does not appear in am_conditional" {
895 "multiply defined in condition" {
898 "previously defined here" -
899 "included from here" {
905 # replace the original path in the output, when the file
907 if {[file exists
[file join $::GIT_WORK_TREE $path]]} {
909 if {$type eq
"warning" ||
$type eq
"error"} {
912 set msg
[string range
$line [lindex $imsg 0] [lindex $imsg 1]]
917 set pos
[string range
$line [lindex $ipos 0] [lindex $ipos 1]]
921 if {[regexp { \[([^
[]+)\]$} $msg _ cat
]} {
922 _update_diag_list
$this $cat
925 # (line in the output, line in the file, type of hit, message)
926 set new_hit
[list $mark $pos $type $msg $cat]
928 set exists
[array get file_info
$path]
930 # path unknown, add it
931 array set file_info
[list $path [list 0 0 [list]]]
932 # append this file to the list of path
933 lappend file_list
$path
935 foreach {p
info} [array get file_info
$path] break
936 foreach {nwarnings nerrors hits
} $info break
939 foreach e_hit
$hits {
940 foreach {e_mark e_pos e_type e_msg e_cat
} $e_hit break
950 if {$type eq
"error"} {incr nerrors
}
951 if {$type eq
"warning"} {incr nwarnings
}
953 lappend hits
$new_hit
954 set info [list $nwarnings $nerrors $hits]
956 array set file_info
[list $path $info]
957 set file_list_needs_update
1
961 set line
[string replace
$line [lindex $ipath 0] [lindex $ipath 1] $path]
963 # convert ipath and ipos after the original path was replaced
964 set offset
[expr [string length
$path] - $orig_path_len]
966 set ipath
[lreplace $ipath 1 1 [expr [lindex $ipath 1] + $offset]]
968 # shift the ipos only when it is not infront of the path
969 if {$ipos ne
{} && [lindex $ipos 0] > [lindex $ipath 0]} {
971 [expr [lindex $ipos 0] + $offset] \
972 [expr [lindex $ipos 1] + $offset]]
975 # file does not exists, clear ipath and ipos, so that there will
976 # be no tags for them
983 if {[regexp {^.
*?
: Entering directory
[`'
](.
*)'
} $line match path
]} {
984 # huh, path maybe empty?
986 lappend dir_stack
[file normalize
[file join [lindex $dir_stack end
] $path]]
991 if {[regexp {^.
*?
: Leaving directory
[`'
](.
*)'
} $line match path
]} {
992 # huh, path maybe empty?
994 set dir_stack
[lrange $dir_stack 0 end-1
]
1000 $w_output insert end
"$run_nl"
1003 if {$markup ne
{}} {
1004 $w_output insert end
"$line"
1005 foreach {posbegin colbegin posend colend
} $markup {
1007 foreach style
[lsort -integer [split $colbegin ";"]] {
1008 if {$style eq
"7"} {append prefix i
; continue}
1009 # ignore bold (1), because it doesn't buy us anything
1011 && ($style < 30 ||
$style > 37)
1012 && ($style < 40 ||
$style > 47)} {
1015 set a
"$mark linestart + $posbegin chars"
1016 set b
"$mark linestart + $posend chars"
1017 catch {$w_output tag add
$prefix$style $a $b}
1021 $w_output insert end
"$line" $type
1024 set i1
[$w_output index
"$mark + [lindex $ipath 0] chars"]
1025 set i2
[$w_output index
"$mark + [lindex $ipath 1] chars + 1 c"]
1026 $w_output tag add path
$i1 $i2
1028 # only add the pos tag, when there is a path too
1031 set i1
[$w_output index
"$mark + [lindex $ipos 0] chars"]
1032 set i2
[$w_output index
"$mark + [lindex $ipos 1] chars + 1 c"]
1033 $w_output tag add pos
$i1 $i2
1038 if {1.0 == $scroll_pos} {
1039 $w_output yview moveto
1.0
1043 fconfigure $current_fd -blocking 1
1044 if {[eof $current_fd]} {
1045 if {$exit_status eq
{}} {
1046 after cancel
$build_timer
1047 set build_end
[exec date
-R]
1048 set build_run_s
[expr [exec date
+%s
-d $build_end] - $build_start_s]
1050 set state committing
1052 if {[catch {close $current_fd} err errDict
]} {
1054 if {[dict get
$errDict -code] eq
1} {
1055 set exit_status
[lindex [dict get
$errDict -errorcode] 2]
1059 # close the fd to git-hash-object, so that we can read the
1060 # result on the other end in
1061 close $output_hash_out
1062 set build_tree
(output
) [list \
1065 [gets $output_hash_pipe]]
1066 close $output_hash_pipe
1067 set build_tree
(exit_status
) [list \
1070 [git hash-object
-w -t blob
--stdin <<$exit_status]]
1076 catch {close $current_fd}
1079 set file_list_needs_update
1
1088 fconfigure $current_fd -blocking 0
1091 $w_output conf
-state disabled
1093 if {$file_list_needs_update} {
1094 _update_file_list
$this
1098 catch {close $current_fd}
1099 catch {close $output_hash_out}
1100 catch {gets $output_hash_pipe}
1101 catch {close $output_hash_pipe}
1104 method _update_file_list
{} {
1105 # TODO: remeber current position and selection
1106 # we append only, or update the number of errors/warnings
1107 set files_scroll_pos
[$w_files yview
]
1108 set hits_scroll_pos
[$w_hits yview
]
1110 if {$file_list_busy} {
1113 set file_list_busy
1
1114 set file_list_needs_update
0
1115 set current_file_list
[list]
1117 foreach i
$ui_files_cols {
1118 $i tag remove in_sel
0.0 end
1119 $i conf
-state normal
1122 $w_errs conf
-width [expr $ui_errs_width + 1]
1123 set ui_errs_width_max
$ui_errs_width
1124 $w_warns conf
-width [expr $ui_warns_width + 1]
1125 set ui_warns_width_max
$ui_warns_width
1129 foreach path
$file_list {
1130 foreach {p
info} [array get file_info
$path] break
1131 foreach {nwarnings nerrors hits
} $info break
1133 # filter based on diagnostic type
1134 if {$current_diag == 1} {
1135 if {$nerrors == 0} continue
1137 } elseif
{$current_diag == 2} {
1138 if {$nwarnings == 0} continue
1140 } elseif
{$current_diag > 2} {
1143 set diag
[lindex $diag_list $current_diag]
1145 foreach {mark pos type msg cat
} $hit break
1146 if {$cat ne
$diag} continue
1147 if {$type eq
"error"} {incr nerrors
}
1148 if {$type eq
"warning"} {incr nwarnings
}
1150 if {($nerrors + $nwarnings) == 0} continue
1153 foreach i
$ui_files_cols {$i insert end
"$fl_nl"}
1156 lappend current_file_list
$path
1158 $w_files insert end
"[escape_path $path]"
1160 if {$nerrors == 0} {
1163 $w_errs insert end
"$nerrors" count
1164 set len
[string length
$nerrors]
1165 if {$ui_errs_width_max < $len} {
1166 set ui_errs_width_max
$len
1169 if {$nwarnings == 0} {
1172 $w_warns insert end
"$nwarnings" count
1173 set len
[string length
$nwarnings]
1174 if {$ui_warns_width_max < $len} {
1175 set ui_warns_width_max
$len
1179 if {$ui_errs_width != $ui_errs_width_max} {
1180 $w_errs conf
-width [expr $ui_errs_width_max + 1]
1182 if {$ui_warns_width != $ui_warns_width_max} {
1183 $w_warns conf
-width [expr $ui_warns_width_max + 1]
1185 foreach i
$ui_files_cols {
1186 $i conf
-state disabled
1190 many2scrollbar
$ui_files_cols yview
$w_vpane.f.sby
\
1191 [lindex $files_scroll_pos 0] \
1192 [lindex $files_scroll_pos 1]
1194 set file_list_busy
0
1196 if {[llength $current_file_list] != 0} {
1197 if {$current_path eq
{}} {
1198 # select the first file, when no one is selected
1199 set current_path
[lindex $current_file_list 0]
1202 # restore selection of current path
1203 set lno
[lsearch -exact $current_file_list $current_path]
1207 foreach i
$ui_files_cols {
1208 $i tag add in_sel
$lno.0 "$lno.0 + 1 line"
1212 # reaload file and jump to last scroll pos
1213 _show_hits_for_file
$this $current_path $hits_scroll_pos
1216 method _select_from_file_list
{x y
} {
1217 if {$file_list_busy} return
1219 # TODO: remeber scroll pos, when updating the same path?
1221 set lno
[lindex [split [$w_files index
@0,$y] .
] 0]
1222 set path
[lindex $current_file_list [expr {$lno - 1}]]
1224 foreach i
$ui_files_cols {
1225 $i tag remove in_sel
0.0 end
1232 foreach i
$ui_files_cols {
1233 $i tag add in_sel
$lno.0 "$lno.0 + 1 line"
1236 _show_hits_for_file
$this $path
1239 method _show_hits_for_file
{path
{scroll_pos
{}}} {
1240 if {$hits_busy} return
1243 set current_path
$path
1245 foreach i
$ui_hits_cols {
1246 $i conf
-state normal
1248 $i conf
-state disabled
1250 $w_lnos conf
-width [expr $ui_lnos_width + 1]
1251 set ui_lnos_width_max
$ui_lnos_width
1255 # re-build current_path_lno_hits
1256 array set current_path_lno_hits
{}
1258 if {$current_path eq
{}} {
1263 foreach {p path_info
} [array get file_info
$current_path] break
1264 foreach {nwarnings nerrors path_hits
} $path_info break
1266 set diag
[lindex $diag_list $current_diag]
1267 foreach hit
$path_hits {
1268 foreach {mark pos type msg cat
} $hit break
1270 # filter based on diagnostic type
1271 if { ($current_diag == 1 && $type != "error")
1272 ||
($current_diag == 2 && $type != "warning")
1273 ||
($current_diag > 2 && $cat ne
$diag)} continue
1277 set lno
[lindex [split $pos :] 0]
1280 set lno_entry
[array get current_path_lno_hits
$lno]
1281 if {$lno_entry eq
{}} {
1282 # lno unknown, add it
1283 set lno_info
[list -1 [list]]
1285 foreach {_lno lno_info
} $lno_entry break
1287 foreach {primary_hit lno_hits
} $lno_info break
1288 if {$primary_hit != -1} {
1289 foreach {p_mark p_pos p_type p_msg
} [lindex $lno_hits $primary_hit] break
1290 if {$type eq
"error" && $p_type eq
"warning"} {
1291 set primary_hit
[llength $lno_hits]
1296 lappend lno_hits
$hit
1297 array set current_path_lno_hits
[list $lno [list $primary_hit $lno_hits]]
1300 set lnos
[lsort -integer [array names current_path_lno_hits
]]
1302 # insert hits without line information
1303 if {[llength $lnos] > 0 && [lindex $lnos 0] == 0} {
1304 set lnos
[lrange $lnos 1 end
]
1306 foreach i
$ui_hits_cols {$i conf
-state normal
}
1308 foreach {lno
info} [array get current_path_lno_hits
0] break
1309 foreach {primary_hit hits
} $info break
1311 foreach {mark pos type msg cat
} $hit break
1313 $w_lnos insert end
"$hits_nl"
1314 $w_hits insert end
"$hits_nl"
1317 $w_hits insert end
"$mark" jumpmark
1318 $w_hits insert end
"$msg" $type
1321 foreach i
$ui_hits_cols {$i conf
-state disabled
}
1324 if {[llength $lnos] == 0} {
1325 if {$scroll_pos ne
{}} {
1326 many2scrollbar
$ui_hits_cols yview
$w_vpane.o.sby
\
1327 [lindex $scroll_pos 0] \
1328 [lindex $scroll_pos 1]
1334 set cmd
[list | git grep
--no-color
-h -n -p -3]
1337 lappend args
-@ $lno
1339 if {[file pathtype
$current_path] eq
"relative"} {
1340 if {$build_history_pos >= 0} {
1341 foreach {build_c build_t build_run_s _cmd
} [lindex $build_history $build_history_pos] break
1342 lappend args
"$build_c:worktree"
1345 set ::GIT_WORK_TREE "/"
1346 lappend cmd
--no-index
1348 lappend args
-- $current_path
1349 lappend cmd
{*}$args
1351 if {[catch {set fd
[open $cmd r
]} err
]} {
1353 # fallback to GNU nl and GNU grep to get the content
1354 set cmd2
[list | nl
-s: -w1 -ba -- $current_path | env
-u GREP_OPTIONS grep
--color=never
-C 3]
1356 lappend cmd2
-e "^$lno:"
1358 if {[catch {set fd
[open $cmd2 r
]} err2
]} {
1362 -title {gui-grep
: fatal
error} \
1363 -message "failed: $cmd\n$err\n\nfallback failed: $cmd2\n$err2"
1371 fconfigure $fd -eofchar {}
1377 fileevent $fd readable
[cb _read_file
$fd $scroll_pos]
1380 method _read_file
{fd scroll_pos
} {
1381 foreach i
$ui_hits_cols {$i conf
-state normal
}
1383 while {[gets $fd line
] >= 0} {
1389 if {[regexp {^
--} $line]} {
1393 # remove any color from lno and sep
1394 regexp {^
(\d
+)([-:=])(.
*)$} $line match lno line_type line
1395 regsub {\r$} $line {} line
1396 if { $line_type eq
{:}
1397 && [array get current_path_lno_hits
$lno] ne
{}} {
1398 foreach {lno
info} [array get current_path_lno_hits
$lno] break
1399 foreach {primary_hit hits
} $info break
1401 # the actual line has the mark and the aux message of the primamry hit
1402 foreach {mark h_lno h_type auxmsg
} [lindex $hits $primary_hit] break
1405 foreach {h_mark h_pos h_type h_msg h_cat
} $hit break
1407 $w_lnos insert end
"$hits_nl"
1408 $w_hits insert end
"$hits_nl"
1411 $w_lnos insert end
"$h_pos" $h_type
1412 set len
[string length
$h_pos]
1413 if {$ui_lnos_width_max < $len} {
1414 set ui_lnos_width_max
$len
1417 $w_hits insert end
"$h_mark" jumpmark
1418 $w_hits insert end
"$h_msg" $h_type
1423 $w_lnos insert end
"$hits_nl"
1424 $w_hits insert end
"$hits_nl"
1427 $w_lnos insert end
"$lno" normal
1428 set len
[string length
$lno]
1429 if {$ui_lnos_width_max < $len} {
1430 set ui_lnos_width_max
$len
1434 $w_hits insert end
"$mark" jumpmark
1436 if {$auxmsg ne
{}} {
1437 $w_hits insert end
"$auxmsg" auxmark
1439 $w_hits insert end
"$line" normal
1445 #update line number column width
1446 if {$ui_lnos_width != $ui_lnos_width_max} {
1447 $w_lnos conf
-width [expr $ui_lnos_width_max + 1]
1450 if {$scroll_pos ne
{}} {
1451 many2scrollbar
$ui_hits_cols yview
$w_vpane.o.sby
\
1452 [lindex $scroll_pos 0] \
1453 [lindex $scroll_pos 1]
1459 foreach i
$ui_hits_cols {$i conf
-state disabled
}
1465 method _jump_to_hit_in_output
{x y
} {
1470 if {$current_path eq
{}} {
1474 set imark
[$w_hits tag nextrange jumpmark
"@$x,$y linestart" "@$x,$y lineend"]
1479 set mark
[$w_hits get
[lindex $imark 0] [lindex $imark 1]]
1481 $w_output tag remove currenthit
0.0 end
1482 $w_output tag add currenthit
"$mark linestart" "$mark lineend"
1485 method _open_from_hits
{x y
} {
1490 if {$current_path eq
{}} {
1496 set wlno
[$w_lnos search
-regexp {^
[[:digit
:]]+(?
::[[:digit
:]]+)?
$} "@0,$y linestart" end
]
1498 set wlno
[$w_lnos search
-backwards -regexp {^
[[:digit
:]]+(?
::[[:digit
:]]+)?
$} "@0,$y linestart" 1.0]
1501 set lno
[lindex [split [$w_lnos get
"$wlno" "$wlno lineend"] :] 0]
1502 set iaux
[$w_hits tag nextrange auxmark
"@$x,$y linestart" "@$x,$y lineend"]
1504 set aux
[$w_hits get
[lindex $iaux 0] [lindex $iaux 1]]
1506 set aux
[$w_hits get
-displaychars "@0,$y linestart" "@0,$y lineend"]
1510 open_in_git_editor
$current_path $lno 0 $aux
1513 method _safe_cmd
{} {
1514 set cmd
[$w_entry get
]
1515 $w_entry delete
0 end
1516 if {[lindex $cmd_history 1] ne
$cmd} {
1517 set cmd_history
[linsert $cmd_history 1 $cmd]
1518 set cmd_history
[lreplace $cmd_history 0 0 ""]
1520 set cmd_history_pos
0
1523 method _prev_cmd
{} {
1524 if {[expr [llength $cmd_history] - 1] > $cmd_history_pos} {
1525 if {$cmd_history_pos == 0} {
1526 set cmd_history
[lreplace $cmd_history 0 0 [$w_entry get
]]
1528 incr cmd_history_pos
1529 $w_entry delete
0 end
1530 $w_entry insert
0 [lindex $cmd_history $cmd_history_pos]
1534 method _next_cmd
{} {
1535 if {0 < $cmd_history_pos} {
1536 incr cmd_history_pos
-1
1537 $w_entry delete
0 end
1538 $w_entry insert
0 [lindex $cmd_history $cmd_history_pos]
1542 method _search_prev_cmd
{} {
1543 set cursor
[$w_entry index insert
]
1546 $w_entry icursor
$cursor
1550 set prefix
[string range
[$w_entry get
] 0 $cursor]
1551 for {set i
[expr $cmd_history_pos + 1]} {$i < [llength $cmd_history]} {incr i
} {
1552 set cmd
[lindex $cmd_history $i]
1553 if {[string range
$cmd 0 $cursor] eq
$prefix} {
1554 set cmd_history_pos
$i
1555 $w_entry delete
0 end
1556 $w_entry insert
0 $cmd
1557 $w_entry icursor
[expr $cursor + 1]
1563 method _search_next_cmd
{} {
1564 set cursor
[$w_entry index insert
]
1567 $w_entry icursor
$cursor
1571 set prefix
[string range
[$w_entry get
] 0 $cursor]
1572 for {set i
[expr $cmd_history_pos - 1]} {$i > 0} {incr i
-1} {
1573 set cmd
[lindex $cmd_history $i]
1574 if {[string range
$cmd 0 $cursor] eq
$prefix} {
1575 set cmd_history_pos
$i
1576 $w_entry delete
0 end
1577 $w_entry insert
0 $cmd
1578 $w_entry icursor
[expr $cursor + 1]
1584 method _prev_build
{} {
1585 if {[llength $build_history] > ($build_history_pos + 1)} {
1586 incr build_history_pos
1591 method _next_build
{} {
1592 if {0 < $build_history_pos} {
1593 incr build_history_pos
-1
1599 if {$build_history_pos >= 0} return
1601 after cancel
$build_timer
1602 set build_end
[exec date
-R]
1603 set build_run_s
[expr [exec date
+%s
-d $build_end] - $build_start_s]
1606 fconfigure $current_fd -blocking 1
1607 foreach p
[pid $current_fd] {
1608 catch {exec kill
$p}
1610 catch {close $output_hash_out}
1611 catch {gets $output_hash_pipe}
1612 catch {close $output_hash_pipe}
1614 if {[catch {close $current_fd} err opts
]} {
1615 set details
[dict get
$opts -errorcode]
1616 # we killed the child ourself, don't handle this as an error
1617 if { [lindex $details 0] ne
{CHILDKILLED
}
1618 && [lindex $details 2] ne
{SIGKILL
}} {
1632 method _select_diagnostics
{} {
1633 $w_diags selection clear
1634 set current_diag
[$w_diags current
]
1635 set file_list_needs_update
1
1636 _update_file_list
$this
1639 method _reset_diag_list
{} {
1640 set diag_list
[list "All" "Errors" "Warnings"]
1643 foreach diag
$diag_list {
1644 set cx
[string length
$diag]
1645 if {$cx > $width} {set width
$cx}
1647 $w_diags configure
-values $diag_list
1648 $w_diags configure
-width $width
1649 $w_diags current
$current_diag
1652 method _update_diag_list
{diag
} {
1653 set exists
[lsearch -exact $diag_list $diag]
1654 if {$exists != -1} return
1656 lappend diag_list
$diag
1657 $w_diags configure
-values $diag_list
1659 set cx
[string length
$diag]
1660 if {$cx > [$w_diags cget
-width]} {
1661 $w_diags configure
-width $cx
1663 $w_diags current
$current_diag
1666 method _always_takefocus
{w
} {
1670 method reorder_bindtags
{} {
1671 foreach i
[list $w_entry] {
1672 bindtags $i [list all
$i [winfo class
$i] .
]
1676 method link_vpane
{vpane
} {
1677 bind $w_vpane <Map
> [cb _on_pane_mapped
$vpane]
1680 method _on_pane_mapped
{master_vpane
} {
1682 after idle
[list after idle
[list $w_vpane sashpos
0 [$master_vpane sashpos
0]]]
1684 after idle
[list after idle
\
1685 [list $w_vpane sash
place 0 \
1686 [lindex [$master_vpane sash coord
0] 0] \
1687 [lindex [$w_vpane sash coord
0] 1]]]
1691 method _open_from_output
{x y
} {
1692 set ipath
[$w_output tag nextrange path
"@$x,$y linestart" "@$x,$y lineend"]
1694 set path
[$w_output get
[lindex $ipath 0] [lindex $ipath 1]]
1697 set ipos
[$w_output tag nextrange pos
"@$x,$y linestart" "@$x,$y lineend"]
1699 set pos
[$w_output get
[lindex $ipos 0] [lindex $ipos 1]]
1700 set lno
[lindex [split $pos :] 0]
1703 open_in_git_editor
$path $lno
1707 method _update_path_label
{args
} {
1708 # any change to current_path makes the current_path_lno_hits array invalid
1709 array unset current_path_lno_hits
1711 if {$current_path eq
{}} {
1712 set current_path_label
""
1714 set current_path_label
"File: [escape_path $current_path]"
1718 method _copy_path
{} {
1726 method _update_cmd_label
{args
} {
1727 $w_entry conf
-state normal
1728 if {$current_cmd eq
{}} {
1729 set current_cmd_label
""
1733 set current_cmd_label
"[_get_runtime $this] Running command: $current_cmd"
1734 $w_entry conf
-state disabled
1735 $w_indicator conf
-foreground white
-background blue
1738 set current_cmd_label
"[_get_runtime $this] Successful command: $current_cmd"
1739 $w_indicator conf
-foreground black
-background green
1742 set current_cmd_label
"[_get_runtime $this] Failed command: $current_cmd"
1743 $w_indicator conf
-foreground black
-background red
1746 set current_cmd_label
"[_get_runtime $this] Canceling command: $current_cmd"
1747 $w_indicator conf
-foreground black
-background cyan
1750 set current_cmd_label
"[_get_runtime $this] Committing command: $current_cmd"
1751 $w_indicator conf
-foreground black
-background orange
1754 set current_cmd_label
"[_get_runtime $this] Loading command: $current_cmd"
1755 $w_entry conf
-state disabled
1756 $w_indicator conf
-foreground white
-background blue
1760 if {$state_change_cb ne
{}} {
1761 eval $state_change_cb $state
1766 method _get_runtime
{} {
1767 set m
[expr $build_run_s / 60]
1768 set s
[expr $build_run_s % 60]
1772 if {$build_history_pos >= 0
1773 && ![catch {set relative_start
"[exec git log -1 -g --pretty=%ar $build_ref@{$build_history_pos}]"} err
]} {
1774 return "@{$relative_start} \[$m:$s\]"
1779 method _update_runtime
{} {
1780 set new_build_run_s
[expr [exec date
+%s
] - $build_start_s]
1781 if {$new_build_run_s > $build_run_s} {
1782 set build_run_s
$new_build_run_s
1785 set build_timer
[after 250 [cb _update_runtime
]]
1788 method _commit_build
{} {
1790 foreach name
[array names static_build_tree
] {
1791 foreach {mode type hash
} $static_build_tree($name) break
1792 append ls_tree
"$mode $type $hash\t$name\n"
1794 foreach name
[array names build_tree
] {
1795 foreach {mode type hash
} $build_tree($name) break
1796 append ls_tree
"$mode $type $hash\t$name\n"
1798 set tree
[git mktree
<<$ls_tree]
1800 set cmd
[$w_entry get
]
1803 set restore_envs
[modify_env
[list \
1804 GIT_AUTHOR_DATE
1 $build_start \
1805 GIT_COMMITTER_DATE
1 $build_end \
1808 set commit
[git commit-tree
$tree <<$cmdn]
1810 restore_env
$restore_envs
1812 set reflog
[gitdir logs
$build_ref]
1813 if {[file exists
$reflog] ||
![catch {
1814 file mkdir
[file dirname
$reflog]
1815 set fd
[open $reflog a
]
1818 exec git update-ref
-m $cmd $build_ref $commit
1821 set build_history
[linsert $build_history 0 [list \
1826 set build_history_pos
0
1829 method _files_scroll_line
{dir
} {
1830 if {$file_list_busy} return
1832 if {[catch {$w_files index in_sel.first
}]} {
1836 set lno
[lindex [split [$w_files index in_sel.first
] .
] 0]
1839 set path
[lindex $current_file_list [expr {$lno - 1}]]
1844 foreach i
$ui_files_cols {
1845 $i tag remove in_sel
0.0 end
1846 $i tag add in_sel
$lno.0 "$lno.0 + 1 line"
1850 _show_hits_for_file
$this $path
1853 method _files_scroll_page
{dir
} {
1854 if {$file_list_busy} return
1856 $w_files yview scroll
$dir pages
1858 [lindex [$w_files yview
] 0]
1859 * [llength $current_file_list]
1862 set path
[lindex $current_file_list [expr {$lno - 1}]]
1867 foreach i
$ui_files_cols {
1868 $i tag remove in_sel
0.0 end
1869 $i tag add in_sel
$lno.0 "$lno.0 + 1 line"
1873 _show_hits_for_file
$this $path
1876 method _visible
{} {
1877 if {[$ui_finder visible
]} {
1878 focus [$ui_finder editor
]
1884 method _get_envmods
{} {
1885 set env_mods
$envmods
1887 foreach config
$configmods {
1888 foreach mod
[_get_buildconfig
$this $config] {
1889 if {[regexp {^
([A-Za-z0-9_
]+)\s
*((?
:[-+%].?
)?
=)\s
*(.
*)$} $mod match name op value
]} {
1890 lappend env_mods
$name $op $value
1891 } elseif
{[regexp {^
!([A-Za-z0-9_
]+)$} $mod match name
]} {
1892 lappend env_mods
$name ! {}
1899 method _popup_configs
{X Y
} {
1904 $m_configs delete
0 end
1906 array unset selected_configs
1908 array unset menu_hierarchy
1909 # build the menu hierarchy first without actually entries
1910 foreach full_config
[lsort [array names buildconfig_config gui.buildconfig.
*.env
]] {
1911 set config
[string range
$full_config [string length
{gui.buildconfig.
}] end-
[string length
{.env
}]]
1913 set names
[split $config "/"]
1914 set parent
$m_configs
1915 for {set i
0} {$i < [llength $names]-1} {incr i
} {
1916 set subname
[join [lrange $names 0 $i] "/"]
1918 if {![info exists menu_hierarchy
($subname)]} {
1919 set subid
$parent.t
[incr buildconfig_menu_id
]
1920 $parent add cascade
\
1921 -label [lindex $names $i] \
1923 menu $subid -tearoff 0
1925 set menu_hierarchy
($subname) $subid
1927 set parent
$menu_hierarchy($subname)
1931 foreach full_config
[lsort [array names buildconfig_config gui.buildconfig.
*.env
]] {
1932 set config
[string range
$full_config [string length
{gui.buildconfig.
}] end-
[string length
{.env
}]]
1933 if {[lsearch -exact $configmods $config] >= 0} {
1934 set selected_configs
($config) 1
1936 set selected_configs
($config) 0
1939 set names
[split $config "/"]
1940 set parent
$m_configs
1941 for {set i
0} {$i < [llength $names]-1} {incr i
} {
1942 set subname
[join [lrange $names 0 $i] "/"]
1943 set parent
$menu_hierarchy($subname)
1946 if {[info exists menu_hierarchy
($config)]} {
1947 $menu_hierarchy($config) insert
0 separator
1948 $menu_hierarchy($config) insert
0 checkbutton \
1949 -label [_get_buildconfig
$this $config title
"This"] \
1950 -command [cb _update_configs_from_menu
] \
1951 -variable ${__this
}::selected_configs($config) \
1955 $parent add
checkbutton \
1956 -label [_get_buildconfig
$this $config title
[lindex $names end
]] \
1957 -command [cb _update_configs_from_menu
] \
1958 -variable ${__this
}::selected_configs($config) \
1963 if {[array size selected_configs
] > 0} {
1964 tk_popup $m_configs $X $Y
1968 method _load_config
{} {
1971 array unset buildconfig_config
1972 # make this a list and iterate over all commands
1973 set cmd
[get_config gui.build.configcommand
{}]
1975 _parse_config buildconfig_config
[list open_read
$cmd]
1977 foreach name
[array names repo_config
] {
1978 if {[catch {set v
$buildconfig_config($name)}]} {
1979 set buildconfig_config
($name) $repo_config($name)
1984 method _get_buildconfig
{config
{var
{env
}} {default {}}} {
1985 if {[catch {set v
$buildconfig_config(gui.buildconfig.
$config.
$var)}]} {
1992 method _update_configs_from_menu
{} {
1993 set configmods
[list]
1994 foreach config
[array names selected_configs
] {
1995 if {$selected_configs($config)} {
1996 lappend configmods
$config
2003 proc envargs
{envmods
} {
2005 array set newenv
[array get env
]
2007 foreach {name op value
} $envmods {
2009 if {[info exists newenv
($name)]} {
2010 # remember, that the variable was set
2011 set old
$newenv($name)
2014 if {![regexp {([-+%])(.
)=} $op match op sep
]} {
2015 regexp {([-+%])=} $op match op
2017 if {[string first
$op "-+%"] >= 0 && $old ne
{}} {
2019 set l
[split $old $sep]
2020 set e
[lsearch -exact $l $value]
2022 set l
[concat [lrange $l 0 $e-1] [lrange $l $e+1 end
]]
2023 set e
[lsearch -exact $l $value]
2025 set old
[join $l $sep]
2027 set f
[string first
$value $old]
2029 set old
[string replace
$old $f $f+[string length
$value]]
2030 set f
[string first
$value $old]
2034 set newenv
($name) ${old
}${sep
}${value
}
2035 } elseif
{$op eq
"%"} {
2036 set newenv
($name) ${value
}${sep
}${old
}
2039 set newenv
($name) ${old
}
2041 } elseif
{$op eq
"!"} {
2042 catch {unset newenv
($name)}
2044 set newenv
($name) $value
2049 foreach name
[array names env
] {
2050 if {![info exists newenv
($name)]} {
2051 lappend env_args
-u $name
2054 foreach name
[array names newenv
] {
2055 if {![info exists env
($name)]} {
2056 lappend env_args
$name=$newenv($name)
2057 } elseif
{$env($name) ne
$newenv($name)} {
2058 lappend env_args
$name=$newenv($name)
2066 proc modify_env
{envmods
} {
2069 set restore_envs
[list]
2070 foreach {name
set value
} $envmods {
2071 if {[info exists env
($name)]} {
2072 # remember, that the variable was set
2073 lappend restore_envs
$name 1 $env($name)
2075 lappend restore_envs
$name 0 {}
2078 set env
($name) $value
2080 catch {unset env
($name)}
2083 return $restore_envs
2086 proc restore_env
{envrestores
} {
2088 foreach {name
set value
} $envrestores {
2090 set env
($name) $value