Skip to content

Commit

Permalink
Reload snippets.yml on changes
Browse files Browse the repository at this point in the history
  • Loading branch information
sandro-h committed May 2, 2021
1 parent dcb373e commit a4a4f5a
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 119 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ build-centos: ensure-centos-image

.PHONY: build-windows
build-windows:
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build ${EXTRA_BUILD_ARGS}
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build -ldflags "-H=windowsgui ${EXTRA_WIN_LDFLAGS}" ${EXTRA_WIN_BUILD_ARGS}

.PHONY: build-linux
build-linux:
Expand Down Expand Up @@ -75,7 +75,8 @@ print-version:

.PHONY: build-all-optimized
build-all-optimized: EXTRA_BUILD_ARGS=-ldflags='-s -w'
build-all-optimized: build-linux build-centos build-windows
build-all-optimized: EXTRA_WIN_LDFLAGS=-s -w
build-all-optimized: build-linux build-centos build-windows

upx:
wget https://github.com/upx/upx/releases/download/v3.96/upx-3.96-amd64_linux.tar.xz
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.16

require (
fyne.io/fyne/v2 v2.0.3
github.com/fsnotify/fsnotify v1.4.9
github.com/go-vgo/robotgo v0.93.1
github.com/lithammer/fuzzysearch v1.1.2
github.com/robotn/gohook v0.30.5
Expand Down
160 changes: 43 additions & 117 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package main

import (
"fmt"
"image/color"
"math"
"log"
"os"
"path/filepath"
"sort"
"strings"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/driver/desktop"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/fsnotify/fsnotify"
"github.com/go-vgo/robotgo"
"github.com/lithammer/fuzzysearch/fuzzy"
hook "github.com/robotn/gohook"
"gopkg.in/yaml.v2"
)
Expand All @@ -28,7 +24,9 @@ type snippet struct {
}

func main() {
snippets, snippetsText, err := loadSnippets()
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
snippetsFile := filepath.Join(dir, "snippets.yml")
snippets, err := loadSnippets(snippetsFile)
if err != nil {
panic(err)
}
Expand All @@ -42,8 +40,7 @@ func main() {
w = a.NewWindow("")
}

list, entry := createSearchWidget(snippets,
snippetsText,
search := newSearchWidget(snippets,
func(snippet *snippet) {
w.Hide()
typeSnippet(snippet.content)
Expand All @@ -53,108 +50,77 @@ func main() {
},
)

split := container.NewVSplit(entry, list)
go watchSnippets(snippetsFile, func() {
snippets, err := loadSnippets(snippetsFile)
if err != nil {
log.Println("error reloading snippets.yml:", err)
return
}
search.setSnippets(snippets)
})

split := container.NewVSplit(search.entry, search.list)
split.Offset = 0
w.SetContent(split)
w.Resize(fyne.NewSize(400, 400))
w.Canvas().Focus(entry)
w.Canvas().Focus(search.entry)
w.CenterOnScreen()

go listenForHotkeys(w)

w.ShowAndRun()
}

func loadSnippets() ([]*snippet, []string, error) {
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
bytes, err := os.ReadFile(filepath.Join(dir, "snippets.yml"))
func loadSnippets(snippetsFile string) ([]*snippet, error) {
bytes, err := os.ReadFile(snippetsFile)
if err != nil {
return nil, nil, err
return nil, err
}

var rawSnippets map[string]string
err = yaml.Unmarshal(bytes, &rawSnippets)
if err != nil {
return nil, nil, err
return nil, err
}

var snippets []*snippet
var snippetsText []string
for k, v := range rawSnippets {
snippets = append(snippets, &snippet{
label: k,
content: v,
})
snippetsText = append(snippetsText, fmt.Sprintf("%s: %s", k, v))
}
return snippets, snippetsText, nil
return snippets, nil
}

func createSearchWidget(snippets []*snippet, snippetsText []string, onSubmit func(snippet *snippet), onCancel func()) (*widget.List, *snippetEntry) {
filteredSnippets := snippets

list := widget.NewList(
func() int {
return len(filteredSnippets)
},
func() fyne.CanvasObject {
label := widget.NewLabel("tmpl lbl")
label.TextStyle.Bold = true
content := canvas.NewText("tmpl content", color.RGBA{128, 128, 128, 255})
content.TextStyle.Monospace = true
return container.NewHBox(label, content)
},
func(id widget.ListItemID, item fyne.CanvasObject) {
container := item.(*fyne.Container)
label := container.Objects[0].(*widget.Label)
content := container.Objects[1].(*canvas.Text)
label.SetText(filteredSnippets[id].label)
content.Text = strings.ReplaceAll(filteredSnippets[id].content, "\n", "\\n")
ellipsis(container, content)
},
)

var selectedID widget.ListItemID = -1
list.OnSelected = func(id widget.ListItemID) {
selectedID = id
func watchSnippets(snippetsFile string, onModified func()) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
panic(err)
}
list.Select(0)
defer watcher.Close()

entry := newSnippetEntry()

resetSearch := func() {
entry.Text = ""
entry.OnChanged(entry.Text)
list.Select(0)
err = watcher.Add(snippetsFile)
if err != nil {
panic(err)
}

entry.onTypedKey = func(key *fyne.KeyEvent) {
if key.Name == "Down" {
list.Select((selectedID + 1) % len(filteredSnippets))
} else if key.Name == "Up" {
list.Select((len(filteredSnippets) + selectedID - 1) % len(filteredSnippets))
} else if key.Name == "Return" {
if selectedID >= 0 && selectedID < len(filteredSnippets) {
onSubmit(filteredSnippets[selectedID])
resetSearch()
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
} else if key.Name == "Escape" {
onCancel()
resetSearch()
}
}
entry.OnChanged = func(s string) {
ranked := fuzzy.RankFindFold(s, snippetsText)
sort.Sort(ranked)
filteredSnippets = make([]*snippet, 0)
for _, r := range ranked {
filteredSnippets = append(filteredSnippets, snippets[r.OriginalIndex])
if event.Op&fsnotify.Write == fsnotify.Write {
onModified()
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("error:", err)
}
list.Refresh()
list.Select(0)
}

return list, entry
}

func listenForHotkeys(w fyne.Window) {
Expand All @@ -180,46 +146,6 @@ func typeSnippet(content string) {
}
}

type snippetEntry struct {
widget.Entry
onTypedKey func(key *fyne.KeyEvent)
}

func newSnippetEntry() *snippetEntry {
e := &snippetEntry{}
e.ExtendBaseWidget(e)
return e
}

func (e *snippetEntry) TypedKey(key *fyne.KeyEvent) {
e.Entry.TypedKey(key)
if e.onTypedKey != nil {
e.onTypedKey(key)
}
}

func ellipsis(container *fyne.Container, label *canvas.Text) {
w := fyne.MeasureText(string(label.Text), theme.TextSize(), label.TextStyle).Width
if label.Position().X+w > container.Size().Width {
wellipsis := fyne.MeasureText(string("..."), theme.TextSize(), label.TextStyle).Width
wmax := container.Size().Width - wellipsis
wpc := float64(w) / float64(len(label.Text))
k := 0
for label.Position().X+w > wmax {
overlap := label.Position().X + w - wmax
overlapc := int(math.Ceil(math.Max(1, float64(overlap)/wpc)))
if overlapc > len(label.Text) {
break
}
label.Text = label.Text[:len(label.Text)-overlapc]
w = fyne.MeasureText(string(label.Text), theme.TextSize(), label.TextStyle).Width
k++
}
label.Text += "..."
label.Refresh()
}
}

type myTheme struct{}

func (m myTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color {
Expand Down
Loading

0 comments on commit a4a4f5a

Please sign in to comment.