load_file_dialog: add fuzzy subsequence search across nested files
This commit is contained in:
parent
2eb46f421f
commit
03e9716936
|
|
@ -4689,6 +4689,92 @@ proc load_additional_files {} {
|
||||||
# confirm_overwrt: ask before overwriting an existing file
|
# confirm_overwrt: ask before overwriting an existing file
|
||||||
# initialf: fill the file entry box with this name (used when saving)
|
# initialf: fill the file entry box with this name (used when saving)
|
||||||
#
|
#
|
||||||
|
proc fuzzy_subseq_score {q s} {
|
||||||
|
set q [string tolower $q]
|
||||||
|
set s [string tolower $s]
|
||||||
|
set n [string length $q]
|
||||||
|
set m [string length $s]
|
||||||
|
if {$n == 0} { return 0 }
|
||||||
|
if {$n > $m} { return -1 }
|
||||||
|
set qi 0
|
||||||
|
set last -2
|
||||||
|
set score 0
|
||||||
|
for {set i 0} {$i < $m && $qi < $n} {incr i} {
|
||||||
|
if {[string index $q $qi] eq [string index $s $i]} {
|
||||||
|
incr score 1
|
||||||
|
if {$i == $last + 1} { incr score 3 }
|
||||||
|
if {$i == 0} {
|
||||||
|
incr score 6
|
||||||
|
} else {
|
||||||
|
if {[regexp {[/_\-. ]} [string index $s [expr {$i-1}]]]} { incr score 4 }
|
||||||
|
}
|
||||||
|
set last $i
|
||||||
|
incr qi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if {$qi < $n} { return -1 }
|
||||||
|
return [expr {$score * 100 - $last}]
|
||||||
|
}
|
||||||
|
|
||||||
|
proc fuzzy_match_glob {pat name} {
|
||||||
|
if {[regexp {^(.*)\{([^{}]+)\}(.*)$} $pat -> pre alts post]} {
|
||||||
|
foreach alt [split $alts ","] {
|
||||||
|
if {[string match "${pre}${alt}${post}" $name]} { return 1 }
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return [string match $pat $name]
|
||||||
|
}
|
||||||
|
|
||||||
|
proc fuzzy_walk {dir maxdepth} {
|
||||||
|
set out {}
|
||||||
|
if {$maxdepth <= 0} { return $out }
|
||||||
|
if {[catch {glob -nocomplain -directory $dir -tails *} entries]} { return $out }
|
||||||
|
foreach e $entries {
|
||||||
|
if {[string index $e 0] eq "."} { continue }
|
||||||
|
set full [file join $dir $e]
|
||||||
|
if {[file isdirectory $full]} {
|
||||||
|
foreach sub [fuzzy_walk $full [expr {$maxdepth - 1}]] {
|
||||||
|
lappend out [file join $e $sub]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lappend out $e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $out
|
||||||
|
}
|
||||||
|
|
||||||
|
proc fuzzy_filter_files2 {q} {
|
||||||
|
global file_dialog_files2 file_dialog_dir1 file_dialog_ext
|
||||||
|
if {$q eq {}} {
|
||||||
|
setglob $file_dialog_dir1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set all [fuzzy_walk $file_dialog_dir1 6]
|
||||||
|
set ext_pat $file_dialog_ext
|
||||||
|
if {$ext_pat ne {} && $ext_pat ne {*}} {
|
||||||
|
set filt {}
|
||||||
|
foreach f $all {
|
||||||
|
if {[fuzzy_match_glob $ext_pat [file tail $f]]} { lappend filt $f }
|
||||||
|
}
|
||||||
|
set all $filt
|
||||||
|
}
|
||||||
|
set scored {}
|
||||||
|
foreach name $all {
|
||||||
|
set sc [fuzzy_subseq_score $q $name]
|
||||||
|
if {$sc >= 0} { lappend scored [list $sc $name] }
|
||||||
|
}
|
||||||
|
set sorted [lsort -decreasing -integer -index 0 $scored]
|
||||||
|
set out {}
|
||||||
|
set n 0
|
||||||
|
foreach pair $sorted {
|
||||||
|
if {$n >= 500} break
|
||||||
|
lappend out [lindex $pair 1]
|
||||||
|
incr n
|
||||||
|
}
|
||||||
|
set file_dialog_files2 $out
|
||||||
|
}
|
||||||
|
|
||||||
proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
|
proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
|
||||||
{loadfile {1}} {confirm_overwrt {1}} {initialf {}}} {
|
{loadfile {1}} {confirm_overwrt {1}} {initialf {}}} {
|
||||||
global file_dialog_index1 file_dialog_files2 file_dialog_files1 file_dialog_retval file_dialog_dir1 pathlist OS
|
global file_dialog_index1 file_dialog_files2 file_dialog_files1 file_dialog_retval file_dialog_dir1 pathlist OS
|
||||||
|
|
@ -4853,6 +4939,16 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
|
||||||
set file_dialog_retval { }
|
set file_dialog_retval { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label .load.buttons_bot.fzflab -text { Fuzzy:}
|
||||||
|
entry .load.buttons_bot.fzf -width 18 -highlightcolor red -highlightthickness 2 \
|
||||||
|
-highlightbackground [option get . background {}]
|
||||||
|
entry_replace_selection .load.buttons_bot.fzf
|
||||||
|
bind .load.buttons_bot.fzf <KeyRelease> {
|
||||||
|
fuzzy_filter_files2 [.load.buttons_bot.fzf get]
|
||||||
|
file_dialog_set_colors2
|
||||||
|
set file_dialog_retval { }
|
||||||
|
}
|
||||||
|
|
||||||
button .load.buttons.up -width 5 -text Up -command {load_file_dialog_up $file_dialog_dir1} -takefocus 0
|
button .load.buttons.up -width 5 -text Up -command {load_file_dialog_up $file_dialog_dir1} -takefocus 0
|
||||||
label .load.buttons.mkdirlab -text { New dir: }
|
label .load.buttons.mkdirlab -text { New dir: }
|
||||||
entry .load.buttons.newdir -width 16 -takefocus 0
|
entry .load.buttons.newdir -width 16 -takefocus 0
|
||||||
|
|
@ -4887,6 +4983,8 @@ proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}}
|
||||||
pack .load.buttons.rmdir .load.buttons.mkdir -side right
|
pack .load.buttons.rmdir .load.buttons.mkdir -side right
|
||||||
pack .load.buttons_bot.srclab -side left
|
pack .load.buttons_bot.srclab -side left
|
||||||
pack .load.buttons_bot.src -side left
|
pack .load.buttons_bot.src -side left
|
||||||
|
pack .load.buttons_bot.fzflab -side left
|
||||||
|
pack .load.buttons_bot.fzf -side left
|
||||||
pack .load.buttons_bot.label -side left
|
pack .load.buttons_bot.label -side left
|
||||||
pack .load.buttons_bot.entry -side left -fill x -expand true
|
pack .load.buttons_bot.entry -side left -fill x -expand true
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue