github.com/kopoli/go-terminal-size@v0.0.0-20170219200355-5c97524c8b54/size.go (about)

     1  // Package tsize gets the terminal size. Supports Linux and Windows.
     2  package tsize
     3  
     4  import (
     5  	"errors"
     6  	"os"
     7  
     8  	isatty "github.com/mattn/go-isatty"
     9  )
    10  
    11  // Size represents terminal size in columns and rows as Width and Height,
    12  // respectively.
    13  type Size struct {
    14  	Width  int
    15  	Height int
    16  }
    17  
    18  var isTerminal = isatty.IsTerminal
    19  
    20  // ErrNotATerminal is the error to return if the given file to FgetSize isn't a
    21  // terminal.
    22  var ErrNotATerminal = errors.New("Given file is not a terminal")
    23  
    24  // GetSize gets the current terminal size. The terminal is expected to be
    25  // os.Stdout. Returns the NotATerminal error, if it is not a terminal.
    26  func GetSize() (s Size, err error) {
    27  	return FgetSize(os.Stdout)
    28  }
    29  
    30  // FgetSize gets the terminal size of a given os.File. Returns the NotATerminal error, if it is not a terminal.
    31  func FgetSize(fp *os.File) (s Size, err error) {
    32  	if fp == nil || !isTerminal(fp.Fd()) {
    33  		err = ErrNotATerminal
    34  		return
    35  	}
    36  
    37  	s, err = getTerminalSize(fp)
    38  	return
    39  }
    40  
    41  // SizeListener listens to terminal size changes. The new size is returned
    42  // through the Change channel when the change occurs.
    43  type SizeListener struct {
    44  	Change <-chan Size
    45  
    46  	done chan struct{}
    47  }
    48  
    49  // Close implements the io.Closer interface that stops listening to terminal
    50  // size changes.
    51  func (sc *SizeListener) Close() (err error) {
    52  	if sc.done != nil {
    53  		close(sc.done)
    54  		sc.done = nil
    55  		sc.Change = nil
    56  	}
    57  
    58  	return
    59  }
    60  
    61  // NewSizeListener creates a new size change listener
    62  func NewSizeListener() (sc *SizeListener, err error) {
    63  	sc = &SizeListener{}
    64  
    65  	sizechan := make(chan Size, 1)
    66  	sc.Change = sizechan
    67  	sc.done = make(chan struct{})
    68  
    69  	err = getTerminalSizeChanges(sizechan, sc.done)
    70  	if err != nil {
    71  		close(sizechan)
    72  		close(sc.done)
    73  		sc = &SizeListener{}
    74  		return
    75  	}
    76  
    77  	return
    78  }