Version 11 of pathentry

Updated 2002-09-26 16:47:59

MSW: The goal is to offer an entry widget which does auto-path-completion, offers completion on TAB (with cycling through the possibilities), and a popup menu to allow the user to specify the next directory(/ies).

pathentry works as follows: It takes all the arguments an entry takes, (because it's basically an entry with some bindings and extra commands), and offers two own commands, complete and popup.

  • path complete tries to complete the current text in the entry if there is an unambigous completion, and if there is none, the text is not changed, but a list of all possible completions is returned.
  • path popup takes two arguments (X & Y coordinates) and pops up a menu to allow the user to choose from the possible completions. If there is only one unambigous completion, the completion is filled in, and no menu pops up.
  • path partdel (partial delete) deletes either the last path component if the current value exists, cuts back to the next possible start of possible globs if it doesn't and isn't a start of globs, or simply deletes a char if none of that is true.

This implementation is not yet done! I just thought I'd share my thoughts with you, because it happens to be quite usable already :)

Things lacking:

  • The options -popup and -completion only accept 0 and 1 for now, should also accept yes, no, false, true
  • The options -popup and -completion are ignore atm :)
  • an option -menusize, telling the popup menu to launch submenus for more than x entries (on unix, enter /usr/bin into the entry and click on it with the right mousebutton to see what I mean)
  • configure and cget must be caught, too, to offer runtime altering of the pathentries options
  • TAB bindings:
         TAB: when there is 1 completion, complete. (done now through keyrelease)
              when there is > 1 completions, cycle through them

How to play

 pathentry .e
 pack .e
 Focus it, enter the following three characters: '/', 'u', 'b'.
 In the entry now there should be '/usr/bin/' (on a typical unix)
 Toy around with backspace and the right mousebutton :)

Current implementation (no need to add the points I talked about above, will do that soon :) goes here:

 proc pathentry {path args} {
    set arg {}
    if {[string index $path 0] != {.}} {
        return -code error "$path is no valid widget path!"
    }
    foreach {sw ar} $args {
        switch -- $sw {
            -completion { if {[catch { expr !$ar }]} { return -code error "-completion takes a boolean argument, $ar is none." } }
            -popup { if {[catch { expr !$ar }]} { return -code error "-popup takes a boolen argument, $ar is none." } }
            default { lappend arg $sw $ar }
        }
    }
    if {[catch { eval [concat entry $path $arg] } err]} {
        return -code error $err
    }
    rename $path ${path}_entry
    proc $path {cmd args} {
        upvar #0 [set vname [[set pat [lindex [info level [info level]] 0]]_entry cget -textvariable]] acc
        switch -- $cmd {
            complete    {
                if {[llength [set glo [glob -nocomplain "$acc*"]]]==1} {
                    if {[file isdirectory [set acc $glo]]} { append acc / }
                    $pat icursor end
                    $pat xview end
                } else { 
                    return $glo 
                }
            } partdel   {
                for {set ac $acc} {![file exists $ac] && ![llength [glob -nocomplain $ac*]]} {set ac [string range $ac 0 end-1]} {}
                if {$ac != $acc} {
                    set acc $ac
                } elseif {[file exists $acc]} {
                    set acc [file dirname $acc]
                    if {$acc != {/}} {append acc /}
                } else {
                    set acc [string range $acc 0 end-1]
                }
                $pat icursor end
                $pat xview end
            } popup     {
                foreach {xcoord ycoord} $args {break}
                if {[winfo exists $pat.popmen]} {destroy $pat.popmen}
                menu $pat.popmen -tearoff 0 -title {Path Completion} ; set ctr 0
                set possible [lsort [$pat complete]]; if {[llength $possible]==1} {return}
                foreach poss $possible {
                    $pat.popmen add command -label [file tail $poss] \
                         -command "if {\[file isdirectory \[set ::$vname $poss\]\]} { append $vname / } ; $pat icursor end; $pat xview e

nd"

                    incr ctr
                }
                if {$ctr} { tk_popup $pat.popmen $xcoord $ycoord } else { destroy $pat.popmen }
            } default   {
                eval [concat ${pat}_entry $cmd $args]
            }
        }
    }
    bind $path <KeyRelease> "$path complete"
    bind $path <3> "$path popup %X %Y"
    bind $path <KeyRelease-BackSpace> "$path partdel; break"
    bind $path <KeyPress-BackSpace> { break }
 }

Comments ? Welcome ...