Beispiel #1
0
// setupterm wraps the Terminfo setupterm, searching for possible options in
// multiple directories, including the system directory and $HOME/.terminfo
func setupterm(name string) error {
	oldpath := os.Getenv("TERMINFO")
	plist := strings.Split(oldpath, ":")
	if home := os.Getenv("HOME"); home != "" {
		plist = append(plist, home+"/.terminfo")
	}
	plist = append(plist, "")
	rsn := C.int(0)

	for _, p := range plist {
		// Override environment
		if p == "" {
			os.Unsetenv("TERMINFO")
		} else {
			os.Setenv("TERMINFO", p)
		}
		rv, _ := C.setupterm(C.CString(name), 1, &rsn)

		// Restore environment
		if oldpath == "" {
			os.Unsetenv("TERMINFO")
		} else {
			os.Setenv("TERMINFO", oldpath)
		}

		if rv != C.ERR {
			return nil
		}
	}

	switch rsn {
	case 1:
		return errors.New("hardcopy terminal")
	case 0:
		return errors.New("terminal definition not found")
	case -1:
		return errors.New("terminfo database missing")
	default:
		return errors.New("setupterm failed (other)")
	}
}
Beispiel #2
0
// This program is used to collect data from the system's terminfo library,
// and write it into Go source code.  That is, we maintain our terminfo
// capabilities encoded in the program.  It should never need to be run by
// an end user, but developers can use this to add codes for additional
// terminal types.
func getinfo(name string) (*tcell.Terminfo, error) {
	rsn := C.int(0)
	C.noenv()
	rv, _ := C.setupterm(C.CString(name), 1, &rsn)
	if rv == C.ERR {
		switch rsn {
		case 1:
			return nil, errors.New("hardcopy terminal")
		case 0:
			return nil, errors.New("terminal definition not found")
		case -1:
			return nil, errors.New("terminfo database missing")
		default:
			return nil, errors.New("setupterm failed (other)")
		}
	}
	t := &tcell.Terminfo{}
	t.Name = name
	t.Colors = tigetnum("colors")
	t.Columns = tigetnum("cols")
	t.Lines = tigetnum("lines")
	t.Bell = tigetstr("bel")
	t.Clear = tigetstr("clear")
	t.EnterCA = tigetstr("smcup")
	t.ExitCA = tigetstr("rmcup")
	t.ShowCursor = tigetstr("cnorm")
	t.HideCursor = tigetstr("civis")
	t.AttrOff = tigetstr("sgr0")
	t.Underline = tigetstr("smul")
	t.Bold = tigetstr("bold")
	t.Blink = tigetstr("blink")
	t.Dim = tigetstr("dim")
	t.Reverse = tigetstr("rev")
	t.EnterKeypad = tigetstr("smkx")
	t.ExitKeypad = tigetstr("rmkx")
	t.SetFg = tigetstr("setaf")
	t.SetBg = tigetstr("setab")
	t.SetCursor = tigetstr("cup")
	t.CursorBack1 = tigetstr("cub1")
	t.CursorUp1 = tigetstr("cuu1")
	t.KeyF1 = tigetstr("kf1")
	t.KeyF2 = tigetstr("kf2")
	t.KeyF3 = tigetstr("kf3")
	t.KeyF4 = tigetstr("kf4")
	t.KeyF5 = tigetstr("kf5")
	t.KeyF6 = tigetstr("kf6")
	t.KeyF7 = tigetstr("kf7")
	t.KeyF8 = tigetstr("kf8")
	t.KeyF9 = tigetstr("kf9")
	t.KeyF10 = tigetstr("kf10")
	t.KeyF11 = tigetstr("kf11")
	t.KeyF12 = tigetstr("kf12")
	t.KeyF13 = tigetstr("kf13")
	t.KeyF14 = tigetstr("kf14")
	t.KeyF15 = tigetstr("kf15")
	t.KeyF16 = tigetstr("kf16")
	t.KeyF17 = tigetstr("kf17")
	t.KeyF18 = tigetstr("kf18")
	t.KeyF19 = tigetstr("kf19")
	t.KeyF20 = tigetstr("kf20")
	t.KeyF21 = tigetstr("kf21")
	t.KeyF22 = tigetstr("kf22")
	t.KeyF23 = tigetstr("kf23")
	t.KeyF24 = tigetstr("kf24")
	t.KeyF25 = tigetstr("kf25")
	t.KeyF26 = tigetstr("kf26")
	t.KeyF27 = tigetstr("kf27")
	t.KeyF28 = tigetstr("kf28")
	t.KeyF29 = tigetstr("kf29")
	t.KeyF30 = tigetstr("kf30")
	t.KeyF31 = tigetstr("kf31")
	t.KeyF32 = tigetstr("kf32")
	t.KeyF33 = tigetstr("kf33")
	t.KeyF34 = tigetstr("kf34")
	t.KeyF35 = tigetstr("kf35")
	t.KeyF36 = tigetstr("kf36")
	t.KeyF37 = tigetstr("kf37")
	t.KeyF38 = tigetstr("kf38")
	t.KeyF39 = tigetstr("kf39")
	t.KeyF40 = tigetstr("kf40")
	t.KeyF41 = tigetstr("kf41")
	t.KeyF42 = tigetstr("kf42")
	t.KeyF43 = tigetstr("kf43")
	t.KeyF44 = tigetstr("kf44")
	t.KeyF45 = tigetstr("kf45")
	t.KeyF46 = tigetstr("kf46")
	t.KeyF47 = tigetstr("kf47")
	t.KeyF48 = tigetstr("kf48")
	t.KeyF49 = tigetstr("kf49")
	t.KeyF50 = tigetstr("kf50")
	t.KeyF51 = tigetstr("kf51")
	t.KeyF52 = tigetstr("kf52")
	t.KeyF53 = tigetstr("kf53")
	t.KeyF54 = tigetstr("kf54")
	t.KeyF55 = tigetstr("kf55")
	t.KeyF56 = tigetstr("kf56")
	t.KeyF57 = tigetstr("kf57")
	t.KeyF58 = tigetstr("kf58")
	t.KeyF59 = tigetstr("kf59")
	t.KeyF60 = tigetstr("kf60")
	t.KeyF61 = tigetstr("kf61")
	t.KeyF62 = tigetstr("kf62")
	t.KeyF63 = tigetstr("kf63")
	t.KeyF64 = tigetstr("kf64")
	t.KeyInsert = tigetstr("kich1")
	t.KeyDelete = tigetstr("kdch1")
	t.KeyBackspace = tigetstr("kbs")
	t.KeyHome = tigetstr("khome")
	t.KeyEnd = tigetstr("kend")
	t.KeyUp = tigetstr("kcuu1")
	t.KeyDown = tigetstr("kcud1")
	t.KeyRight = tigetstr("kcuf1")
	t.KeyLeft = tigetstr("kcub1")
	t.KeyPgDn = tigetstr("knp")
	t.KeyPgUp = tigetstr("kpp")
	t.KeyBacktab = tigetstr("kcbt")
	t.KeyExit = tigetstr("kext")
	t.KeyCancel = tigetstr("kcan")
	t.KeyPrint = tigetstr("kprt")
	t.KeyHelp = tigetstr("khlp")
	t.KeyClear = tigetstr("kclr")
	t.AltChars = tigetstr("acsc")
	t.EnterAcs = tigetstr("smacs")
	t.ExitAcs = tigetstr("rmacs")
	t.Mouse = tigetstr("kmous")
	// If the kmous entry is present, then we need to record the
	// the codes to enter and exit mouse mode.  Sadly, this is not
	// part of the terminfo databases anywhere that I've found, but
	// is an extension.  The escape codes are documented in the XTerm
	// manual, and all terminals that have kmous are expected to
	// use these same codes, unless explicitly configured otherwise
	// vi XM.  Note that in any event, we only known how to parse either
	// x11 or SGR mouse events -- if your terminal doesn't support one
	// of these two forms, you maybe out of luck.
	t.MouseMode = tigetstr("XM")
	if t.Mouse != "" && t.MouseMode == "" {
		// we anticipate that all xterm mouse tracking compatible
		// terminals understand mouse tracking (1000), but we hope
		// that those that don't understand any-event tracking (1003)
		// will at least ignore it.  Likewise we hope that terminals
		// that don't understand SGR reporting (1006) just ignore it.
		t.MouseMode = "%?%p1%{1}%=%t%'h'%Pa%e%'l'%Pa%;" +
			"\x1b[?1000%ga%c\x1b[?1003%ga%c\x1b[?1006%ga%c"
	}
	// We only support colors in ANSI 8 or 256 color mode.
	if t.Colors < 8 || t.SetFg == "" {
		t.Colors = 0
	}
	if t.SetCursor == "" {
		return nil, errors.New("terminal not cursor addressable")
	}

	// For padding, we lookup the pad char.  If that isn't present,
	// and npc is *not* set, then we assume a null byte.
	t.PadChar = tigetstr("pad")
	if t.PadChar == "" {
		if !tigetflag("npc") {
			t.PadChar = "\u0000"
		}
	}

	return t, nil
}
Beispiel #3
0
// This program is used to collect data from the system's terminfo library,
// and write it into Go source code.  That is, we maintain our terminfo
// capabilities encoded in the program.  It should never need to be run by
// an end user, but developers can use this to add codes for additional
// terminal types.
//
// If a terminal name ending with -truecolor is given, and we cannot find
// one, we will try to fabricte one from either the -256color (if present)
// or the unadorned base name, adding the XTerm specific 24-bit color
// escapes.  We believe that all 24-bit capable terminals use the same
// escape sequences, and terminfo has yet to evolve to support this.
func getinfo(name string) (*tcell.Terminfo, error) {
	addTrueColor := false
	rsn := C.int(0)
	C.noenv()
	rv, _ := C.setupterm(C.CString(name), 1, &rsn)
	if rv == C.ERR {
		if strings.HasSuffix(name, "-truecolor") {
			base := name[:len(name)-len("-truecolor")]
			// Probably -256color is closest to what we want
			rv, _ = C.setupterm(C.CString(base+"-256color"), 1,
				&rsn)
			// Otherwise try the base
			if rv == C.ERR {
				rv, _ = C.setupterm(C.CString(base), 1, &rsn)
			}
			if rv != C.ERR {
				addTrueColor = true
			}
		}
	}
	if rv == C.ERR {
		switch rsn {
		case 1:
			return nil, errors.New("hardcopy terminal")
		case 0:
			return nil, errors.New("terminal definition not found")
		case -1:
			return nil, errors.New("terminfo database missing")
		default:
			return nil, errors.New("setupterm failed (other)")
		}
	}
	t := &tcell.Terminfo{}
	t.Name = name
	t.Colors = tigetnum("colors")
	t.Columns = tigetnum("cols")
	t.Lines = tigetnum("lines")
	t.Bell = tigetstr("bel")
	t.Clear = tigetstr("clear")
	t.EnterCA = tigetstr("smcup")
	t.ExitCA = tigetstr("rmcup")
	t.ShowCursor = tigetstr("cnorm")
	t.HideCursor = tigetstr("civis")
	t.AttrOff = tigetstr("sgr0")
	t.Underline = tigetstr("smul")
	t.Bold = tigetstr("bold")
	t.Blink = tigetstr("blink")
	t.Dim = tigetstr("dim")
	t.Reverse = tigetstr("rev")
	t.EnterKeypad = tigetstr("smkx")
	t.ExitKeypad = tigetstr("rmkx")
	t.SetFg = tigetstr("setaf")
	t.SetBg = tigetstr("setab")
	t.SetCursor = tigetstr("cup")
	t.CursorBack1 = tigetstr("cub1")
	t.CursorUp1 = tigetstr("cuu1")
	t.KeyF1 = tigetstr("kf1")
	t.KeyF2 = tigetstr("kf2")
	t.KeyF3 = tigetstr("kf3")
	t.KeyF4 = tigetstr("kf4")
	t.KeyF5 = tigetstr("kf5")
	t.KeyF6 = tigetstr("kf6")
	t.KeyF7 = tigetstr("kf7")
	t.KeyF8 = tigetstr("kf8")
	t.KeyF9 = tigetstr("kf9")
	t.KeyF10 = tigetstr("kf10")
	t.KeyF11 = tigetstr("kf11")
	t.KeyF12 = tigetstr("kf12")
	t.KeyF13 = tigetstr("kf13")
	t.KeyF14 = tigetstr("kf14")
	t.KeyF15 = tigetstr("kf15")
	t.KeyF16 = tigetstr("kf16")
	t.KeyF17 = tigetstr("kf17")
	t.KeyF18 = tigetstr("kf18")
	t.KeyF19 = tigetstr("kf19")
	t.KeyF20 = tigetstr("kf20")
	t.KeyF21 = tigetstr("kf21")
	t.KeyF22 = tigetstr("kf22")
	t.KeyF23 = tigetstr("kf23")
	t.KeyF24 = tigetstr("kf24")
	t.KeyF25 = tigetstr("kf25")
	t.KeyF26 = tigetstr("kf26")
	t.KeyF27 = tigetstr("kf27")
	t.KeyF28 = tigetstr("kf28")
	t.KeyF29 = tigetstr("kf29")
	t.KeyF30 = tigetstr("kf30")
	t.KeyF31 = tigetstr("kf31")
	t.KeyF32 = tigetstr("kf32")
	t.KeyF33 = tigetstr("kf33")
	t.KeyF34 = tigetstr("kf34")
	t.KeyF35 = tigetstr("kf35")
	t.KeyF36 = tigetstr("kf36")
	t.KeyF37 = tigetstr("kf37")
	t.KeyF38 = tigetstr("kf38")
	t.KeyF39 = tigetstr("kf39")
	t.KeyF40 = tigetstr("kf40")
	t.KeyF41 = tigetstr("kf41")
	t.KeyF42 = tigetstr("kf42")
	t.KeyF43 = tigetstr("kf43")
	t.KeyF44 = tigetstr("kf44")
	t.KeyF45 = tigetstr("kf45")
	t.KeyF46 = tigetstr("kf46")
	t.KeyF47 = tigetstr("kf47")
	t.KeyF48 = tigetstr("kf48")
	t.KeyF49 = tigetstr("kf49")
	t.KeyF50 = tigetstr("kf50")
	t.KeyF51 = tigetstr("kf51")
	t.KeyF52 = tigetstr("kf52")
	t.KeyF53 = tigetstr("kf53")
	t.KeyF54 = tigetstr("kf54")
	t.KeyF55 = tigetstr("kf55")
	t.KeyF56 = tigetstr("kf56")
	t.KeyF57 = tigetstr("kf57")
	t.KeyF58 = tigetstr("kf58")
	t.KeyF59 = tigetstr("kf59")
	t.KeyF60 = tigetstr("kf60")
	t.KeyF61 = tigetstr("kf61")
	t.KeyF62 = tigetstr("kf62")
	t.KeyF63 = tigetstr("kf63")
	t.KeyF64 = tigetstr("kf64")
	t.KeyInsert = tigetstr("kich1")
	t.KeyDelete = tigetstr("kdch1")
	t.KeyBackspace = tigetstr("kbs")
	t.KeyHome = tigetstr("khome")
	t.KeyEnd = tigetstr("kend")
	t.KeyUp = tigetstr("kcuu1")
	t.KeyDown = tigetstr("kcud1")
	t.KeyRight = tigetstr("kcuf1")
	t.KeyLeft = tigetstr("kcub1")
	t.KeyPgDn = tigetstr("knp")
	t.KeyPgUp = tigetstr("kpp")
	t.KeyBacktab = tigetstr("kcbt")
	t.KeyExit = tigetstr("kext")
	t.KeyCancel = tigetstr("kcan")
	t.KeyPrint = tigetstr("kprt")
	t.KeyHelp = tigetstr("khlp")
	t.KeyClear = tigetstr("kclr")
	t.AltChars = tigetstr("acsc")
	t.EnterAcs = tigetstr("smacs")
	t.ExitAcs = tigetstr("rmacs")
	t.EnableAcs = tigetstr("enacs")
	t.Mouse = tigetstr("kmous")
	t.KeyShfRight = tigetstr("kRIT")
	t.KeyShfLeft = tigetstr("kLFT")
	t.KeyShfHome = tigetstr("kHOM")
	t.KeyShfEnd = tigetstr("kEND")

	// Terminfo lacks descriptions for a bunch of modified keys,
	// but modern XTerm and emulators often have them.  Let's add them,
	// if the shifted right and left arrows are defined.
	if t.KeyShfRight == "\x1b[1;2C" && t.KeyShfLeft == "\x1b[1;2D" {
		t.KeyShfUp = "\x1b[1;2A"
		t.KeyShfDown = "\x1b[1;2B"
		t.KeyMetaUp = "\x1b[1;9A"
		t.KeyMetaDown = "\x1b[1;9B"
		t.KeyMetaRight = "\x1b[1;9C"
		t.KeyMetaLeft = "\x1b[1;9D"
		t.KeyAltUp = "\x1b[1;3A"
		t.KeyAltDown = "\x1b[1;3B"
		t.KeyAltRight = "\x1b[1;3C"
		t.KeyAltLeft = "\x1b[1;3D"
		t.KeyCtrlUp = "\x1b[1;5A"
		t.KeyCtrlDown = "\x1b[1;5B"
		t.KeyCtrlRight = "\x1b[1;5C"
		t.KeyCtrlLeft = "\x1b[1;5D"
		t.KeyAltShfUp = "\x1b[1;4A"
		t.KeyAltShfDown = "\x1b[1;4B"
		t.KeyAltShfRight = "\x1b[1;4C"
		t.KeyAltShfLeft = "\x1b[1;4D"

		t.KeyMetaShfUp = "\x1b[1;10A"
		t.KeyMetaShfDown = "\x1b[1;10B"
		t.KeyMetaShfRight = "\x1b[1;10C"
		t.KeyMetaShfLeft = "\x1b[1;10D"

		t.KeyCtrlShfUp = "\x1b[1;6A"
		t.KeyCtrlShfDown = "\x1b[1;6B"
		t.KeyCtrlShfRight = "\x1b[1;6C"
		t.KeyCtrlShfLeft = "\x1b[1;6D"
	}
	// And also for Home and End
	if t.KeyShfHome == "\x1b[1;2H" && t.KeyShfEnd == "\x1b[1;2F" {
		t.KeyCtrlHome = "\x1b[1;5H"
		t.KeyCtrlEnd = "\x1b[1;5F"
		t.KeyAltHome = "\x1b[1;9H"
		t.KeyAltEnd = "\x1b[1;9F"
		t.KeyCtrlShfHome = "\x1b[1;6H"
		t.KeyCtrlShfEnd = "\x1b[1;6F"
		t.KeyAltShfHome = "\x1b[1;4H"
		t.KeyAltShfEnd = "\x1b[1;4F"
		t.KeyMetaShfHome = "\x1b[1;10H"
		t.KeyMetaShfEnd = "\x1b[1;10F"
	}

	// And the same thing for rxvt and workalikes (Eterm, aterm, etc.)
	// It seems that urxvt at least send ESC as ALT prefix for these,
	// although some places seem to indicate a separate ALT key sesquence.
	if t.KeyShfRight == "\x1b[c" && t.KeyShfLeft == "\x1b[d" {
		t.KeyShfUp = "\x1b[a"
		t.KeyShfDown = "\x1b[b"
		t.KeyCtrlUp = "\x1b[Oa"
		t.KeyCtrlDown = "\x1b[Ob"
		t.KeyCtrlRight = "\x1b[Oc"
		t.KeyCtrlLeft = "\x1b[Od"
	}
	if t.KeyShfHome == "\x1b[7$" && t.KeyShfEnd == "\x1b[8$" {
		t.KeyCtrlHome = "\x1b[7^"
		t.KeyCtrlEnd = "\x1b[8^"
	}

	// If the kmous entry is present, then we need to record the
	// the codes to enter and exit mouse mode.  Sadly, this is not
	// part of the terminfo databases anywhere that I've found, but
	// is an extension.  The escape codes are documented in the XTerm
	// manual, and all terminals that have kmous are expected to
	// use these same codes, unless explicitly configured otherwise
	// vi XM.  Note that in any event, we only known how to parse either
	// x11 or SGR mouse events -- if your terminal doesn't support one
	// of these two forms, you maybe out of luck.
	t.MouseMode = tigetstr("XM")
	if t.Mouse != "" && t.MouseMode == "" {
		// we anticipate that all xterm mouse tracking compatible
		// terminals understand mouse tracking (1000), but we hope
		// that those that don't understand any-event tracking (1003)
		// will at least ignore it.  Likewise we hope that terminals
		// that don't understand SGR reporting (1006) just ignore it.
		t.MouseMode = "%?%p1%{1}%=%t%'h'%Pa%e%'l'%Pa%;" +
			"\x1b[?1000%ga%c\x1b[?1003%ga%c\x1b[?1006%ga%c"
	}

	// We only support colors in ANSI 8 or 256 color mode.
	if t.Colors < 8 || t.SetFg == "" {
		t.Colors = 0
	}
	if t.SetCursor == "" {
		return nil, errors.New("terminal not cursor addressable")
	}

	// For padding, we lookup the pad char.  If that isn't present,
	// and npc is *not* set, then we assume a null byte.
	t.PadChar = tigetstr("pad")
	if t.PadChar == "" {
		if !tigetflag("npc") {
			t.PadChar = "\u0000"
		}
	}

	// For some terminals we fabricate a -truecolor entry, that may
	// not exist in terminfo.
	if addTrueColor {
		t.SetFgRGB = "\x1b[38;2;%p1%d;%p2%d;%p3%dm"
		t.SetBgRGB = "\x1b[48;2;%p1%d;%p2%d;%p3%dm"
		t.SetFgBgRGB = "\x1b[38;2;%p1%d;%p2%d;%p3%d;" +
			"48;2;%p4%d;%p5%d;%p6%dm"
	}

	// For terminals that use "standard" SGR sequences, lets combine the
	// foreground and background together.
	if strings.HasPrefix(t.SetFg, "\x1b[") &&
		strings.HasPrefix(t.SetBg, "\x1b[") &&
		strings.HasSuffix(t.SetFg, "m") &&
		strings.HasSuffix(t.SetBg, "m") {
		fg := t.SetFg[:len(t.SetFg)-1]
		r := regexp.MustCompile("%p1")
		bg := r.ReplaceAllString(t.SetBg[2:], "%p2")
		t.SetFgBg = fg + ";" + bg
	}

	return t, nil
}