Skip to content

Commit

Permalink
Merge pull request #41 from thaJeztah/split_implementations
Browse files Browse the repository at this point in the history
split exported functions from implementation
  • Loading branch information
thaJeztah committed May 2, 2023
2 parents 4793886 + bb04910 commit 9c3c875
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 180 deletions.
3 changes: 3 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package term provides structures and helper functions to work with
// terminal (state, sizes).
package term
20 changes: 0 additions & 20 deletions tc.go

This file was deleted.

103 changes: 43 additions & 60 deletions term.go
Original file line number Diff line number Diff line change
@@ -1,102 +1,85 @@
//go:build !windows
// +build !windows

// Package term provides structures and helper functions to work with
// terminal (state, sizes).
package term

import (
"errors"
"io"
"os"

"golang.org/x/sys/unix"
)
import "io"

// ErrInvalidState is returned if the state of the terminal is invalid.
//
// Deprecated: ErrInvalidState is no longer used.
var ErrInvalidState = errors.New("Invalid terminal state")

// State represents the state of the terminal.
type State struct {
termios unix.Termios
}
// State holds the platform-specific state / console mode for the terminal.
type State terminalState

// Winsize represents the size of the terminal window.
type Winsize struct {
Height uint16
Width uint16
x uint16
y uint16

// Only used on Unix
x uint16
y uint16
}

// StdStreams returns the standard streams (stdin, stdout, stderr).
//
// On Windows, it attempts to turn on VT handling on all std handles if
// supported, or falls back to terminal emulation. On Unix, this returns
// the standard [os.Stdin], [os.Stdout] and [os.Stderr].
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
return os.Stdin, os.Stdout, os.Stderr
return stdStreams()
}

// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
func GetFdInfo(in interface{}) (uintptr, bool) {
var inFd uintptr
var isTerminalIn bool
if file, ok := in.(*os.File); ok {
inFd = file.Fd()
isTerminalIn = IsTerminal(inFd)
}
return inFd, isTerminalIn
func GetFdInfo(in interface{}) (fd uintptr, isTerminal bool) {
return getFdInfo(in)
}

// GetWinsize returns the window size based on the specified file descriptor.
func GetWinsize(fd uintptr) (*Winsize, error) {
return getWinsize(fd)
}

// SetWinsize tries to set the specified window size for the specified file
// descriptor. It is only implemented on Unix, and returns an error on Windows.
func SetWinsize(fd uintptr, ws *Winsize) error {
return setWinsize(fd, ws)
}

// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
_, err := tcget(fd)
return err == nil
return isTerminal(fd)
}

// RestoreTerminal restores the terminal connected to the given file descriptor
// to a previous state.
func RestoreTerminal(fd uintptr, state *State) error {
if state == nil {
return errors.New("invalid terminal state")
}
return tcset(fd, &state.termios)
return restoreTerminal(fd, state)
}

// SaveState saves the state of the terminal connected to the given file descriptor.
func SaveState(fd uintptr) (*State, error) {
termios, err := tcget(fd)
if err != nil {
return nil, err
}
return &State{termios: *termios}, nil
return saveState(fd)
}

// DisableEcho applies the specified state to the terminal connected to the file
// descriptor, with echo disabled.
func DisableEcho(fd uintptr, state *State) error {
newState := state.termios
newState.Lflag &^= unix.ECHO

if err := tcset(fd, &newState); err != nil {
return err
}
return nil
return disableEcho(fd, state)
}

// SetRawTerminal puts the terminal connected to the given file descriptor into
// raw mode and returns the previous state. On UNIX, this puts both the input
// and output into raw mode. On Windows, it only puts the input into raw mode.
func SetRawTerminal(fd uintptr) (*State, error) {
oldState, err := MakeRaw(fd)
if err != nil {
return nil, err
}
return oldState, err
// raw mode and returns the previous state. On UNIX, this is the equivalent of
// [MakeRaw], and puts both the input and output into raw mode. On Windows, it
// only puts the input into raw mode.
func SetRawTerminal(fd uintptr) (previousState *State, err error) {
return setRawTerminal(fd)
}

// SetRawTerminalOutput puts the output of terminal connected to the given file
// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
// state. On Windows, it disables LF -> CRLF translation.
func SetRawTerminalOutput(fd uintptr) (*State, error) {
return nil, nil
func SetRawTerminalOutput(fd uintptr) (previousState *State, err error) {
return setRawTerminalOutput(fd)
}

// MakeRaw puts the terminal (Windows Console) connected to the
// given file descriptor into raw mode and returns the previous state of
// the terminal so that it can be restored.
func MakeRaw(fd uintptr) (previousState *State, err error) {
return makeRaw(fd)
}
98 changes: 98 additions & 0 deletions term_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//go:build !windows
// +build !windows

package term

import (
"errors"
"io"
"os"

"golang.org/x/sys/unix"
)

// ErrInvalidState is returned if the state of the terminal is invalid.
//
// Deprecated: ErrInvalidState is no longer used.
var ErrInvalidState = errors.New("Invalid terminal state")

// terminalState holds the platform-specific state / console mode for the terminal.
type terminalState struct {
termios unix.Termios
}

func stdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
return os.Stdin, os.Stdout, os.Stderr
}

func getFdInfo(in interface{}) (uintptr, bool) {
var inFd uintptr
var isTerminalIn bool
if file, ok := in.(*os.File); ok {
inFd = file.Fd()
isTerminalIn = isTerminal(inFd)
}
return inFd, isTerminalIn
}

func getWinsize(fd uintptr) (*Winsize, error) {
uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel}
return ws, err
}

func setWinsize(fd uintptr, ws *Winsize) error {
return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &unix.Winsize{
Row: ws.Height,
Col: ws.Width,
Xpixel: ws.x,
Ypixel: ws.y,
})
}

func isTerminal(fd uintptr) bool {
_, err := tcget(fd)
return err == nil
}

func restoreTerminal(fd uintptr, state *State) error {
if state == nil {
return errors.New("invalid terminal state")
}
return tcset(fd, &state.termios)
}

func saveState(fd uintptr) (*State, error) {
termios, err := tcget(fd)
if err != nil {
return nil, err
}
return &State{termios: *termios}, nil
}

func disableEcho(fd uintptr, state *State) error {
newState := state.termios
newState.Lflag &^= unix.ECHO

return tcset(fd, &newState)
}

func setRawTerminal(fd uintptr) (*State, error) {
return makeRaw(fd)
}

func setRawTerminalOutput(fd uintptr) (*State, error) {
return nil, nil
}

func tcget(fd uintptr) (*unix.Termios, error) {
p, err := unix.IoctlGetTermios(int(fd), getTermios)
if err != nil {
return nil, err
}
return p, nil
}

func tcset(fd uintptr, p *unix.Termios) error {
return unix.IoctlSetTermios(int(fd), setTermios, p)
}

0 comments on commit 9c3c875

Please sign in to comment.