-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
170 lines (143 loc) · 5.25 KB
/
main.go
File metadata and controls
170 lines (143 loc) · 5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package main
import (
"embed"
"flag"
"fmt"
"log"
"os"
"time"
"keylint/internal/app"
"keylint/internal/cli"
"keylint/internal/features/enhance"
featurelogger "keylint/internal/features/logger"
"keylint/internal/features/pyramidize"
"keylint/internal/features/shortcut"
"keylint/internal/features/updater"
"keylint/internal/logger"
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/events"
)
// AppVersion is injected at build time via -ldflags "-X main.AppVersion=x.y.z".
var AppVersion = "dev"
//go:embed all:frontend/dist
var assets embed.FS
//go:embed build/appicon.png
var appIcon []byte
func init() {
application.RegisterEvent[string]("shortcut:triggered")
application.RegisterEvent[string]("settings:changed")
}
func main() {
// CLI dispatch — runs headlessly, no Wails/GUI.
if len(os.Args) > 1 {
switch os.Args[1] {
case "-fix", "-pyramidize":
if err := cli.Run(os.Args[1:], os.Stdout, os.Stderr); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
os.Exit(0)
}
}
simulateShortcut := flag.Bool("simulate-shortcut", false, "Fire a synthetic shortcut event on startup (Linux dev mode)")
flag.Parse()
wailsApp := application.New(application.Options{
Name: "KeyLint",
Description: "AI-powered text enhancement",
Icon: appIcon,
Assets: application.AssetOptions{
Handler: application.AssetFileServerFS(assets),
},
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: false,
},
})
services, err := app.InitializeApp(wailsApp, app.AppIcon(appIcon))
if err != nil {
log.Fatalf("failed to initialise app: %v", err)
}
// Initialize structured logger based on the saved settings.
cfg := services.Settings.Get()
logger.Init(cfg.LogLevel, cfg.SensitiveLogging)
logger.Info("app initializing", "version", AppVersion)
// Register backend services so the frontend can call their methods.
wailsApp.RegisterService(application.NewService(services.Settings))
wailsApp.RegisterService(application.NewService(services.Welcome))
wailsApp.RegisterService(application.NewService(services.Clipboard))
wailsApp.RegisterService(application.NewService(enhance.NewService(services.Settings)))
// Pyramidize service — captures source app on hotkey and exposes RPC methods.
pyramidizeSvc := pyramidize.NewService(services.Settings, services.Clipboard)
wailsApp.RegisterService(application.NewService(pyramidizeSvc))
// Log service — forwards frontend log messages into debug.log.
wailsApp.RegisterService(application.NewService(featurelogger.NewService()))
// Updater service — AppVersion injected at build time via ldflags.
updaterSvc := updater.NewService(AppVersion, services.Settings)
updaterSvc.SetQuitFunc(func() {
// Brief delay so the frontend can display the "closing" message.
time.Sleep(2 * time.Second)
wailsApp.Quit()
})
wailsApp.RegisterService(application.NewService(updaterSvc))
// Dev-tools shortcut simulation service.
sim := &simulateService{shortcut: services.Shortcut}
wailsApp.RegisterService(application.NewService(sim))
window := wailsApp.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "KeyLint",
Width: 1280,
Height: 800,
BackgroundColour: application.NewRGB(27, 38, 54),
URL: "/",
})
// Hide to tray on close instead of quitting.
window.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) {
window.Hide()
e.Cancel()
})
logger.Info("window created")
// Start the system tray.
services.Tray.Setup(window)
// Register the global shortcut (no-op on Linux).
// Unregister on shutdown so dev-mode restarts don't leave a stale registration.
if err := services.Shortcut.Register(); err != nil {
log.Printf("warn: shortcut registration failed: %v", err)
logger.Warn("shortcut: registration failed", "err", err)
} else {
logger.Info("shortcut: registered", "key", cfg.ShortcutKey)
}
wailsApp.OnShutdown(func() { services.Shortcut.Unregister() })
// Forward shortcut events to the frontend.
// First send Ctrl+C to copy selected text from the source app, then notify
// the frontend so it can read the clipboard and enhance the text.
// Show the window so the frontend can receive and process the event.
go func() {
ch := services.Shortcut.Triggered()
for event := range ch {
logger.Info("shortcut: triggered", "source", event.Source)
// Capture the source app window BEFORE copying from foreground,
// so SendBack() can restore focus to the correct window later.
pyramidizeSvc.CaptureSourceApp()
if err := services.Clipboard.CopyFromForeground(); err != nil {
logger.Warn("shortcut: CopyFromForeground failed", "err", err)
}
wailsApp.Event.Emit("shortcut:triggered", event.Source)
}
}()
// Simulate shortcut on startup when --simulate-shortcut flag is set.
if *simulateShortcut {
if s, ok := services.Shortcut.(interface{ Simulate() }); ok {
go s.Simulate()
}
}
if err := wailsApp.Run(); err != nil {
log.Fatal(err)
}
}
// simulateService exposes SimulateShortcut to the frontend (used by dev-tools button).
type simulateService struct {
shortcut shortcut.Service
}
func (s *simulateService) SimulateShortcut() {
if sim, ok := s.shortcut.(interface{ Simulate() }); ok {
sim.Simulate()
}
}