Haskellで端末の幅を取得する方法は?端末の幅を取得するHaskell
物事は私はこれが唯一のUNIXを動作するように持っている
System.Posix.IOCtl (could not figure out how to get it to work)
を試してみました。
おかげ
Haskellで端末の幅を取得する方法は?端末の幅を取得するHaskell
物事は私はこれが唯一のUNIXを動作するように持っている
System.Posix.IOCtl (could not figure out how to get it to work)
を試してみました。
おかげ
あなたは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 Platformのどちらかと一緒にパッケージ化されていると思うので、あなたはすでにそれを持っている可能性があります。
Cabalを使用している場合は、.cabal
ファイルにTermSize.hs
を追加して、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
}
は今、あなたはあなたの要求を表現するためのダミーデータ型を作成する必要があります。
最後に、要求タイプをIOControl
と入力し、Winsize
データタイプに関連付ける必要があります。
instance IOControl TIOCGWINSZ Winsize where
ioctlReq _ = ??
あなたのヘッダファイルでTIOCGWINSZ
(私のシステム上の0x5413
)で表される定数で??
を交換する必要があります。
これでioctl
を発行する準備が整いました。 1は、STDOUTを参照していること
main = do { ws <- ioctl' 1 TIOCGWINSZ
; putStrLn $ "My terminal is " ++ show (ws_col ws) ++ " columns wide"
}
注:あなたがioctl'
フォームを使用したいので、このコマンドは、入力されたデータを気にしません。
Phew!
あなただけのUnix上でこれを必要とするので、私はお勧め:
resizeOutput <- readProcess "/usr/X11/bin/resize" [] ""
そして出力の構文解析の小さなビットをしています。これは100%移植可能ではないかもしれませんが、私はあなたがresize
に引数を与えて(特に-u
をチェックしてください)、かなり安定した出力を得ることができると信じています。
それはクールだ、私はhsc2hsを見てする必要があります! – pat
非常に良い、ありがとう –