diff options
| author | Paul Buetow <paul@buetow.org> | 2025-09-06 15:04:37 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-09-06 15:04:37 +0300 |
| commit | 7c0266e94378f6121719939c6d53915eb72eed3e (patch) | |
| tree | 64017871e9516fbe3cf2dfbd63729e790ed1e0ef | |
| parent | e2418d22e0ff8d5d8bb883cf38b47dc94a6c308e (diff) | |
feat(hexai-action): add --infile/--outfile flags; docs and tests\n\n- Add flags to read from file and write to file\n- Refactor IO open into helper for testability\n- Add CLI integration-style test for IO\n- Update README and docs/usage.md with examples\n- Update docs/testing.md with instructions
| -rw-r--r-- | PROJECTSTATUS.md | 5 | ||||
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | cmd/internal/hexai-action/main.go | 42 | ||||
| -rw-r--r-- | cmd/internal/hexai-action/main_test.go | 44 | ||||
| -rw-r--r-- | docs/testing.md | 14 | ||||
| -rw-r--r-- | docs/usage.md | 22 |
6 files changed, 129 insertions, 4 deletions
diff --git a/PROJECTSTATUS.md b/PROJECTSTATUS.md index 1f61d5e..5959f31 100644 --- a/PROJECTSTATUS.md +++ b/PROJECTSTATUS.md @@ -4,7 +4,7 @@ This documents shows future items and in progress items. Already completed ones ## Features -### AI menu +### [/] AI menu ``` [keys.normal] @@ -23,8 +23,7 @@ And then generate a menu with all the code actions hexai-lsp knows of and includ ### More features -* [ ] Have all text LLM prompts be configurable. With defaults as of now. -* [ ] implement a code action for selected code block the way via a unix pipe as faster access in helix +* [/] implement a code action for selected code block the way via a unix pipe as faster access in helix - pipe selected code to external command and replace selection with output - the external command should open a menu to select an action (e.g. "format", "refactor", "explain", "test", etc.) and then apply it to the selected code - the external menu can be opened in a separate tmux pane @@ -96,3 +96,9 @@ Run: - `cat input.go | ./hexai-action` - or `./hexai-action < input.go` +- or with files: `./hexai-action --infile input.go --outfile output.go` + +Flags + +- `--infile` Read input from the given file instead of stdin. +- `--outfile` Write output to the given file instead of stdout (truncates/creates). diff --git a/cmd/internal/hexai-action/main.go b/cmd/internal/hexai-action/main.go index 50e6774..8bcc3cd 100644 --- a/cmd/internal/hexai-action/main.go +++ b/cmd/internal/hexai-action/main.go @@ -2,15 +2,55 @@ package main import ( "context" + "flag" "fmt" + "io" "os" "codeberg.org/snonux/hexai/internal/hexaiaction" ) func main() { - if err := hexaiaction.Run(context.Background(), os.Stdin, os.Stdout, os.Stderr); err != nil { + infile := flag.String("infile", "", "Read input from this file instead of stdin") + outfile := flag.String("outfile", "", "Write output to this file instead of stdout") + flag.Parse() + + in, out, closeIn, closeOut, err := openIO(*infile, *outfile) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer closeIn() + defer closeOut() + + if err := hexaiaction.Run(context.Background(), in, out, os.Stderr); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } + +// openIO returns readers/writers for infile/outfile flags with deferred closers. +func openIO(infile, outfile string) (io.Reader, io.Writer, func(), func(), error) { + in := io.Reader(os.Stdin) + out := io.Writer(os.Stdout) + closeIn := func() {} + closeOut := func() {} + + if path := infile; path != "" { + f, err := os.Open(path) + if err != nil { + return nil, nil, func() {}, func() {}, fmt.Errorf("hexai-action: cannot open infile: %w", err) + } + in = f + closeIn = func() { _ = f.Close() } + } + if path := outfile; path != "" { + f, err := os.Create(path) + if err != nil { + return nil, nil, func() {}, func() {}, fmt.Errorf("hexai-action: cannot open outfile: %w", err) + } + out = f + closeOut = func() { _ = f.Close() } + } + return in, out, closeIn, closeOut, nil +} diff --git a/cmd/internal/hexai-action/main_test.go b/cmd/internal/hexai-action/main_test.go new file mode 100644 index 0000000..9603826 --- /dev/null +++ b/cmd/internal/hexai-action/main_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "io" + "os" + "path/filepath" + "testing" +) + +// TestOpenIO_InOutFiles verifies that openIO opens the specified files +// and that writing via the returned writer persists to disk. +func TestOpenIO_InOutFiles(t *testing.T) { + dir := t.TempDir() + inPath := filepath.Join(dir, "in.txt") + outPath := filepath.Join(dir, "out.txt") + + // Prepare input file + want := "hello world" + if err := os.WriteFile(inPath, []byte(want), 0o600); err != nil { + t.Fatalf("write infile: %v", err) + } + + in, out, cin, cout, err := openIO(inPath, outPath) + if err != nil { + t.Fatalf("openIO: %v", err) + } + defer cin() + defer cout() + + // Copy through to simulate main's behavior + if _, err := io.Copy(out.(io.Writer), in); err != nil { + t.Fatalf("copy: %v", err) + } + + // Verify outfile content + got, err := os.ReadFile(outPath) + if err != nil { + t.Fatalf("read outfile: %v", err) + } + if string(got) != want { + t.Fatalf("mismatch: got %q want %q", string(got), want) + } +} + diff --git a/docs/testing.md b/docs/testing.md index eff6f2e..17dd4b3 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -14,3 +14,17 @@ Suggested additions: - Expand table‑driven coverage for completion edit computations and label/filter selection. - Add more negative tests (malformed SSE/JSON payloads) to assert robust error handling. +## Running Tests + +- Full suite with coverage: + - `HEXAI_TEST_SKIP_NET=1 go test ./... -cover` + - The `HEXAI_TEST_SKIP_NET=1` env var disables any tests that require network access, keeping runs deterministic in CI/sandboxes. + +- Package-specific runs: + - `HEXAI_TEST_SKIP_NET=1 go test ./cmd/internal/hexai-action -cover` + - `HEXAI_TEST_SKIP_NET=1 go test ./internal/hexaiaction -cover` + +Notes + +- Some environments restrict writes to the Go build cache; if you see cache permission errors, re-run in a less-restricted shell or allow the command to write to the cache. +- Always format Go code before committing: `gofumpt -w .` diff --git a/docs/usage.md b/docs/usage.md index c74ee7d..a5c5dca 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -102,3 +102,25 @@ hexai 'install ripgrep on macOS' # Verbose explanation hexai 'install ripgrep on macOS and explain' ``` + +## Hexai Action (TUI) + +`hexai-action` runs code actions over a selection or diagnostics+selection piped from stdin, or read from a file. + +- Choose an action with arrow keys, `j/k`, `g/G`, Enter, or hotkeys `[s] [r] [c] [t]`. +- Output is written to stdout by default, or to a file via `--outfile`. + +Input formats are the same as described in the README (inline instruction markers for rewrite; optional `Diagnostics:` header block). + +Examples + +```sh +# From stdin +cat input.go | hexai-action + +# From file to file +hexai-action --infile input.go --outfile output.go + +# Using shell redirection +hexai-action < input.go > output.go +``` |
