summaryrefslogtreecommitdiff
path: root/internal/askcli
diff options
context:
space:
mode:
Diffstat (limited to 'internal/askcli')
-rw-r--r--internal/askcli/command_watch.go34
-rw-r--r--internal/askcli/command_watch_test.go26
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)
+ }
+}