packages feed

pretty-ghci-0.1.0.0: src/System/Terminal/Utils.hsc

{-# LANGUAGE ForeignFunctionInterface #-}

module System.Terminal.Utils (
  getTerminalSize,
) where

import Foreign
import Foreign.C.Types
import Foreign.Marshal.Alloc ( alloca )


-- | Try to get the number of rows and columns respectively in the terminal
getTerminalSize :: IO (Maybe (Int,Int))

#if defined(WINDOWS)

getTerminalSize = pure Nothing

#else

#include <sys/ioctl.h>
#include <unistd.h>

getTerminalSize = alloca $ \ws -> do
  res <- ioctl (#const STDOUT_FILENO) (#const TIOCGWINSZ) ws
  if res == -1
    then pure Nothing
    else do
      WinSize row col <- peek ws
      pure (Just (fromIntegral row, fromIntegral col))

-- | @ioctl@ fills the struct at the pointer you passed in with the size info
foreign import ccall "sys/ioctl.h ioctl"
  ioctl :: CInt -> CInt -> Ptr WinSize -> IO CInt

-- | Match @struct winsize@ in @sys/ioctl.h@.
data WinSize = WinSize CUShort 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
    pure (WinSize row col)
  poke ptr (WinSize row col) = do
    (#poke struct winsize, ws_row) ptr row
    (#poke struct winsize, ws_col) ptr col

#endif