-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuffer.go
More file actions
101 lines (88 loc) · 3.51 KB
/
buffer.go
File metadata and controls
101 lines (88 loc) · 3.51 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
package command
import (
"errors"
"io"
)
// ErrClosed is returned when attempting to read from or write to a closed
// reader or writer.
var ErrClosed = errors.New("command: write to closed buffer")
// ErrReadOnly is returned when attempting to write to a read-only command.
var ErrReadOnly = errors.New("command: write to read-only buffer")
// Buffer represents a command's execution.
// Buffers provide read access to command output.
// Reading drives execution and returns output until the command completes.
//
// Buffers may implement additional interfaces for extended capabilities:
// - [AttachBuffer] - connect to controlling terminal
// - [LogBuffer] - capture diagnostic output
// - [WriteBuffer] - provide input to the command
type Buffer interface {
// Read reads output from the command.
// The command starts on first Read and completes at EOF.
// Implementations must return EOF when the command terminates.
// Multiple reads may be required to consume all output.
io.Reader
}
// WriteBuffer is an optional interface for buffers that accept input.
// Buffers that accept input allow writing to the command's stdin.
//
// Note that Close closes stdin, not stdout.
// The buffer must still be read to EOF to observe command completion.
type WriteBuffer interface {
Buffer
// Write writes data to the command's stdin.
// The command starts on first Write if it hasn't started from Read.
// Implementations should buffer or stream data to the command's stdin.
io.Writer
// Close closes the command's stdin, signaling EOF to the command.
// This does NOT close stdout - the buffer must still be read to EOF.
// After Close, subsequent Write calls must return an error.
// Implementations should wait for stdin close to propagate to the command.
io.Closer
}
// AttachBuffer is an optional interface for terminal-attached buffers.
// Terminal-attached buffers connect the command directly to the terminal
// for interactive use.
//
// After calling Attach, the buffer must still be readable exactly once
// to observe command completion, but the Read must return 0 bytes and EOF.
type AttachBuffer interface {
Buffer
// Attach connects the command to the controlling terminal.
// Both stdin and stdout must be connected to allow interactive use.
// The command should start immediately if not already started.
//
// After Attach returns, the buffer must remain readable exactly once.
// The single Read call must block until the command completes,
// then return 0 bytes read and io.EOF.
//
// Implementations must handle terminal control sequences, raw mode,
// and proper cleanup of terminal state.
Attach() error
}
// LogBuffer is an optional interface for buffers with diagnostic output.
// Buffers with diagnostic output can capture stderr separately from stdout.
type LogBuffer interface {
Buffer
// Log sets the destination for diagnostic output (stderr).
// Implementations must write all stderr output to w.
// This is typically called before any Read to ensure stderr is captured.
// Multiple Log calls should replace the previous destination.
Log(io.Writer)
}
// Attach attaches buf to the controlling terminal if it implements
// [AttachBuffer].
// Does nothing if buf does not implement AttachBuffer.
func Attach(buf Buffer) error {
if a, ok := buf.(AttachBuffer); ok {
return a.Attach()
}
return nil
}
// Log sets the log destination for buf if it implements [LogBuffer].
// Does nothing if buf does not implement LogBuffer.
func Log(buf Buffer, w io.Writer) {
if l, ok := buf.(LogBuffer); ok {
l.Log(w)
}
}