Skip to content

Commit

Permalink
feat(app,keytracker)!: restructure corrections code
Browse files Browse the repository at this point in the history
- move check and correction logic into keytracker package.
- use an interface to expose agent methods to keytracker.
  • Loading branch information
joshuar committed Oct 17, 2023
1 parent a6a96fd commit b6ae8da
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 103 deletions.
55 changes: 18 additions & 37 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ import (
"fyne.io/fyne/v2"
"github.com/joshuar/autocorrector/internal/corrections"
"github.com/joshuar/autocorrector/internal/db"
"github.com/joshuar/autocorrector/internal/handler"
"github.com/joshuar/autocorrector/internal/keytracker"
"github.com/joshuar/autocorrector/internal/word"
"github.com/rs/zerolog/log"
)

Expand All @@ -44,70 +42,53 @@ type App struct {
tray fyne.Window
Name, Version string
showNotifications bool
notificationsCh chan *keytracker.Correction
Done chan struct{}
}

func (a *App) ShowNotifications() bool {
return a.showNotifications
}

func (a *App) NotificationCh() chan *keytracker.Correction {
return a.notificationsCh
}

func New() *App {
return &App{
app: newUI(),
Name: Name,
Version: Version,
showNotifications: false,
notificationsCh: make(chan *keytracker.Correction),
Done: make(chan struct{}),
}
}

