Initial commit

This commit is contained in:
La Ancapo 2026-01-25 02:27:22 +01:00
commit c101616e62
309 changed files with 53937 additions and 0 deletions

View file

@ -0,0 +1,190 @@
{-# LANGUAGE CApiFFI #-}
module Basement.Terminal.Size
( getDimensions
) where
import Foreign
import Foreign.C
import Basement.Compat.Base
import Basement.Types.OffsetSize
import Basement.Numerical.Subtractive
import Basement.Numerical.Additive
import Prelude (fromIntegral)
#include "foundation_system.h"
#ifdef FOUNDATION_SYSTEM_WINDOWS
import System.Win32.Types (HANDLE, BOOL)
import Graphics.Win32.Misc (getStdHandle, sTD_OUTPUT_HANDLE, StdHandleId)
#include <windows.h>
#elif defined FOUNDATION_SYSTEM_UNIX
#include <sys/ioctl.h>
#ifdef __sun
#include <sys/termios.h>
#endif
#endif
#include <stdio.h>
#if __GLASGOW_HASKELL__ < 800
#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
#endif
#ifdef FOUNDATION_SYSTEM_UNIX
data Winsize = Winsize
{ ws_row :: !Word16
, ws_col :: !Word16
, ws_xpixel :: !Word16
, ws_ypixel :: !Word16
}
instance Storable Winsize where
sizeOf _ = #{size struct winsize}
alignment _ = #{alignment struct winsize}
peek ptr = do
r <- #{peek struct winsize, ws_row} ptr
c <- #{peek struct winsize, ws_col} ptr
x <- #{peek struct winsize, ws_xpixel} ptr
y <- #{peek struct winsize, ws_ypixel} ptr
return (Winsize r c x y)
poke ptr (Winsize r c x y) = do
#{poke struct winsize, ws_row} ptr r
#{poke struct winsize, ws_col} ptr c
#{poke struct winsize, ws_xpixel} ptr x
#{poke struct winsize, ws_ypixel} ptr y
#elif defined FOUNDATION_SYSTEM_WINDOWS
type Handle = Ptr CChar -- void *
data SmallRect = SmallRect
{ left :: !Int16
, top :: !Int16
, right :: !Int16
, bottom :: !Int16
} deriving (Show)
instance Storable SmallRect where
sizeOf _ = #{size SMALL_RECT}
alignment _ = #{alignment SMALL_RECT}
peek ptr = do
l <- #{peek SMALL_RECT, Left} ptr
r <- #{peek SMALL_RECT, Right} ptr
t <- #{peek SMALL_RECT, Top} ptr
b <- #{peek SMALL_RECT, Bottom} ptr
return (SmallRect l t r b)
poke ptr (SmallRect l t r b) = do
#{poke SMALL_RECT, Left} ptr l
#{poke SMALL_RECT, Top} ptr t
#{poke SMALL_RECT, Right} ptr r
#{poke SMALL_RECT, Bottom} ptr b
data Coord = Coord
{ x :: !Int16
, y :: !Int16
} deriving (Show)
instance Storable Coord where
sizeOf _ = #{size COORD}
alignment _ = #{alignment COORD}
peek ptr = do
x <- #{peek COORD, X} ptr
y <- #{peek COORD, Y} ptr
return (Coord x y)
poke ptr (Coord x y) = do
#{poke COORD, X} ptr x
#{poke COORD, Y} ptr y
data ConsoleScreenBufferInfo = ConsoleScreenBufferInfo
{ dwSize :: !Coord
, dwCursorPosition :: !Coord
, wAttributes :: !Word16
, srWindow :: !SmallRect
, dwMaximumWindowSize :: !Coord
} deriving (Show)
instance Storable ConsoleScreenBufferInfo where
sizeOf _ = #{size CONSOLE_SCREEN_BUFFER_INFO}
alignment _ = #{alignment CONSOLE_SCREEN_BUFFER_INFO}
peek ptr = do
s <- #{peek CONSOLE_SCREEN_BUFFER_INFO, dwSize} ptr
c <- #{peek CONSOLE_SCREEN_BUFFER_INFO, dwCursorPosition} ptr
a <- #{peek CONSOLE_SCREEN_BUFFER_INFO, wAttributes} ptr
w <- #{peek CONSOLE_SCREEN_BUFFER_INFO, srWindow} ptr
m <- #{peek CONSOLE_SCREEN_BUFFER_INFO, dwMaximumWindowSize} ptr
return (ConsoleScreenBufferInfo s c a w m)
poke ptr (ConsoleScreenBufferInfo s c a w m) = do
#{poke CONSOLE_SCREEN_BUFFER_INFO, dwSize} ptr s
#{poke CONSOLE_SCREEN_BUFFER_INFO, dwCursorPosition} ptr c
#{poke CONSOLE_SCREEN_BUFFER_INFO, wAttributes} ptr a
#{poke CONSOLE_SCREEN_BUFFER_INFO, srWindow} ptr w
#{poke CONSOLE_SCREEN_BUFFER_INFO, dwMaximumWindowSize} ptr m
invalidHandleValue :: IntPtr
invalidHandleValue = #{const INVALID_HANDLE_VALUE}
stdOutputHandle :: CULong
stdOutputHandle = #{const STD_OUTPUT_HANDLE}
#endif
-- defined FOUNDATION_SYSTEM_WINDOWS
#ifdef FOUNDATION_SYSTEM_UNIX
foreign import capi "sys/ioctl.h ioctl" c_ioctl :: CInt -> CULong -> Ptr a -> IO CInt
-- | Get the terminal windows size
tiocgwinsz :: CULong
tiocgwinsz = Prelude.fromIntegral (#{const TIOCGWINSZ} :: Word)
#elif defined FOUNDATION_SYSTEM_WINDOWS
foreign import ccall "GetConsoleScreenBufferInfo" c_get_console_screen_buffer_info
:: HANDLE -> Ptr ConsoleScreenBufferInfo -> IO BOOL
#endif
#ifdef FOUNDATION_SYSTEM_UNIX
ioctlWinsize :: CInt -> IO (Maybe (CountOf Char, CountOf Char))
ioctlWinsize fd = alloca $ \winsizePtr -> do
status <- c_ioctl fd tiocgwinsz winsizePtr
if status == (-1 :: CInt)
then pure Nothing
else Just . toDimensions <$> peek winsizePtr
where
toDimensions winsize =
( CountOf . Prelude.fromIntegral . ws_col $ winsize
, CountOf . Prelude.fromIntegral . ws_row $ winsize)
#elif defined FOUNDATION_SYSTEM_WINDOWS
getConsoleScreenBufferInfo :: HANDLE -> IO (Maybe ConsoleScreenBufferInfo)
getConsoleScreenBufferInfo handle = alloca $ \infoPtr -> do
status <- c_get_console_screen_buffer_info handle infoPtr
if status
then Just <$> peek infoPtr
else pure Nothing
winWinsize :: StdHandleId -> IO (Maybe (CountOf Char, CountOf Char))
winWinsize handleRef = (infoToDimensions <$>) <$>
(getStdHandle handleRef >>= getConsoleScreenBufferInfo)
where
infoToDimensions info =
let window = srWindow info
width = Prelude.fromIntegral (right window - left window + 1)
height = Prelude.fromIntegral (bottom window - top window + 1)
in (CountOf width, CountOf height)
#endif
-- defined FOUNDATION_SYSTEM_WINDOWS
-- | Return the size of the current terminal
--
-- If the system is not supported or that querying the system result in an error
-- then a default size of (80, 24) will be given back.
getDimensions :: IO (CountOf Char, CountOf Char)
getDimensions =
#if defined FOUNDATION_SYSTEM_WINDOWS
maybe defaultSize id <$> winWinsize sTD_OUTPUT_HANDLE
#elif defined FOUNDATION_SYSTEM_UNIX
maybe defaultSize id <$> ioctlWinsize 0
#else
pure defaultSize
#endif
where
defaultSize = (80, 24)