Skip to content

Commit 0aab5c0

Browse files
authored
feat: add ci (#1)
1 parent 2a7cd3c commit 0aab5c0

28 files changed

Lines changed: 539 additions & 359 deletions

.github/workflows/ci.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
on:
2+
pull_request:
3+
branches: ["*"]
4+
tags-ignore:
5+
- "release-please--*" # Exclude tags containing "staging"
6+
name: CI
7+
permissions:
8+
contents: read
9+
jobs:
10+
lint:
11+
name: lint
12+
strategy:
13+
matrix:
14+
go: ["1.25.2"]
15+
os: [macos-latest]
16+
runs-on: ${{ matrix.os }}
17+
steps:
18+
- uses: actions/checkout@v4
19+
with:
20+
repository: ${{ github.event.pull_request.head.repo.full_name }}
21+
ref: ${{ github.head_ref }}
22+
- uses: actions/setup-go@v5
23+
with:
24+
go-version: ${{ matrix.go }}
25+
- name: golangci-lint
26+
uses: golangci/golangci-lint-action@v8
27+
with:
28+
version: v2.6
29+
go-checks:
30+
name: ${{ matrix.check }}
31+
strategy:
32+
matrix:
33+
go: ["1.25.2"]
34+
os: [macos-latest]
35+
check: [formatting, vet, test]
36+
runs-on: ${{ matrix.os }}
37+
steps:
38+
- uses: actions/checkout@v4
39+
with:
40+
repository: ${{ github.event.pull_request.head.repo.full_name }}
41+
ref: ${{ github.head_ref }}
42+
- uses: actions/setup-go@v5
43+
with:
44+
go-version: ${{ matrix.go }}
45+
- name: Check code formatting (Unix)
46+
shell: bash
47+
run: |
48+
fmt_out=$(go fmt ./...)
49+
if [ -n "$fmt_out" ]; then
50+
echo "The following files are not formatted:"
51+
echo "$fmt_out"
52+
exit 1
53+
fi
54+
- name: Run vet
55+
if: ${{ matrix.check == 'vet' }}
56+
run: go vet ./...
57+
- name: Run test
58+
if: ${{ matrix.check == 'test' }}
59+
run: go test ./... -v
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
on:
2+
push:
3+
branches:
4+
- main
5+
6+
permissions:
7+
contents: write
8+
pull-requests: write
9+
10+
name: release-please
11+
12+
jobs:
13+
release-please:
14+
strategy:
15+
matrix:
16+
go: ["1.25.2"]
17+
os: [macos-latest]
18+
runs-on: ${{ matrix.os }}
19+
steps:
20+
# Create a release using the release-please action.
21+
- uses: googleapis/release-please-action@v4
22+
id: release
23+
with:
24+
token: ${{ secrets.MY_RELEASE_PLEASE_TOKEN }}
25+
release-type: go
26+
27+
# Checkout the repository.
28+
- uses: actions/checkout@v4
29+
if: ${{ steps.release.outputs.release_created }}
30+
with:
31+
repository: ${{ github.event.pull_request.head.repo.full_name }}
32+
ref: ${{ github.head_ref }}
33+
34+
# Set up Go.
35+
- uses: actions/setup-go@v5
36+
if: ${{ steps.release.outputs.release_created }}
37+
with:
38+
go-version: ${{ matrix.go }}
39+
40+
# Build artifacts for multiple platforms.
41+
- name: Build nvs artifacts
42+
if: ${{ steps.release.outputs.release_created }}
43+
run: |
44+
mkdir -p bin
45+
# Build for darwin-arm64
46+
env GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w -X github.com/y3owk1n/govim/internal/cli.Version=${{ steps.release.outputs.tag_name }}" -trimpath -o bin/govim-darwin-arm64 cmd/govim/main.go
47+
48+
# Build for darwin-amd64
49+
env GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X github.com/y3owk1n/govim/internal/cli.Version=${{ steps.release.outputs.tag_name }}" -trimpath -o bin/govim-darwin-amd64 cmd/govim/main.go
50+
51+
# Generate SHA256 checksum files for each artifact
52+
- name: Generate Checksums
53+
if: ${{ steps.release.outputs.release_created }}
54+
run: |
55+
cd build
56+
for file in nvs-*; do
57+
shasum -a 256 "$file" | awk '{print $1}' > "$file.sha256"
58+
done
59+
ls -l
60+
61+
# Upload release artifacts and their respective checksum files
62+
- name: Upload Release Artifacts
63+
if: ${{ steps.release.outputs.release_created }}
64+
env:
65+
GITHUB_TOKEN: ${{ secrets.MY_RELEASE_PLEASE_TOKEN }}
66+
run: |
67+
for file in build/nvs-*; do
68+
if [[ "$file" != *.sha256 ]]; then
69+
gh release upload "${{ steps.release.outputs.tag_name }}" "$file"
70+
gh release upload "${{ steps.release.outputs.tag_name }}" "$file.sha256"
71+
fi
72+
done

.golangci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: "2"
2+
# Options for analysis running.
3+
run:
4+
# Include test files or not.
5+
# Default: true
6+
tests: false

cmd/govim/main.go

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,20 @@ func (a *App) Run() error {
156156
// Wait for interrupt signal with force-quit support
157157
sigChan := make(chan os.Signal, 1)
158158
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
159-
159+
160160
// First signal: graceful shutdown
161161
<-sigChan
162162
a.logger.Info("Received shutdown signal, starting graceful shutdown...")
163163
fmt.Println("\n⚠️ Shutting down gracefully... (press Ctrl+C again to force quit)")
164-
164+
165165
// Start cleanup in goroutine
166166
done := make(chan struct{})
167167
go func() {
168168
// Quit systray to exit the event loop
169169
systray.Quit()
170170
close(done)
171171
}()
172-
172+
173173
// Wait for cleanup or second signal
174174
select {
175175
case <-done:
@@ -186,7 +186,7 @@ func (a *App) Run() error {
186186
fmt.Println("⚠️ Shutdown timeout, force quitting...")
187187
os.Exit(1)
188188
}
189-
189+
190190
return nil
191191
}
192192

@@ -287,33 +287,33 @@ func (a *App) activateHintMode(withActions bool) {
287287
a.logger.Debug("Scanning for clickable elements",
288288
zap.Strings("roles", roles))
289289

290-
elements, err := accessibility.GetClickableElements()
290+
elements, err := accessibility.GetClickableElements()
291291
if err != nil {
292292
a.logger.Error("Failed to get clickable elements", zap.Error(err))
293293
return
294294
}
295295

296296
a.logger.Info("Found clickable elements", zap.Int("count", len(elements)))
297297

298-
// Optionally include menu bar elements
299-
if a.config.Hints.Menubar {
300-
if mbElems, merr := accessibility.GetMenuBarClickableElements(); merr == nil {
301-
elements = append(elements, mbElems...)
302-
a.logger.Debug("Included menubar elements", zap.Int("count", len(mbElems)))
303-
} else {
304-
a.logger.Warn("Failed to get menubar elements", zap.Error(merr))
305-
}
306-
}
307-
308-
// Optionally include Dock elements
309-
if a.config.Hints.Dock {
310-
if dockElems, derr := accessibility.GetDockClickableElements(); derr == nil {
311-
elements = append(elements, dockElems...)
312-
a.logger.Debug("Included dock elements", zap.Int("count", len(dockElems)))
313-
} else {
314-
a.logger.Warn("Failed to get dock elements", zap.Error(derr))
315-
}
316-
}
298+
// Optionally include menu bar elements
299+
if a.config.Hints.Menubar {
300+
if mbElems, merr := accessibility.GetMenuBarClickableElements(); merr == nil {
301+
elements = append(elements, mbElems...)
302+
a.logger.Debug("Included menubar elements", zap.Int("count", len(mbElems)))
303+
} else {
304+
a.logger.Warn("Failed to get menubar elements", zap.Error(merr))
305+
}
306+
}
307+
308+
// Optionally include Dock elements
309+
if a.config.Hints.Dock {
310+
if dockElems, derr := accessibility.GetDockClickableElements(); derr == nil {
311+
elements = append(elements, dockElems...)
312+
a.logger.Debug("Included dock elements", zap.Int("count", len(dockElems)))
313+
} else {
314+
a.logger.Warn("Failed to get dock elements", zap.Error(derr))
315+
}
316+
}
317317

318318
if len(elements) == 0 {
319319
a.logger.Warn("No clickable elements found")
@@ -371,9 +371,10 @@ func (a *App) handleKeyPress(key string) {
371371
}
372372

373373
// Route to appropriate handler
374-
if a.currentMode == ModeHint || a.currentMode == ModeHintWithActions {
374+
switch a.currentMode {
375+
case ModeHint, ModeHintWithActions:
375376
a.handleHintKey(key)
376-
} else if a.currentMode == ModeScroll {
377+
case ModeScroll:
377378
a.handleScrollKey(key)
378379
}
379380
}
@@ -487,29 +488,29 @@ func (a *App) showActionMenu(hint *hints.Hint) {
487488
actionHints := make([]*hints.Hint, 0, len(actions))
488489
baseX := hint.Position.X
489490
baseY := hint.Position.Y
490-
491+
491492
// Estimate width per character (approximate for monospace font at size 11)
492493
charWidth := 7.0
493494
gapBetweenHints := 8.0 // Consistent gap between hint boxes
494-
495+
495496
currentX := float64(baseX)
496-
497+
497498
for _, action := range actions {
498499
// Format: [key]label (e.g., "[l]eft")
499500
actionLabel := fmt.Sprintf("[%s]%s", action.key, action.label)
500-
501+
501502
actionHint := &hints.Hint{
502503
Label: actionLabel,
503504
Element: hint.Element,
504505
Position: image.Point{X: int(currentX), Y: baseY},
505506
}
506507
actionHints = append(actionHints, actionHint)
507-
508+
508509
// Calculate width of this hint box (text width + padding * 2)
509510
textWidth := float64(len(actionLabel)) * charWidth
510511
padding := 3.0 * 2 // padding on both sides
511512
hintBoxWidth := textWidth + padding
512-
513+
513514
// Move to next position (current box width + gap)
514515
currentX += hintBoxWidth + gapBetweenHints
515516
}
@@ -519,7 +520,7 @@ func (a *App) showActionMenu(hint *hints.Hint) {
519520
actionStyle.FontSize = 11 // Smaller font
520521
actionStyle.Padding = 3 // Less padding
521522
actionStyle.BorderRadius = 3 // Smaller border radius
522-
523+
523524
// Draw all action hints without arrows and with custom style
524525
if err := a.hintOverlay.DrawHintsWithoutArrow(actionHints, actionStyle); err != nil {
525526
a.logger.Error("Failed to draw action menu", zap.Error(err))
@@ -535,24 +536,24 @@ func (a *App) handleActionKey(key string) {
535536
// Handle backspace/delete to go back to hint selection
536537
if key == "\x7f" || key == "delete" || key == "backspace" {
537538
a.logger.Debug("Backspace pressed in action mode, returning to hint selection")
538-
539+
539540
// Clear selected hint
540541
a.selectedHint = nil
541-
542+
542543
// Remove the last character from hintInput (e.g., "ABD" -> "AB")
543544
if len(a.hintInput) > 0 {
544545
a.hintInput = a.hintInput[:len(a.hintInput)-1]
545546
a.logger.Debug("Removed last character from hint input", zap.String("input", a.hintInput))
546547
}
547-
548+
548549
// Redraw hints with updated input filter
549550
var filtered []*hints.Hint
550551
if a.hintInput == "" {
551552
filtered = a.currentHints.GetHints()
552553
} else {
553554
filtered = a.currentHints.FilterByPrefix(a.hintInput)
554555
}
555-
556+
556557
// Update matched prefix for filtered hints and redraw
557558
for _, hint := range filtered {
558559
hint.MatchedPrefix = a.hintInput
@@ -697,7 +698,7 @@ func (a *App) switchScrollAreaByNumber(key string) {
697698
a.logger.Debug("Invalid number key", zap.String("key", key))
698699
return
699700
}
700-
701+
701702
number := int(key[0] - '0')
702703
detector := a.scrollController.GetDetector()
703704
newArea := detector.SetActiveByNumber(number)
@@ -796,7 +797,9 @@ func (a *App) drawScrollAreaLabels(areas []*scroll.ScrollArea) {
796797

797798
// Draw the number hints
798799
if len(areaHints) > 0 {
799-
a.hintOverlay.DrawHints(areaHints)
800+
if err := a.hintOverlay.DrawHints(areaHints); err != nil {
801+
a.logger.Error("Failed to draw hints", zap.Error(err))
802+
}
800803
}
801804

802805
// Draw highlight on active area
@@ -827,11 +830,12 @@ func (a *App) exitMode() {
827830
a.hintOverlay.Clear()
828831

829832
// Clean up mode-specific state
830-
if a.currentMode == ModeHint || a.currentMode == ModeHintWithActions {
833+
switch a.currentMode {
834+
case ModeHint, ModeHintWithActions:
831835
a.currentHints = nil
832836
a.hintInput = ""
833837
a.selectedHint = nil
834-
} else if a.currentMode == ModeScroll {
838+
case ModeScroll:
835839
a.scrollController.Cleanup()
836840
}
837841

@@ -1010,9 +1014,9 @@ func main() {
10101014
if len(os.Args) > 1 {
10111015
arg := os.Args[1]
10121016
// These commands use CLI/IPC
1013-
if arg == "launch" || arg == "start" || arg == "stop" || arg == "hints" ||
1014-
arg == "scroll" || arg == "hints_action" || arg == "idle" || arg == "status" ||
1015-
arg == "help" || arg == "--help" || arg == "-h" || arg == "--version" || arg == "-v" {
1017+
if arg == "launch" || arg == "start" || arg == "stop" || arg == "hints" ||
1018+
arg == "scroll" || arg == "hints_action" || arg == "idle" || arg == "status" ||
1019+
arg == "help" || arg == "--help" || arg == "-h" || arg == "--version" || arg == "-v" {
10161020
cli.Execute()
10171021
return
10181022
}

cmd/govim/main_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ func TestMain_BasicImport(t *testing.T) {
1212
t.Errorf("Main package import caused panic: %v", r)
1313
}
1414
}()
15-
15+
1616
// Just test that we can get here without panicking
1717
// The actual functionality testing should be done in unit tests
1818
// for individual components

flake.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
inputs = {
3-
nixpkgs.url = "github:NixOS/nixpkgs";
3+
nixpkgs.url = "github:NixOS/nixpkgs/b976292fb39a449bcf410219e4cf0aa05a8b4d04?narHash=sha256-NmiCO/7hKv3TVIXXtEAkpGHiJzQc/5z8PT8tO+SKPZA=";
44
};
55

66
outputs =

0 commit comments

Comments
 (0)