From 20c97bd5000c452c7aee435112d985b464698b42 Mon Sep 17 00:00:00 2001 From: slagernate Date: Thu, 7 May 2026 16:02:36 -0700 Subject: [PATCH] file_chooser: add fuzzy subsequence search inline in .ins dialog --- src/xschem.tcl | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/xschem.tcl b/src/xschem.tcl index ebae6a8d..ee1f4f89 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -5839,6 +5839,77 @@ proc file_chooser_delete {} { } #### maxdepth: how many levels to descend for each $paths directory (-1: no limit) +proc fuzzy_chooser_inline {q} { + global file_chooser new_file_browser_depth new_file_browser_ext pathlist + if {$q eq {}} { + set file_chooser(files) {} + set file_chooser(fullpathlist) {} + set file_chooser(nitems) 0 + .ins.center.leftdir.l selection clear 0 end + file_chooser_dirlist + return + } + set nfbe $new_file_browser_ext + if {[catch {regexp $nfbe {12345}}]} { set nfbe {} } + set allfiles [match_file {} {} $new_file_browser_depth 1] + set scored {} + foreach f $allfiles { + if {$nfbe ne {}} { + set ok 0 + catch {set ok [regexp $nfbe $f]} + if {!$ok} continue + } + set sc [fuzzy_subseq_score $q $f] + if {$sc >= 0} { lappend scored [list $sc $f] } + } + set sorted [lsort -decreasing -integer -index 0 $scored] + set hits {} + set n 0 + foreach pair $sorted { + if {$n >= 500} break + lappend hits [lindex $pair 1] + incr n + } + set seen_dir [dict create] + set new_dirs {} + foreach f $hits { + set d [file dirname $f] + if {![dict exists $seen_dir $d]} { + dict set seen_dir $d 1 + lappend new_dirs $d + } + } + set new_tails {} + foreach d $new_dirs { + set t {} + foreach p $pathlist { + set pp [file dirname $p]/ + if {[string first $pp $d] == 0} { + set t [string range $d [string length $pp] end] + break + } + } + if {$t eq {}} { set t [file tail $d] } + lappend new_tails $t + } + set file_chooser(dirs) $new_dirs + set file_chooser(dirtails) $new_tails + set file_chooser(files) $hits + set file_chooser(fullpathlist) $hits + set file_chooser(nitems) [llength $hits] + global dark_gui_colorscheme + if {$dark_gui_colorscheme} { set col cyan } else { set col blue } + set i 0 + foreach p $file_chooser(dirs) { + if {[lsearch -exact $pathlist $p] != -1} { + .ins.center.leftdir.l itemconfigure $i -foreground $col -selectforeground $col + } else { + .ins.center.leftdir.l itemconfigure $i -foreground black -selectforeground black + } + incr i + } +} + proc file_chooser {} { global file_chooser new_file_browser_ext new_file_browser_depth USER_CONF_DIR set file_chooser(action) load @@ -5963,6 +6034,14 @@ proc file_chooser {} { entry .ins.top3.ext_e -width 30 -takefocus 0 -state normal -textvariable new_file_browser_ext balloon .ins.top3.ext_e "Show only files matching the\nextension regular expression" + label .ins.top3.fzf_l -text { Fuzzy:} + entry .ins.top3.fzf_e -width 25 -highlightcolor red -highlightthickness 2 \ + -highlightbackground [option get . background {}] + balloon .ins.top3.fzf_e "Subsequence-match across all library paths.\nLeft pane shows dirs with hits; middle pane shows full paths." + bind .ins.top3.fzf_e { + fuzzy_chooser_inline [.ins.top3.fzf_e get] + } + button .ins.top4.select_current -takefocus 0 -text {Select current} -command { set file_chooser(regex) {} file_chooser_select [xschem get schname] @@ -6033,6 +6112,10 @@ proc file_chooser {} { } bind .ins.top3.pat_e { + if {[winfo exists .ins.top3.fzf_e] && [.ins.top3.fzf_e get] ne {}} { + .ins.top3.fzf_e delete 0 end + fuzzy_chooser_inline {} + } file_chooser_search current } bind .ins.center.leftdir.l <> { @@ -6135,6 +6218,8 @@ proc file_chooser {} { pack .ins.top.editpaths -side left pack .ins.top3.ext_l -side left pack .ins.top3.ext_e -side left + pack .ins.top3.fzf_l -side left + pack .ins.top3.fzf_e -side left if { [info exists file_chooser(geometry)]} { wm geometry .ins "${file_chooser(geometry)}" } elseif {[file exists $USER_CONF_DIR/file_chooser_geometry]} { @@ -6179,6 +6264,9 @@ proc file_chooser {} { "set file_chooser(sp1) $file_chooser(sp1)\n" \ ] $USER_CONF_DIR/file_chooser_geometry } + set file_chooser(files) {} + set file_chooser(fullpathlist) {} + set file_chooser(nitems) 0 file_chooser_dirlist file_chooser_filelist set file_chooser(old_dirs) $file_chooser(dirs)