返回 DeepSeek-Reasonix
command_transport.go
根目录 / internal / persistentshell / command_transport.go
1 package persistentshell
2
3 import (
4 "context"
5 "fmt"
6 "strings"
7 )
8
9 type commandStage struct {
10 script string
11 ack string
12 }
13
14 // Leave framing headroom below Darwin's 1024-byte canonical input limit.
15 const commandWordLimit = 512
16
17 // Keep each input below the canonical PTY limit and wait until it is consumed.
18 // Newlines alone do not fence Readline's terminal-mode transitions, which can
19 // discard queued input. Staging never runs user code; only the final eval does.
20 func commandStages(command, start, end string) []commandStage {
21 if len(ansiCQuote(command)) <= commandWordLimit {
22 return []commandStage{{script: posixCommandScript(command, start, end)}}
23 }
24 variable := "__rx_command_" + newMarkerID()
25 var stages []commandStage
26 for offset := 0; offset < len(command); offset += commandWordLimit / 4 {
27 assignment := variable + "="
28 if offset > 0 {
29 assignment += `"$` + variable + `"`
30 }
31 ack := fmt.Sprintf("%s_INPUT_%d", start, offset)
32 script := assignment + ansiCQuote(command[offset:min(offset+commandWordLimit/4, len(command))]) +
33 "; printf '%s\\n' " + posixQuote(ack) + "\n"
34 stages = append(stages, commandStage{script: script, ack: ack})
35 }
36 return append(stages, commandStage{script: commandWordScript(`"$`+variable+`"`, start, end, "; unset "+variable)})
37 }
38
39 func (s *session) writeCommand(ctx context.Context, command, start, end string) error {
40 for _, stage := range commandStages(command, start, end) {
41 if err := ctx.Err(); err != nil {
42 return err
43 }
44 if err := s.writeScript(stage.script); err != nil {
45 return err
46 }
47 if stage.ack == "" {
48 return nil
49 }
50 var pending string
51 if err := s.pump(ctx, func(text string) bool {
52 pending += text
53 if strings.Contains(pending, stage.ack+"\n") {
54 return true
55 }
56 if len(pending) > markerOverlap {
57 pending = pending[len(pending)-markerOverlap:]
58 }
59 return false
60 }); err != nil {
61 return err
62 }
63 }
64 return nil
65 }
66
66 lines GO