github.com/xyproto/orbiton/v2@v2.65.12-0.20240516144430-e10a419274ec/suggest.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"regexp"
     7  
     8  	"github.com/xyproto/vt100"
     9  )
    10  
    11  // corpus will grep all files matching the glob for "searchword.*" and return a list of what matched "*".
    12  // I thought this might be slow, but initial tests shows that this appears to be fast enough for interactive usage.
    13  func corpus(searchword, glob string) []string {
    14  	wordCount := make(map[string]int)
    15  
    16  	filenames, err := filepath.Glob(glob)
    17  	if err != nil {
    18  		return []string{}
    19  	}
    20  
    21  	corpusRegex := regexp.MustCompile(`[[:^alpha:]]` + searchword + `\.([[:alpha:]]*)`)
    22  
    23  	var data []byte
    24  	var highestCount int
    25  	for _, filename := range filenames {
    26  		data, err = os.ReadFile(filename)
    27  		if err != nil {
    28  			continue
    29  		}
    30  		submatches := corpusRegex.FindAllStringSubmatch(string(data), -1)
    31  		for _, submatch := range submatches {
    32  			word := submatch[1]
    33  			if _, ok := wordCount[word]; ok {
    34  				wordCount[word]++
    35  				if wordCount[word] > highestCount {
    36  					highestCount = wordCount[word]
    37  				}
    38  			} else {
    39  				wordCount[word] = 1
    40  				if wordCount[word] > highestCount {
    41  					highestCount = wordCount[word]
    42  				}
    43  			}
    44  		}
    45  	}
    46  
    47  	// Copy the words from the map to a string slice, such
    48  	// that the most frequent words appear first.
    49  	sl := make([]string, len(wordCount))
    50  	slIndex := 0
    51  	for i := highestCount; i >= 0; i-- {
    52  		for word, count := range wordCount {
    53  			if count == i && len(word) > 0 {
    54  				sl[slIndex] = word
    55  				slIndex++
    56  			}
    57  		}
    58  	}
    59  
    60  	return sl
    61  }
    62  
    63  // SuggestMode lets the user tab through the suggested words
    64  func (e *Editor) SuggestMode(c *vt100.Canvas, status *StatusBar, tty *vt100.TTY, suggestions []string) string {
    65  	if len(suggestions) == 0 {
    66  		return ""
    67  	}
    68  
    69  	suggestIndex := 0
    70  	s := suggestions[suggestIndex]
    71  
    72  	status.ClearAll(c)
    73  	status.SetMessage("Suggest: " + s)
    74  	status.ShowNoTimeout(c, e)
    75  
    76  	var doneChoosing bool
    77  	for !doneChoosing {
    78  		key := tty.String()
    79  		switch key {
    80  		case "c:9", "↓", "→": // tab, down arrow or right arrow
    81  			// Cycle suggested words
    82  			suggestIndex++
    83  			if suggestIndex == len(suggestions) {
    84  				suggestIndex = 0
    85  			}
    86  			s = suggestions[suggestIndex]
    87  			status.ClearAll(c)
    88  			status.SetMessage("Suggest: " + s)
    89  			status.ShowNoTimeout(c, e)
    90  		case "↑", "←": // up arrow or left arrow
    91  			// Cycle suggested words (one back)
    92  			suggestIndex--
    93  			if suggestIndex < 0 {
    94  				suggestIndex = len(suggestions) - 1
    95  			}
    96  			s = suggestions[suggestIndex]
    97  			status.ClearAll(c)
    98  			status.SetMessage("Suggest: " + s)
    99  			status.ShowNoTimeout(c, e)
   100  		case "c:8", "c:127": // ctrl-h or backspace
   101  			fallthrough
   102  		case "c:27", "c:17": // esc, ctrl-q or backspace
   103  			s = ""
   104  			fallthrough
   105  		case "c:13", "c:32": // return or space
   106  			doneChoosing = true
   107  		}
   108  	}
   109  	status.ClearAll(c)
   110  	// The chosen word
   111  	return s
   112  }