diff options
Diffstat (limited to 'internal/askcli')
| -rw-r--r-- | internal/askcli/command_watch.go | 34 | ||||
| -rw-r--r-- | internal/askcli/command_watch_test.go | 26 |
2 files changed, 53 insertions, 7 deletions
diff --git a/internal/askcli/command_watch.go b/internal/askcli/command_watch.go index 0e326ef..8d8e35f 100644 --- a/internal/askcli/command_watch.go +++ b/internal/askcli/command_watch.go @@ -34,6 +34,25 @@ var newWatchTicker = func(interval time.Duration) watchTicker { return realWatchTicker{ticker: time.NewTicker(interval)} } +// deferredWriter buffers writes for capture while preserving terminal +// width detection by delegating Fd to the underlying writer. +type deferredWriter struct { + w io.Writer + buf bytes.Buffer +} + +func (dw *deferredWriter) Write(p []byte) (int, error) { + return dw.buf.Write(p) +} + +func (dw *deferredWriter) Fd() uintptr { + type fder interface{ Fd() uintptr } + if f, ok := dw.w.(fder); ok { + return f.Fd() + } + return 0 +} + func (d *Dispatcher) handleWatch(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { watchArgs := args[1:] if len(watchArgs) == 0 { @@ -49,7 +68,7 @@ func (d *Dispatcher) handleWatch(ctx context.Context, args []string, stdout, std var lastOutput []byte for { - output, code, err := d.watchOutput(ctx, watchArgs) + output, code, err := d.watchOutput(ctx, watchArgs, stdout, stderr) if err != nil { return code, err } @@ -85,16 +104,17 @@ func watchCommandAllowed(args []string) bool { return false } -func (d *Dispatcher) watchOutput(ctx context.Context, args []string) ([]byte, int, error) { - var stdout, stderr bytes.Buffer - code, err := d.dispatchCommand(ctx, append([]string(nil), args...), nil, &stdout, &stderr) +func (d *Dispatcher) watchOutput(ctx context.Context, args []string, realStdout, realStderr io.Writer) ([]byte, int, error) { + outW := &deferredWriter{w: realStdout} + errW := &deferredWriter{w: realStderr} + code, err := d.dispatchCommand(ctx, append([]string(nil), args...), nil, outW, errW) if err != nil { return nil, code, fmt.Errorf("watch %s: %w", args[0], err) } // Combine stdout and stderr so warnings or errors emitted by the // watched subcommand are visible in the watched display. - out := make([]byte, 0, stdout.Len()+stderr.Len()) - out = append(out, stdout.Bytes()...) - out = append(out, stderr.Bytes()...) + out := make([]byte, 0, outW.buf.Len()+errW.buf.Len()) + out = append(out, outW.buf.Bytes()...) + out = append(out, errW.buf.Bytes()...) return out, code, nil } diff --git a/internal/askcli/command_watch_test.go b/internal/askcli/command_watch_test.go index 77d0fda..abd74ff 100644 --- a/internal/askcli/command_watch_test.go +++ b/internal/askcli/command_watch_test.go @@ -267,3 +267,29 @@ func TestHandleWatch_RejectsUnsafeSubcommands(t *testing.T) { }) } } + +type mockFdWriter struct { + io.Writer + fd uintptr +} + +func (m *mockFdWriter) Fd() uintptr { return m.fd } + +func TestDeferredWriter_PreservesFd(t *testing.T) { + w := &mockFdWriter{Writer: &bytes.Buffer{}, fd: 42} + dw := &deferredWriter{w: w} + if got := dw.Fd(); got != 42 { + t.Fatalf("Fd() = %d, want 42", got) + } + _, _ = dw.Write([]byte("hello")) + if !bytes.Equal(dw.buf.Bytes(), []byte("hello")) { + t.Fatalf("buf = %q, want hello", dw.buf.Bytes()) + } +} + +func TestDeferredWriter_FdZeroWhenUnsupported(t *testing.T) { + dw := &deferredWriter{w: &bytes.Buffer{}} + if got := dw.Fd(); got != 0 { + t.Fatalf("Fd() = %d, want 0", got) + } +} |
