diff --git a/content.go b/content.go index 9f378a7..ce0bdd8 100644 --- a/content.go +++ b/content.go @@ -1,14 +1,10 @@ package main import ( - "bytes" "fmt" ui "github.com/gizak/termui/v3" "github.com/gizak/termui/v3/widgets" "os" - "path/filepath" - "runtime" - "sort" "strings" ) @@ -17,12 +13,6 @@ var maxLineNum = 80 var maxContentLineSize = 1 var displayLineSize = 30 -type Entry struct { - command bytes.Buffer - explain bytes.Buffer - detail bytes.Buffer -} - type WidgetType int32 const ( @@ -90,96 +80,9 @@ func NewContent(inputTextChan *chan string, recHistoryCommandChan *chan string) return content } -type EntrySlice []*Entry -func (e EntrySlice) Len() int { return len(e) } -func (e EntrySlice) Less(i, j int) bool { return strings.Compare(e[i].command.String(), e[j].command.String()) <= 0 } -func (e EntrySlice) Swap(i, j int) { e[i], e[j] = e[j], e[i] } - - - // 加载并解析文件 func (c *Content) loadContent() { - - var files []string - c.entries = make([]*Entry, 0) - if runtime.GOOS == "darwin" || runtime.GOOS == "linux"{ - homedir, err := os.UserHomeDir() - if err != nil { - homedir = "/usr/local/bin/" - } - files = Files(homedir + "/.files") - } else { - panic("nonsupport system") - } - - for _, file := range files { - entries := make([]*Entry, 0) - b, err := ReadContent(file) - if err != nil { - return - } - content := string(b) - lines := strings.Split(content, "\n") - - var entry *Entry - - index := -1 - for i, line := range lines { - if index == 0 || index == 1 { - line = strings.Trim(line, "\t") - line = strings.Trim(line, " ") - } - if strings.HasPrefix(line, "%%##") { - if entry != nil { - c.entries = append(c.entries, entry) - } - entry = &Entry{ - command: bytes.Buffer{}, - explain: bytes.Buffer{}, - detail: bytes.Buffer{}, - } - index = -1 - continue - } else if strings.HasPrefix(line, "%%") { - index += 1 - line = line[2:] - } - if entry == nil { - continue - } - if line == "" && index < 2{ - continue - } - if index == 0 { - file = filepath.Base(file) - file = strings.Trim(file, ".txt") - line = file + "-" + line - if len(line) > maxLineNum { - entry.command.WriteString(line[0:maxLineNum]) - } else { - entry.command.Reset() - entry.command.WriteString(line) - for entry.command.Len() < maxLineNum { - entry.command.WriteString(" ") - } - } - } else if index == 1{ - entry.explain.WriteString(line) - } else { - entry.detail.WriteString(line) - entry.detail.WriteString("\n") - } - - if i == len(lines) - 1 && entry.command.Len() != 0 { - entries = append(entries, entry) - } - } - sort.Sort((EntrySlice)(entries)) - c.entries = append(c.entries, entries...) - } - if len(c.entries) == 0 { - panic("读取空的内容") - } + c.entries = LoadContent() c.listWidget.Rows = make([]string, 0, len(c.entries)) c.listEntries = make([]*Entry, 0, len(c.entries)) for _, entry := range c.entries { @@ -260,7 +163,6 @@ func (c *Content)contentDownPage() { c.contentEndIdx = oldEnd } - c.contentWidget.Text = c.decorateText(idx, c.contentStartIdx, c.contentEndIdx) } @@ -314,6 +216,7 @@ func (c *Content) HandleEvent(e ui.Event) (ui.Drawable, bool, bool) { if e.Type == ui.KeyboardEvent { switch e.ID { case "": + ui.Close() os.Exit(-1) case "": c.reset() diff --git a/entry.go b/entry.go new file mode 100644 index 0000000..4a9a6fd --- /dev/null +++ b/entry.go @@ -0,0 +1,112 @@ +package main + +import ( + "bytes" + "log" + "os" + "path/filepath" + "runtime" + "sort" + "strings" +) + +type Entry struct { + command bytes.Buffer + explain bytes.Buffer + detail bytes.Buffer +} + + +type EntrySlice []*Entry +func (e EntrySlice) Len() int { return len(e) } +func (e EntrySlice) Less(i, j int) bool { return strings.Compare(e[i].command.String(), e[j].command.String()) <= 0 } +func (e EntrySlice) Swap(i, j int) { e[i], e[j] = e[j], e[i] } + +func LoadContent() []*Entry { + + var files []string + entries := make([]*Entry, 0) + + if runtime.GOOS == "darwin" || runtime.GOOS == "linux"{ + homedir, err := os.UserHomeDir() + if err != nil { + homedir = "/usr/local/bin/" + } + files = Files(homedir + "/.files") + } else { + panic("nonsupport system") + } + + for _, file := range files { + subEntries := make([]*Entry, 0) + b, err := ReadContent(file) + if err != nil { + log.Printf("can't read content from:%s, error:%s", file, err.Error()) + continue + } + content := string(b) + lines := strings.Split(content, "\n") + + var entry *Entry + + index := -1 + for i, line := range lines { + if index == 0 || index == 1 { + line = strings.Trim(line, "\t") + line = strings.Trim(line, " ") + } + if strings.HasPrefix(line, "%%##") { + if entry != nil { + subEntries = append(subEntries, entry) + } + entry = &Entry{ + command: bytes.Buffer{}, + explain: bytes.Buffer{}, + detail: bytes.Buffer{}, + } + index = -1 + continue + } else if strings.HasPrefix(line, "%%") { + index += 1 + line = line[2:] + } + if entry == nil { + continue + } + if line == "" && index < 2{ + continue + } + if index == 0 { + file = filepath.Base(file) + file = strings.Trim(file, ".txt") + line = file + "-" + line + if len(line) > maxLineNum { + entry.command.WriteString(line[0:maxLineNum]) + } else { + entry.command.Reset() + entry.command.WriteString(line) + for entry.command.Len() < maxLineNum { + entry.command.WriteString(" ") + } + } + } else if index == 1{ + entry.explain.WriteString(line) + } else { + entry.detail.WriteString(line) + entry.detail.WriteString("\n") + } + + if i == len(lines) - 1 && entry.command.Len() != 0 { + subEntries = append(subEntries, entry) + } + } + sort.Sort((EntrySlice)(subEntries)) + entries = append(entries, subEntries...) + } + if len(entries) == 0 { + panic("读取空的内容") + } + return entries +} + + diff --git a/exec_prompt.go b/exec_prompt.go new file mode 100644 index 0000000..b512d61 --- /dev/null +++ b/exec_prompt.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "github.com/c-bata/go-prompt" + "os" +) + + +type ExePrompt struct { + entries []*Entry + entryMap map[string]*Entry +} + +func (e *ExePrompt) completer() prompt.Completer { + f := func(d prompt.Document) []prompt.Suggest { + s := make([]prompt.Suggest, 0) + for _, entry := range e.entries { + suggest := prompt.Suggest{ + Text: entry.command.String(), + Description: entry.explain.String(), + } + s = append(s, suggest) + } + return prompt.FilterHasPrefix(s, d.GetWordBeforeCursor(), true) + } + return f +} + + +func execCommand() { + exePrompt := &ExePrompt{ + entries: LoadContent(), + entryMap: make(map[string]*Entry, 0), + } + for _, entry := range exePrompt.entries { + exePrompt.entryMap[entry.command.String()] = entry + } + + for { + t := prompt.Input(">> ", exePrompt.completer()) + entry, ok := exePrompt.entryMap[t] + if t == "exit" { + os.Exit(0) + } + if ok { + fmt.Println(entry.detail.String()) + } + + } +} \ No newline at end of file diff --git a/fastfind b/fastfind index 1fb56d6..4528c23 100755 Binary files a/fastfind and b/fastfind differ diff --git a/go.mod b/go.mod index 75c9248..15dac05 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,9 @@ module fastfind go 1.13 require ( - github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe + github.com/c-bata/go-prompt v0.2.3 github.com/gizak/termui/v3 v3.1.0 + github.com/mattn/go-colorable v0.1.7 // indirect + github.com/mattn/go-tty v0.0.3 // indirect + github.com/pkg/term v0.0.0-20200520122047-c3ffed290a03 // indirect ) diff --git a/go.sum b/go.sum index c475102..d29f241 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,30 @@ -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe h1:69JI97HlzP+PH5Mi1thcGlDoBr6PS2Oe+l3mNmAkbs4= -github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= +github.com/c-bata/go-prompt v0.2.3 h1:jjCS+QhG/sULBhAaBdjb2PlMRVaKXQgn+4yzaauvs2s= +github.com/c-bata/go-prompt v0.2.3/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc= github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI= +github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840= github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= +github.com/pkg/term v0.0.0-20200520122047-c3ffed290a03 h1:pd4YKIqCB0U7O2I4gWHgEUA2mCEOENmco0l/bM957bU= +github.com/pkg/term v0.0.0-20200520122047-c3ffed290a03/go.mod h1:Z9+Ul5bCbBKnbCvdOWbLqTHhJiYV414CURZJba6L8qA= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/history.go b/history.go index ea7f08b..9a8ac66 100644 --- a/history.go +++ b/history.go @@ -88,6 +88,7 @@ func (i *History) HandleEvent(e ui.Event) (ui.Drawable, bool, bool) { defer i.locker.Unlock() switch e.ID { case "": + ui.Close() os.Exit(-1) case "": if len(i.widget.Rows) > 0 { diff --git a/main.go b/main.go index c740135..efd0abd 100644 --- a/main.go +++ b/main.go @@ -6,20 +6,30 @@ package main import ( "flag" + "fmt" ui "github.com/gizak/termui/v3" "log" + "os" ) var cursor = 0 var short = false +var fullscreen = false +var h = false func init() { - flag.BoolVar(&short, "short", false, "display short") + flag.BoolVar(&h, "h", false, "help") + flag.BoolVar(&fullscreen, "full", false, "进入全屏模式,常驻展示") + flag.BoolVar(&short, "short", false, "在全屏模式下, 适配小屏幕") + flag.Usage = usage } -func main() { - flag.Parse() +func usage() { + fmt.Fprintln(os.Stderr, `fastfind: 快速命令行检索工具,也能够作为一款辅助记忆软件`) + flag.PrintDefaults() +} +func fastfind() { if err := ui.Init(); err != nil { log.Fatalf("failed to initialize termui: %v", err) } @@ -60,8 +70,22 @@ func main() { } } if next { - elems[0] = input.HandleEvent(e) + elems[0] = input.HandleEvent(e) } ui.Render(elems...) } } + +func main() { + flag.Parse() + if h { + flag.Usage() + return + } + if fullscreen == true { + fastfind() + } else { + fmt.Println("输入exit退出") + execCommand() + } +}