如何獲取Haskell終端的寬度?獲取終端寬度Haskell
事情我想
System.Posix.IOCtl (could not figure out how to get it to work)
這隻會有工作UNIX。
感謝
如何獲取Haskell終端的寬度?獲取終端寬度Haskell
事情我想
System.Posix.IOCtl (could not figure out how to get it to work)
這隻會有工作UNIX。
感謝
如果你不想上ncurses的依賴呢,下面是一個使用FFI適當ioctl()
要求的包裝的基礎上,Getting terminal width in C?
TermSize.hsc
{-# LANGUAGE ForeignFunctionInterface #-}
module TermSize (getTermSize) where
import Foreign
import Foreign.C.Error
import Foreign.C.Types
#include <sys/ioctl.h>
#include <unistd.h>
-- Trick for calculating alignment of a type, taken from
-- http://www.haskell.org/haskellwiki/FFICookBook#Working_with_structs
#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
-- The ws_xpixel and ws_ypixel fields are unused, so I've omitted them here.
data WinSize = WinSize { wsRow, wsCol :: CUShort }
instance Storable WinSize where
sizeOf _ = (#size struct winsize)
alignment _ = (#alignment struct winsize)
peek ptr = do
row <- (#peek struct winsize, ws_row) ptr
col <- (#peek struct winsize, ws_col) ptr
return $ WinSize row col
poke ptr (WinSize row col) = do
(#poke struct winsize, ws_row) ptr row
(#poke struct winsize, ws_col) ptr col
foreign import ccall "sys/ioctl.h ioctl"
ioctl :: CInt -> CInt -> Ptr WinSize -> IO CInt
-- | Return current number of (rows, columns) of the terminal.
getTermSize :: IO (Int, Int)
getTermSize =
with (WinSize 0 0) $ \ws -> do
throwErrnoIfMinus1 "ioctl" $
ioctl (#const STDOUT_FILENO) (#const TIOCGWINSZ) ws
WinSize row col <- peek ws
return (fromIntegral row, fromIntegral col)
接受的答案這使用hsc2hs
preprocessor根據C標頭找出正確的常量和偏移量,而不是對它們進行硬編碼。我認爲它與GHC或Haskell平臺打包在一起,所以你已經有機會了。
如果您使用的是Cabal,您可以將TermSize.hs
添加到您的.cabal
文件中,它會自動知道如何從TermSize.hsc
生成它。否則,您可以手動運行hsc2hs TermSize.hsc
以生成.hs
文件,然後您可以使用GHC進行編譯。
你可以使用hcurses。初始化庫之後,可以使用scrSize
來獲取屏幕上的行數和列數。
要使用System.Posix.IOCtl
,你必須定義一個數據類型來表示TIOCGWINSZ
要求,填補了以下結構:
struct winsize {
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel; /* unused */
unsigned short ws_ypixel; /* unused */
};
你需要定義一個Haskell數據類型來保存這些信息,並使它的Storable
一個實例:
{-# LANGUAGE RecordWildCards #-}
import Foreign.Storable
import Foreign.Ptr
import Foreign.C
data Winsize = Winsize { ws_row :: CUShort
, ws_col :: CUShort
, ws_xpixel :: CUShort
, ws_ypixel :: CUShort
}
instance Storable Winsize where
sizeOf _ = 8
alignment _ = 2
peek p = do { ws_row <- peekByteOff p 0
; ws_col <- peekByteOff p 2
; ws_xpixel <- peekByteOff p 4
; ws_ypixel <- peekByteOff p 6
; return $ Winsize {..}
}
poke p Winsize {..} = do { pokeByteOff p 0 ws_row
; pokeByteOff p 2 ws_col
; pokeByteOff p 4 ws_xpixel
; pokeByteOff p 6 ws_ypixel
}
現在,你需要創建一個虛擬的數據類型來表示您的要求:
data TIOCGWINSZ = TIOCGWINSZ
最後,您需要將您的請求類型設置爲IOControl
的實例,並將其與Winsize
數據類型關聯。
instance IOControl TIOCGWINSZ Winsize where
ioctlReq _ = ??
您將需要更換??
與在頭文件TIOCGWINSZ
(0x5413
我的系統上)所代表的常數。
現在,您已準備好發出ioctl
。該命令不關心輸入數據,所以要使用ioctl'
形式:
main = do { ws <- ioctl' 1 TIOCGWINSZ
; putStrLn $ "My terminal is " ++ show (ws_col ws) ++ " columns wide"
}
注意,1是指標準輸出。
唷!
因爲你需要這隻能在Unix上,我建議:
resizeOutput <- readProcess "/usr/X11/bin/resize" [] ""
,然後做解析輸出的一點點位。這可能不是100%可移植的,但我確信你可以提供resize
參數(特別是檢查-u
),所以你會得到相當一致的輸出。
這很酷,我需要看看hsc2hs! – pat
非常好,謝謝 –