From 77a35e663c804f775e073c316d989e122e9535a8 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Sun, 21 Jan 2024 11:40:13 -0800 Subject: [PATCH] Find All looks in *all* files regardless of open status; Open looks in open --- code/code/enumgen.go | 34 +++++++++-------- code/code/filetree.go | 87 +++++++++++++++++++++++++++++++++++++++++-- code/code/findview.go | 5 ++- code/code/gtigen.go | 18 +++++++++ code/codev/views.go | 4 +- 5 files changed, 127 insertions(+), 21 deletions(-) diff --git a/code/code/enumgen.go b/code/code/enumgen.go index 03fb3c8b..ca892189 100644 --- a/code/code/enumgen.go +++ b/code/code/enumgen.go @@ -129,41 +129,45 @@ func (i *ArgVarTypes) UnmarshalText(text []byte) error { return nil } -var _FindLocValues = []FindLoc{0, 1, 2, 3} +var _FindLocValues = []FindLoc{0, 1, 2, 3, 4} // FindLocN is the highest valid value // for type FindLoc, plus one. -const FindLocN FindLoc = 4 +const FindLocN FindLoc = 5 // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the enumgen command to generate them again. func _FindLocNoOp() { var x [1]struct{} _ = x[FindLocAll-(0)] - _ = x[FindLocFile-(1)] - _ = x[FindLocDir-(2)] - _ = x[FindLocNotTop-(3)] + _ = x[FindLocOpen-(1)] + _ = x[FindLocFile-(2)] + _ = x[FindLocDir-(3)] + _ = x[FindLocNotTop-(4)] } var _FindLocNameToValueMap = map[string]FindLoc{ `All`: 0, - `File`: 1, - `Dir`: 2, - `NotTop`: 3, + `Open`: 1, + `File`: 2, + `Dir`: 3, + `NotTop`: 4, } var _FindLocDescMap = map[FindLoc]string{ - 0: `FindLocAll finds in all open folders in the left file browser`, - 1: `FindLocFile only finds in the current active file`, - 2: `FindLocDir only finds in the directory of the current active file`, - 3: `FindLocNotTop finds in all open folders *except* the top-level folder`, + 0: `FindLocAll finds in all directories under the root path`, + 1: `FindOpen finds in all open folders in the left file browser`, + 2: `FindLocFile only finds in the current active file`, + 3: `FindLocDir only finds in the directory of the current active file`, + 4: `FindLocNotTop finds in all open folders *except* the top-level folder`, } var _FindLocMap = map[FindLoc]string{ 0: `All`, - 1: `File`, - 2: `Dir`, - 3: `NotTop`, + 1: `Open`, + 2: `File`, + 3: `Dir`, + 4: `NotTop`, } // String returns the string representation diff --git a/code/code/filetree.go b/code/code/filetree.go index 34f5229e..58974afa 100644 --- a/code/code/filetree.go +++ b/code/code/filetree.go @@ -6,6 +6,7 @@ package code import ( "fmt" + "io/fs" "log" "path/filepath" "regexp" @@ -247,15 +248,17 @@ type FileSearchResults struct { } // FileTreeSearch returns list of all nodes starting at given node of given -// language(s) that contain the given string (non regexp version), sorted in -// descending order by number of occurrences -- ignoreCase transforms -// everything into lowercase +// language(s) that contain the given string, sorted in descending order by number +// of occurrences -- ignoreCase transforms everything into lowercase func FileTreeSearch(start *filetree.Node, find string, ignoreCase, regExp bool, loc FindLoc, activeDir string, langs []fi.Known) []FileSearchResults { fb := []byte(find) fsz := len(find) if fsz == 0 { return nil } + if loc == FindLocAll { + return FindAll(start, find, ignoreCase, regExp, langs) + } var re *regexp.Regexp var err error if regExp { @@ -324,6 +327,84 @@ func FileTreeSearch(start *filetree.Node, find string, ignoreCase, regExp bool, return mls } +// FindAll returns list of all files (regardless of what is currently open) +// starting at given node of given language(s) that contain the given string, +// sorted in descending order by number of occurrences. ignoreCase transforms +// everything into lowercase. +func FindAll(start *filetree.Node, find string, ignoreCase, regExp bool, langs []fi.Known) []FileSearchResults { + fb := []byte(find) + fsz := len(find) + if fsz == 0 { + return nil + } + var re *regexp.Regexp + var err error + if regExp { + re, err = regexp.Compile(find) + if err != nil { + log.Println(err) + return nil + } + } + mls := make([]FileSearchResults, 0) + spath := string(start.FPath) // note: is already Abs + filepath.Walk(spath, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return err + } + if info.Name() == ".git" { + return filepath.SkipDir + } + if info.IsDir() { + return nil + } + if int(info.Size()) > gi.SystemSettings.BigFileSize { + return nil + } + if strings.HasSuffix(info.Name(), ".code") { // exclude self + return nil + } + if len(langs) > 0 { + mtyp, _, err := fi.MimeFromFile(path) + if err != nil { + return nil + } + known := fi.MimeKnown(mtyp) + if !fi.IsMatchList(langs, known) { + return nil + } + } + sfn, found := start.FindFile(path) + var cnt int + var matches []textbuf.Match + if found && sfn.IsOpen() && sfn.Buf != nil { + if regExp { + cnt, matches = sfn.Buf.SearchRegexp(re) + } else { + cnt, matches = sfn.Buf.Search(fb, ignoreCase, false) + } + } else { + if regExp { + cnt, matches = textbuf.SearchFileRegexp(path, re) + } else { + cnt, matches = textbuf.SearchFile(path, fb, ignoreCase) + } + } + if cnt > 0 { + if found { + mls = append(mls, FileSearchResults{sfn, cnt, matches}) + } else { + fmt.Println("file not found in FindFile:", path) + } + } + return nil + }) + sort.Slice(mls, func(i, j int) bool { + return mls[i].Count > mls[j].Count + }) + return mls +} + // EditFiles calls EditFile on selected files func (fn *FileNode) EditFiles() { //gti:add sels := fn.SelectedViews() diff --git a/code/code/findview.go b/code/code/findview.go index fe5dc6ab..225d4414 100644 --- a/code/code/findview.go +++ b/code/code/findview.go @@ -30,9 +30,12 @@ import ( type FindLoc int32 //enums:enum -trim-prefix FindLoc const ( - // FindLocAll finds in all open folders in the left file browser + // FindLocAll finds in all directories under the root path FindLocAll FindLoc = iota + // FindOpen finds in all open folders in the left file browser + FindLocOpen + // FindLocFile only finds in the current active file FindLocFile diff --git a/code/code/gtigen.go b/code/code/gtigen.go index 31c4cbd2..1d2b0a12 100644 --- a/code/code/gtigen.go +++ b/code/code/gtigen.go @@ -219,6 +219,15 @@ func (t *FileNode) SetText(v string) *FileNode { t.Text = v; return t } // SetIcon sets the [FileNode.Icon] func (t *FileNode) SetIcon(v icons.Icon) *FileNode { t.Icon = v; return t } +// SetIconOpen sets the [FileNode.IconOpen] +func (t *FileNode) SetIconOpen(v icons.Icon) *FileNode { t.IconOpen = v; return t } + +// SetIconClosed sets the [FileNode.IconClosed] +func (t *FileNode) SetIconClosed(v icons.Icon) *FileNode { t.IconClosed = v; return t } + +// SetIconLeaf sets the [FileNode.IconLeaf] +func (t *FileNode) SetIconLeaf(v icons.Icon) *FileNode { t.IconLeaf = v; return t } + // SetIndent sets the [FileNode.Indent] func (t *FileNode) SetIndent(v units.Value) *FileNode { t.Indent = v; return t } @@ -419,6 +428,15 @@ func (t *SymTreeView) SetText(v string) *SymTreeView { t.Text = v; return t } // SetIcon sets the [SymTreeView.Icon] func (t *SymTreeView) SetIcon(v icons.Icon) *SymTreeView { t.Icon = v; return t } +// SetIconOpen sets the [SymTreeView.IconOpen] +func (t *SymTreeView) SetIconOpen(v icons.Icon) *SymTreeView { t.IconOpen = v; return t } + +// SetIconClosed sets the [SymTreeView.IconClosed] +func (t *SymTreeView) SetIconClosed(v icons.Icon) *SymTreeView { t.IconClosed = v; return t } + +// SetIconLeaf sets the [SymTreeView.IconLeaf] +func (t *SymTreeView) SetIconLeaf(v icons.Icon) *SymTreeView { t.IconLeaf = v; return t } + // SetIndent sets the [SymTreeView.Indent] func (t *SymTreeView) SetIndent(v units.Value) *SymTreeView { t.Indent = v; return t } diff --git a/code/codev/views.go b/code/codev/views.go index ac83739d..4d793999 100644 --- a/code/codev/views.go +++ b/code/codev/views.go @@ -301,10 +301,10 @@ func (ge *CodeView) UpdateStatusLabel() { } } if tv.ISearch.On { - msg = fmt.Sprintf("\tISearch: %v (n=%v)\t%v", tv.ISearch.Find, len(tv.ISearch.Matches), ge.StatusMessage) + msg = fmt.Sprintf("\tISearch: %v (n=%v)", tv.ISearch.Find, len(tv.ISearch.Matches)) } if tv.QReplace.On { - msg = fmt.Sprintf("\tQReplace: %v -> %v (n=%v)\t%v", tv.QReplace.Find, tv.QReplace.Replace, len(tv.QReplace.Matches), ge.StatusMessage) + msg = fmt.Sprintf("\tQReplace: %v -> %v (n=%v)", tv.QReplace.Find, tv.QReplace.Replace, len(tv.QReplace.Matches)) } }