📄 greppane.tcl
字号:
Focus } destructor { itcl::delete object $driver } method handle_cancel {} { if {${cancelcommand} != ""} { eval ${cancelcommand} } } private method disp_filter {combo txt} { foreach l ${PatternFormats} { if {${txt} == [lindex ${l} 0]} { set GrepPatFilter [lindex ${l} end] break } } } # Format the current value of -pattern public method FormatPattern {} { set pat $pattern if {${pat} != ""} { # Convert string to be used for grep regsub -all {\^|\\|\.|\*|\$|\-|\[|\]} ${pat} {\\&} pat regsub -all {\<|\>} ${pat} {[&]} pat } } private method refresh_combo_history {} { global sn_options global history_List if {![info exists history_List(grep)]} { set history_List(grep) "" } set lbls "" foreach e $history_List(grep) { set lbl [lindex ${e} 2] set len [string first " " ${lbl}] lappend lbls [string range ${lbl} [expr {${len} + 1}] end] } $itk_component(pattern) configure -contents ${lbls} # Add file filter to the history stack of the file filters sn_add_to_histroy_stack sn_options(history,grep,file) \ [$itk_component(filepattern) cget -entrytext] $itk_component(filepattern) configure -contents $sn_options(history,grep,file) } # This method is invoked by the grep history combo box, it # resets the history based on the pattern in the combobox private method history_combo_select_command {txt} { global sn_options global history_List # FIXME: this is a terrible interface, we need a History class !! # Search the history array to see if we can find a match for # the given pattern like "grep Tcl_(*.tcl)" foreach l $history_List(grep) { if {[lindex ${l} 2] == "grep ${txt}"} { set args [lindex ${l} 1] sn_log "Now to reset grep history to \{$args\}" if {[llength $args] == 4} { # FIXME: This means and old "grep history" was pulled out of an # old project file, we did not want to make the file format # incompatible so we just hack around it for now foreach {pat fpat} $args break set icase $GrepNocase } else { foreach {pat fpat icase} $args break } # Split the arguments up and pass them, don't use eval! $this GrepResetFromHistory $pat $fpat $icase return } } } public method StartGrep {} { global sn_options sn_path global errorInfo errorCode # When the user click on the Search button, the very first thing # we want to do is disable search and related widgets. if {${Proceed} == 0} { handle_proceed disabled after idle [list $this StartGrep] return } set pat ${pattern} if {[string compare [string trim ${pat}] ""] == 0} { handle_proceed normal return } set valid [$driver isValidPattern ${pattern}] if {$valid != "1"} { handle_proceed normal sn_error_dialog ${valid} return } # Set toplevel window title to a tool specific string SetTitle # Pattern for files to search, AKA file name filter set filter ${filepattern} # Convert "\" into "/" on windows set filter [file nativename $filter] # Read matched files from the project file set files [lsort -command sn_compare \ [lmatch -glob [sn_project_file_list 0] ${filter}]] # Count files set files_Count [llength ${files}] # No files matched the file filter if {$files_Count == 0} { sn_error_dialog "[get_indep String ErrorNoMatches] \"${filepattern}\" !" handle_proceed normal return } # The actual count is off by one because we update the % done meter # based on the match read back from grep incr files_Count -1 $itk_component(progressbar) configure -maxvalue ${files_Count} # If there is a pattern filter, substitute the current # value of ${pat} into the %s in the filter set pat_filt ${GrepPatFilter} if {[string compare ${pat_filt} ""] != 0} { if {[regsub -all {%s} ${pat_filt} ${pat} pat_filt]} { set pat ${pat_filt} } } else { regsub -all {\<} ${pat} {\\<} pat regsub -all {\>} ${pat} {\\>} pat } # Remove tabs from the pattern regsub -all {\\t} ${pat} "\t" pat tixBusy $itk_component(results) on update idletasks $itk_component(results) config -state normal $itk_component(results) delete 0.0 end $itk_component(results) config -state disabled # Clear selected line property set text_b1_current_line_num -1 tixBusy $itk_component(results) off # FIXME : use one but not both! update idletasks update # Disable horizontal scrolling during the grep. This is to # prevent the horizontal scroll bar from flying all over the # place while the grep is running $itk_component(hscroll) configure -command {} $itk_component(results) configure -xscrollcommand {} sn_log "GREP: detach horizontal scroll" $driver start $pat $files $GrepNocase $maxmatches finish_grep } # Grab the current selection from the window system # and put it in the pattern text box. Use passed in # pat if given. public method setPatternFromClipboard { {pat {}} } { if {$pat == {} && [catch {set pat [string trim [selection get]]}]} { bell sn_error_dialog \ [get_indep String NoSelection] \ [get_indep String MultiGrep] return } set pattern $pat } # Invoked when the user presses the Cancel button private method cancel_grep {} { ${driver} cancel } # Do everything that is needed to return the widget to the state # it was in before the grep was started. Also colorize results. private method finish_grep {} { # The text tagging could take quite some time, so block the GUI tixBusy $itk_component(results) on update idletasks set t $itk_component(results) $driver finish $t see end # Add the grep info to the history sn_log "adding \{${pattern} ${filter} ${GrepNocase}\} to history" # This 3.0 business is a goofy thing that the text # widget does. We just want to find out if the text # widget has any matches (meaning it is not empty) if {[$t index end] >= 3.0} { sn_add_history grep [list ${pattern} ${filter} ${GrepNocase}] \ [sn_make_history_title grep ${filter} ${pattern}] \ [itcl::code $this GrepResetFromHistory] refresh_combo_history } # Re-attach the horizontal scrollbar to the text widget sn_log "re-attach horizontal scroll" $itk_component(hscroll) configure -command "$itk_component(results) xview" $itk_component(results) configure \ -xscrollcommand "$itk_component(hscroll) set" # Make sure horizontal scrollbar is against the left edge $itk_component(results) xview moveto 0 # Release the GUI block tixBusy $itk_component(results) off handle_proceed normal } # User seleted a pattern from the histroy, reset our widgets to that pattern # and run a new grep. private method GrepResetFromHistory {oldpattern oldfilepattern oldicase} { set pattern ${oldpattern} set filepattern ${oldfilepattern} set GrepNocase $oldicase sn_log "GrepResetFromHistory $oldpattern $oldfilepattern $oldicase" $this StartGrep }# FIXME: all of this functionality needs to be in a more general superclass! #disable/enable input fields when the process is running/terminated private method handle_proceed {state} { if {${state} == "normal"} { set wasLineSelected 0 $itk_component(search) configure -state normal $itk_component(cancel) configure -state disabled pack forget $itk_component(progressbar) set Proceed 0 $itk_component(search) configure -state normal bind $itk_component(hull) <Return> [itcl::code ${this} StartGrep] } else { set Proceed 1 set wasLineSelected 0 $itk_component(search) configure -state ${state} $itk_component(cancel) configure -state normal bind $itk_component(hull) <Return> {} # Display the state of the grep command pack $itk_component(progressbar) -side right -fill y } # Set widget state, this will change the color for a label # and make an entry or button inactive foreach component {pattern filepattern filtercombo case limit lines-label format prev next} { $itk_component($component) configure -state ${state} } } # Get the currently selected grep results line method Split_Line {} { global sn_options set line $exported_current_line # calculate the remaining line in the source file to highlight # the found grep pattern if {${line} != ""} { set foundidx [expr {[string length [lrange [split ${line} :] 0 1]]\ + 1}] set textualline [string range ${line} ${foundidx} end] } else { return "" } set pars [sn_goto_comp_error_or_grep ${line}] if {${pars} == ""} { return "" } set file [lindex ${pars} 0] set pos [lindex ${pars} 1]# FIXME: This does not convert path names like /tmp/foo/foo.c into foo/foo.c !!! set file [sn_convert_FileName ${file}] return [list ${file} ${pos}] } private method next_entry {amount} { $this incr_selected_line $amount return [handle_single_click] } method Title {{full 1}} { global sn_options set t [string trimright [get_indep String MultiGrep] "."] set txt $pattern if {${txt} != ""} { set t "${t}: ${txt}" } if {${full}} { return [sn_title ${t}] } else { return ${t} } } method Icon {} { return [sn_view_icon [get_indep String MultiGrep]] } method SetTitle {} { set topw [winfo toplevel $itk_component(hull)] ${topw} configure -title [Title] -iconname [Icon] } # A single click will select a given line, if we have # an split pane goto the given symbol in the other pane. # Note that we set exported_current_line here, it # does not get set by a double click. private method handle_single_click {} { set exported_current_line $text_current_line if {$itk_option(-selectcommand) != ""} { tixBusy $itk_component(results) on update idletasks set ret [eval $itk_option(-selectcommand) [Selection]] highlight_editor_matches tixBusy $itk_component(results) off } else { set ret 0 } set wasLineSelected 1 return ${ret} } # This method seems to display a selected line from the grep # results in a split pane editor.# FIXME: This line hightlight and tagging code is a mess method highlight_editor_matches {} { global sn_options # Highlight the match in the editor. if {$itk_option(-next) != "" && [$itk_option(-next) whoami] == "edit" && ${foundranges} != ""} { set ed [$itk_option(-next) editor]# FIXME: This is screwing around with the editor text widget! very ugly. #verify if the line in the editor has been changed if {${textualline} != [${ed} get "${foundline}.0" "${foundline}.end"]} { if {$sn_options(def,grep-mark-all)} { ${ed} tag remove sel 0.0 end }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -