okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
9c745c5
main
1//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd 2 3package tui 4 5import ( 6"fmt" 7"os" 8"strconv" 9"strings" 10"time" 11 12"github.com/charmbracelet/x/term" 13"golang.org/x/sys/unix" 14) 15 16// queryColors asks for the text and background colors and the palette entries the theme mixes from, then asks 17// for the device attributes every terminal answers, so a terminal that 18// ignores the color queries ends the read instead of stalling it. 19func queryColors () (replyText string ,restoreErr error ) { 20tty ,err := os .OpenFile ("/dev/tty" ,os .O_RDWR ,0 ) 21if err != nil { 22return "" ,nil 23 } 24defer tty .Close () 25// Query failures use default colors; restoration failures must reach startup. 26fd := tty .Fd () 27state ,err := term .MakeRaw (fd ) 28if err != nil { 29return "" ,nil 30 } 31defer func () { 32if err := term .Restore (fd ,state );err != nil { 33restoreErr = fmt .Errorf ("could not restore terminal settings after color detection: %w" ,err ) 34 } 35 }() 36var query strings.Builder 37query .WriteString ("\x1b]10;?\x1b\\\x1b]11;?\x1b\\" ) 38for _ ,i := range queriedPalette { 39query .WriteString ("\x1b]4;" ) 40query .WriteString (strconv .Itoa (i )) 41query .WriteString (";?\x1b\\" ) 42 } 43query .WriteString ("\x1b[c" ) 44if _ ,err := tty .WriteString (query .String ());err != nil { 45return "" ,nil 46 } 47var reply strings.Builder 48deadline := time .Now ().Add (300 * time .Millisecond ) 49buf := make ([]byte ,256 ) 50for { 51left := time .Until (deadline ) 52if left <= 0 { 53break 54 } 55tv := unix .NsecToTimeval (int64 (left )) 56var ready unix.FdSet 57ready .Set (int (fd )) 58n ,err := unix .Select (int (fd )+ 1 ,& ready ,nil ,nil ,& tv ) 59if err == unix .EINTR { 60continue 61 } 62if err != nil || n == 0 { 63break 64 } 65n ,err = tty .Read (buf ) 66if err != nil { 67break 68 } 69reply .Write (buf [:n ]) 70// The device-attributes answer every terminal sends closes the read. 71if da := strings .Index (reply .String (),"\x1b[?" );da >= 0 && strings .Contains (reply .String ()[da :],"c" ) { 72break 73 } 74 } 75return reply .String (),nil 76}