11package cmd
22
33import (
4+ "context"
45 "encoding/json"
56 "fmt"
7+ "os"
8+ "os/signal"
9+ "syscall"
10+ "time"
611
712 "github.com/schovi/shelli/internal/ansi"
813 "github.com/schovi/shelli/internal/daemon"
3136 readTimeoutFlag int
3237 readStripAnsiFlag bool
3338 readJsonFlag bool
39+ readFollowFlag bool
40+ readFollowMsFlag int
3441)
3542
3643func init () {
@@ -42,6 +49,8 @@ func init() {
4249 readCmd .Flags ().IntVar (& readTimeoutFlag , "timeout" , 10 , "Max wait time in seconds (for blocking modes)" )
4350 readCmd .Flags ().BoolVar (& readStripAnsiFlag , "strip-ansi" , false , "Strip ANSI escape codes" )
4451 readCmd .Flags ().BoolVar (& readJsonFlag , "json" , false , "Output as JSON" )
52+ readCmd .Flags ().BoolVarP (& readFollowFlag , "follow" , "f" , false , "Follow output continuously (like tail -f)" )
53+ readCmd .Flags ().IntVar (& readFollowMsFlag , "follow-ms" , 100 , "Poll interval for --follow in milliseconds" )
4554}
4655
4756func runRead (cmd * cobra.Command , args []string ) error {
@@ -76,6 +85,13 @@ func runRead(cmd *cobra.Command, args []string) error {
7685 return fmt .Errorf ("--wait and --settle are mutually exclusive" )
7786 }
7887
88+ if readFollowFlag {
89+ if readAllFlag || readHeadFlag > 0 || readTailFlag > 0 || blocking || readJsonFlag {
90+ return fmt .Errorf ("--follow cannot be combined with --all, --head, --tail, --wait, --settle, or --json" )
91+ }
92+ return runReadFollow (name )
93+ }
94+
7995 client := daemon .NewClient ()
8096 if err := client .EnsureDaemon (); err != nil {
8197 return fmt .Errorf ("daemon: %w" , err )
@@ -138,3 +154,42 @@ func runRead(cmd *cobra.Command, args []string) error {
138154
139155 return nil
140156}
157+
158+ func runReadFollow (name string ) error {
159+ client := daemon .NewClient ()
160+ if err := client .EnsureDaemon (); err != nil {
161+ return fmt .Errorf ("daemon: %w" , err )
162+ }
163+
164+ ctx , cancel := context .WithCancel (context .Background ())
165+ defer cancel ()
166+
167+ sigCh := make (chan os.Signal , 1 )
168+ signal .Notify (sigCh , syscall .SIGINT , syscall .SIGTERM )
169+ go func () {
170+ <- sigCh
171+ cancel ()
172+ }()
173+
174+ pollInterval := time .Duration (readFollowMsFlag ) * time .Millisecond
175+ ticker := time .NewTicker (pollInterval )
176+ defer ticker .Stop ()
177+
178+ for {
179+ select {
180+ case <- ctx .Done ():
181+ return nil
182+ case <- ticker .C :
183+ output , _ , err := client .Read (name , daemon .ReadModeNew , 0 , 0 )
184+ if err != nil {
185+ return err
186+ }
187+ if output != "" {
188+ if readStripAnsiFlag {
189+ output = ansi .Strip (output )
190+ }
191+ fmt .Print (output )
192+ }
193+ }
194+ }
195+ }
0 commit comments