func (a *App) Run() {
appCtx, cancelfunc := context.WithCancel(context.Background())
handler := handler.NewHandler()
if err := createDir(configPath); err != nil {
log.Fatal().Err(err).Msg("Could not create config directory.")
}
correctionsList, err := corrections.NewCorrections()
if err != nil {
log.Fatal().Err(err).Msg("Failed to open corrections file.")
}
stats, err := db.RunStats(appCtx, configPath)
defer close(stats.Done)
if err != nil {
log.Fatal().Err(err).Msg("Failed to start stats tracking.")
}
keyTracker = keytracker.NewKeyTracker(handler.WordCh, stats)
if err := keytracker.NewKeyTracker(a, stats); err != nil {
log.Fatal().Err(err).Msg("Failed to start key tracking.")
}

go func() {
for {
select {
case <-appCtx.Done():
return
case notification := <-handler.NotificationsCh:
if a.showNotifications {
a.app.SendNotification(&notification)
}
}
}
}()

go func() {
for newWord := range handler.WordCh {
log.Debug().Msgf("Checking word: %s", newWord.Word)
stats.IncCheckedCounter()
if correction, ok := correctionsList.CheckWord(newWord.Word); ok {
handler.CorrectionCh <- word.WordDetails{
Word: newWord.Word,
Correction: correction,
Punct: newWord.Punct,
}
}
}
}()

go func() {
for correction := range handler.CorrectionCh {
keyTracker.CorrectWord(correction)
stats.IncCorrectedCounter()
handler.NotificationsCh <- fyne.Notification{
Title: "Correction!",
Content: fmt.Sprintf("Corrected %s with %s", correction.Word, correction.Correction),
case n := <-a.notificationsCh:
a.app.SendNotification(&fyne.Notification{
Title: "Correction!",
Content: fmt.Sprintf("Corrected %s with %s", n.Word, n.Correction),
})
}
}
}()
Expand Down
25 changes: 0 additions & 25 deletions internal/handler/handler.go

This file was deleted.

80 changes: 60 additions & 20 deletions internal/keytracker/keytracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,30 @@ import (
"unicode"
"unicode/utf8"

"github.com/joshuar/autocorrector/internal/corrections"
"github.com/joshuar/autocorrector/internal/db"
"github.com/joshuar/autocorrector/internal/word"
kbd "github.com/joshuar/gokbd"
"github.com/rs/zerolog/log"
)

type agent interface {
ShowNotifications() bool
NotificationCh() chan *Correction
}

type Correction struct {
Word, Correction string
Punct rune
}

func NewCorrection(word, correction string, punct rune) *Correction {
return &Correction{
Word: word,
Correction: correction,
Punct: punct,
}
}

// KeyTracker holds the channels for handling key presses and
// indicating when word/line delimiter characters are encountered or
// backspace is pressed
Expand All @@ -25,7 +43,7 @@ type KeyTracker struct {
paused bool
}

func (kt *KeyTracker) slurpWords(wordCh chan word.WordDetails, stats *db.Stats) {
func (kt *KeyTracker) slurpWords(wordCh chan *Correction, stats *db.Stats) {
charBuf := new(bytes.Buffer)
patternBuf := newPatternBuf(3)
log.Debug().Msg("Slurping words...")
Expand Down Expand Up @@ -55,10 +73,7 @@ func (kt *KeyTracker) slurpWords(wordCh chan word.WordDetails, stats *db.Stats)
// handle that
stats.IncKeyCounter()
if charBuf.Len() > 0 {
wordCh <- word.WordDetails{
Word: charBuf.String(),
Punct: k.AsRune,
}
wordCh <- NewCorrection(charBuf.String(), "", k.AsRune)
charBuf.Reset()
}
default:
Expand All @@ -76,18 +91,35 @@ func (kt *KeyTracker) slurpWords(wordCh chan word.WordDetails, stats *db.Stats)
kt.CloseKeyTracker()
}

func (kt *KeyTracker) CorrectWord(correction word.WordDetails) {
if !kt.paused {
log.Debug().Msgf("Making correction %s to %s", correction.Word, correction.Correction)
func (kt *KeyTracker) checkWord(wordCh chan *Correction, correctionCh chan *Correction, corrections *corrections.Corrections, stats *db.Stats) {
for w := range wordCh {
log.Debug().Msgf("Checking word: %s", w.Word)
stats.IncCheckedCounter()
var ok bool
if w.Correction, ok = corrections.CheckWord(w.Word); ok {
correctionCh <- w
}
}
}

func (kt *KeyTracker) correctWord(correctionCh chan *Correction, agent agent, stats *db.Stats) {
for correction := range correctionCh {
if !kt.paused {
log.Debug().Msgf("Making correction %s to %s", correction.Word, correction.Correction)

// Erase the existing word.
// Effectively, hit backspace key for the length of the word plus the punctuation mark.
for i := 0; i <= utf8.RuneCountInString(correction.Word); i++ {
kt.kbd.TypeBackspace()
// Erase the existing word.
// Effectively, hit backspace key for the length of the word plus the punctuation mark.
for i := 0; i <= utf8.RuneCountInString(correction.Word); i++ {
kt.kbd.TypeBackspace()
}
// Insert the replacement.
// Type out the replacement and whatever punctuation/delimiter was after it.
kt.kbd.TypeString(correction.Correction + string(correction.Punct))
}
stats.IncCorrectedCounter()
if agent.ShowNotifications() {
agent.NotificationCh() <- correction
}
// Insert the replacement.
// Type out the replacement and whatever punctuation/delimiter was after it.
kt.kbd.TypeString(correction.Correction + string(correction.Punct))
}
}

Expand All @@ -101,17 +133,25 @@ func (kt *KeyTracker) CloseKeyTracker() {
}

// NewKeyTracker creates a new keyTracker struct
func NewKeyTracker(wordCh chan word.WordDetails, stats *db.Stats) *KeyTracker {
func NewKeyTracker(agent agent, stats *db.Stats) error {
vKbd, err := kbd.NewVirtualKeyboard("autocorrector")
if err != nil {
log.Error().Err(err).Msg("Could not open a new virtual keyboard.")
return nil
return err
}
kt := &KeyTracker{
kbd: vKbd,
kbdEvents: kbd.SnoopAllKeyboards(kbd.OpenAllKeyboardDevices()),
paused: false,
}
correctionsList, err := corrections.NewCorrections()
if err != nil {
return err
}

correctionCh := make(chan *Correction)
wordCh := make(chan *Correction)
go kt.slurpWords(wordCh, stats)
return kt
go kt.checkWord(wordCh, correctionCh, correctionsList, stats)
go kt.correctWord(correctionCh, agent, stats)
return nil
}
21 changes: 0 additions & 21 deletions internal/word/word.go

This file was deleted.

0 comments on commit b6ae8da

Please sign in to comment.