package mode
import (
)
type Location interface {
tk.ComboBox
}
type LocationSpec struct {
Bindings tk.Bindings
Store LocationStore
IteratePinned func(func(string))
IterateHidden func(func(string))
IterateWorkspaces LocationWSIterator
Filter FilterSpec
}
type LocationStore interface {
Dirs(blacklist map[string]struct{}) ([]store.Dir, error)
Chdir(dir string) error
Getwd() (string, error)
}
var pinnedScore = math.Inf(1)
var errNoDirectoryHistoryStore = errors.New("no directory history store")
func ( cli.App, LocationSpec) (Location, error) {
if .Store == nil {
return nil, errNoDirectoryHistoryStore
}
:= []store.Dir{}
:= map[string]struct{}{}
, := "", ""
if .IteratePinned != nil {
.IteratePinned(func( string) {
[] = struct{}{}
= append(, store.Dir{Score: pinnedScore, Path: })
})
}
if .IterateHidden != nil {
.IterateHidden(func( string) { [] = struct{}{} })
}
, := .Store.Getwd()
if == nil {
[] = struct{}{}
if .IterateWorkspaces != nil {
, = .IterateWorkspaces.Parse()
}
}
, := .Store.Dirs()
if != nil {
return nil, fmt.Errorf("db error: %v", )
}
for , := range {
if filepath.IsAbs(.Path) {
= append(, )
} else if != "" && hasPathPrefix(.Path, ) {
= append(, )
}
}
:= locationList{}
:= tk.NewComboBox(tk.ComboBoxSpec{
CodeArea: tk.CodeAreaSpec{
Prompt: modePrompt(" LOCATION ", true),
Highlighter: .Filter.Highlighter,
},
ListBox: tk.ListBoxSpec{
Bindings: .Bindings,
OnAccept: func( tk.Items, int) {
:= .(locationList).dirs[].Path
if strings.HasPrefix(, ) {
= + [len():]
}
:= .Store.Chdir()
if != nil {
.Notify(.Error())
}
.SetAddon(nil, false)
},
},
OnFilter: func( tk.ComboBox, string) {
.ListBox().Reset(.filter(.Filter.makePredicate()), 0)
},
})
return , nil
}
func (, string) bool {
return == ||
strings.HasPrefix(, +string(filepath.Separator))
}
type LocationWSIterator func(func(kind, pattern string) bool)
func ( LocationWSIterator) ( string) (, string) {
var , string
(func(, string) bool {
if !strings.HasPrefix(, "^") {
= "^" +
}
, := regexp.Compile()
if != nil {
return true
}
if := .FindString(); != "" {
, = ,
return false
}
return true
})
return ,
}
type locationList struct {
dirs []store.Dir
}
func ( locationList) ( func(string) bool) locationList {
var []store.Dir
for , := range .dirs {
if (fsutil.TildeAbbr(.Path)) {
= append(, )
}
}
return locationList{}
}
func ( locationList) ( int) ui.Text {
return ui.T(fmt.Sprintf("%s %s",
showScore(.dirs[].Score), fsutil.TildeAbbr(.dirs[].Path)))
}
func ( locationList) () int { return len(.dirs) }
func ( float64) string {
if == pinnedScore {
return " *"
}
return fmt.Sprintf("%3.0f", )
}