你如何获得 Go 中的终端大小?

Posted

技术标签:

【中文标题】你如何获得 Go 中的终端大小?【英文标题】:How do you get the terminal size in Go? 【发布时间】:2009-11-14 03:38:31 【问题描述】:

如何在 Go 中获取终端大小。在 C 中它看起来像这样:

struct ttysize ts; 
ioctl(0, TIOCGWINSZ, &ts);

但是如何在 Go 中访问 TIOCGWINSZ

【问题讨论】:

【参考方案1】:

cgo编译器目前不能处理c函数中的变量参数和c头文件中的宏,所以不能简单的处理

// #include <sys/ioctl.h>
// typedef struct ttysize ttysize;
import "C"

func GetWinSz() 
    var ts C.ttysize;
    C.ioctl(0,C.TIOCGWINSZ,&ts)

要绕过宏使用常量,所以

// #include <sys/ioctl.h>
// typedef struct ttysize ttysize;
import "C"

const TIOCGWINSZ C.ulong = 0x5413; // Value from Jed Smith's answer

func GetWinSz() 
    var ts C.ttysize;
    C.ioctl(0,TIOCGWINSZ,&ts)

然而,cgo 仍然会对 ioctl 原型中的 ... 感到厌烦。您最好的选择是使用带有特定数量参数的 c 函数包装 ioctl 并将其链接。作为一种技巧,您可以在上面的评论中执行此操作 import "C"

// #include <sys/ioctl.h>
// typedef struct ttysize ttysize;
// void myioctl(int i, unsigned long l, ttysize * t)ioctl(i,l,t);
import "C"

const TIOCGWINSZ C.ulong = 0x5413; // Value from Jed Smith's answer

func GetWinSz() 
    var ts C.ttysize;
    C.myioctl(0,TIOCGWINSZ,&ts)

我没有对此进行测试,但类似的东西应该可以工作。

【讨论】:

【参考方案2】:

最好的方法是使用 syscall 包。 syscall 包没有定义 ioctl 函数,因为它只是做了很多不同的事情,但您仍然可以这样调用它:

syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(TIOCGWINSZ), uintptr(unsafe.Pointer(&ts)))

剩下的两件事是复制 winsize 结构和您需要的常量。为此的工具是 godefs,它将通过查看 C 头文件中的结构和常量来生成一个 .go 源文件。创建一个如下所示的 termios.c 文件:

#include <termios.h>

enum 
    $TIOCGWINSZ = TIOCGWINSZ
;

typedef winsize $winsize;

现在运行

godefs -gpackagename termios.c > termios.go

现在您应该拥有获取终端尺寸所需的一切。设置大小就像在 termios.c 中添加另一个常量一样简单。

【讨论】:

【参考方案3】:

阅读:http://www.darkcoding.net/software/pretty-command-line-console-output-on-unix-in-python-and-go-lang/

const (
    TIOCGWINSZ     = 0x5413
    TIOCGWINSZ_OSX = 1074295912
)

type window struct 
    Row    uint16
    Col    uint16
    Xpixel uint16
    Ypixel uint16


func terminalWidth() (int, error) 
    w := new(window)
    tio := syscall.TIOCGWINSZ
    if runtime.GOOS == "darwin" 
        tio = TIOCGWINSZ_OSX
    
    res, _, err := syscall.Syscall(syscall.SYS_IOCTL,
        uintptr(syscall.Stdin),
        uintptr(tio),
        uintptr(unsafe.Pointer(w)),
    )
    if int(res) == -1 
        return 0, err
    
    return int(w.Col), nil

【讨论】:

【参考方案4】:

随便看看文档,似乎还没有做太多工作——事实上,我根本找不到ioctl

对于一门处于起步阶段的语言,可以肯定地说您是在人迹罕至的地方。 TIOCGWINSZ本身只是一个常量整数(我在Linux源码中找到了它的值):

#define TIOCGWINSZ  0x5413

祝你好运。

【讨论】:

以上是关于你如何获得 Go 中的终端大小?的主要内容,如果未能解决你的问题,请参考以下文章

在 Go 中获取终端大小

你如何获得沙发数据库的大小

如何从终端中的谷歌测试套件获得c ++代码超额?

Go 语言实现的帅帅的 Git 终端 UI:lazygit

如何从PHP中的URL获取图像的大小?

如何获得Windows Server 2008 R2中的总虚拟内存