Last active
December 31, 2021 06:54
-
-
Save pgaskin/4c1a7ff8e0f752d0d1cf262f08afbd7c to your computer and use it in GitHub Desktop.
Go function to intercept escape sequences to set the terminal title.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| // interceptsl intercepts escape sequences to set the terminal title. | |
| func interceptsl(ctx context.Context, w io.Writer, r io.Reader, title chan<- string) error { | |
| state := 0 | |
| ibuf := make([]byte, 256) | |
| tbuf := make([]byte, 256) | |
| obuf := make([]byte, 256) // will use up to cap(ibuf) + cap(tbuf) + 4 in certain situations | |
| for { | |
| select { | |
| case <-ctx.Done(): | |
| return ctx.Err() | |
| default: | |
| } | |
| // note: Go will handle EAGAIN, EINTR, and polling internally while reading files | |
| // note: for a pty, VMIN=0 and VTIME=1 seems to work well (EAGAIN will be returned when nothing is available) | |
| // note: for writes, we don't need to check the count since Go io.Writers are supposed to always do full writes | |
| n, err := r.Read(ibuf) | |
| if err != nil { | |
| return err | |
| } else if n == 0 { | |
| continue | |
| } | |
| // fast path when no escape sequences in the buffer | |
| if state == 0 { | |
| for _, c := range ibuf[:n] { | |
| if c == 0x1B { | |
| goto slowpath | |
| } | |
| } | |
| _, _ = w.Write(ibuf[:n]) | |
| continue | |
| } | |
| slowpath: | |
| obuf = obuf[:0] | |
| for _, c := range ibuf[:n] { | |
| switch state { | |
| case 0: // normal output | |
| switch c { | |
| default: | |
| state = 0 | |
| obuf = append(obuf, c) | |
| case 0x1B: | |
| state = 1 | |
| } | |
| case 1: // at \x1B | |
| switch c { | |
| default: | |
| state = 0 | |
| obuf = append(obuf, 0x1B, c) | |
| case ']': | |
| state = 2 | |
| } | |
| case 2: // at \x1B] | |
| switch c { | |
| default: | |
| state = 0 | |
| obuf = append(obuf, 0x1B, ']', c) | |
| case '0': | |
| state = 3 | |
| } | |
| case 3: // at \x1B]0 | |
| switch c { | |
| default: | |
| state = 0 | |
| obuf = append(obuf, 0x1B, ']', '0', c) | |
| case ';': | |
| state = 4 | |
| tbuf = tbuf[:0] | |
| } | |
| case 4: // in \x1B]0; | |
| switch c { | |
| default: | |
| // next title char | |
| if len(tbuf) < cap(tbuf) { | |
| tbuf = append(tbuf, c) | |
| break // out of the switch | |
| } | |
| fallthrough | |
| case 0x07: | |
| // end of title || overflow | |
| select { | |
| case title <- string(tbuf): | |
| default: | |
| } | |
| if len(tbuf) == cap(tbuf) { | |
| state = 5 | |
| } else { | |
| state = 0 | |
| } | |
| tbuf = tbuf[:0] | |
| case 0x1B: | |
| // start of a new escape sequence (this shouldn't happen) | |
| state = 1 | |
| } | |
| case 5: // in title | |
| switch c { | |
| default: | |
| // overflowing title character | |
| case 0x07: | |
| // end of the overflowing title | |
| state = 0 | |
| case 0x1B: | |
| // start of a new escape sequence (this shouldn't happen) | |
| state = 1 | |
| } | |
| } | |
| } | |
| _, _ = w.Write(obuf) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment