Skip to content

Commit

Permalink
#3, make it work on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
ndmitchell committed Nov 7, 2014
1 parent 055e432 commit ea72545
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 21 deletions.
42 changes: 26 additions & 16 deletions src/System/Console/Terminal/Size.hs
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
{-# LANGUAGE CPP #-}
{- |
Get terminal window height and width without ncurses dependency
Only tested to work on GNU/Linux systems
Based on answer by Andreas Hammar at <http://stackoverflow.com/a/12807521/972985>
-}
module System.Console.Terminal.Size
( Window(..), size, fdSize, hSize
( Window(..), size
#if !defined(mingw32_HOST_OS)
,fdSize, hSize
#endif
) where

import System.Console.Terminal.Common
import qualified System.Console.Terminal.Posix as Posix
#if defined(mingw32_HOST_OS)
import qualified System.Console.Terminal.Windows as Host
#else
import qualified System.Console.Terminal.Posix as Host
import System.Posix.Types(Fd)
import System.IO(Handle)
#endif


-- | Get terminal window width and height for @stdout@.
--
-- >>> import System.Console.Terminal.Size
-- >>> size
-- Just (Window {height = 60, width = 112})
size :: Integral n => IO (Maybe (Window n))
size = Host.size

-- | Get terminal window width and height for a specified file descriptor. If
#if !defined(mingw32_HOST_OS)
-- | /Not available on Windows:/
-- Get terminal window width and height for a specified file descriptor. If
-- it's not attached to a terminal then 'Nothing' is returned.
--
-- >>> import System.Console.Terminal.Size
Expand All @@ -26,21 +42,15 @@ import System.IO(Handle)
-- >>> fdSize fd
-- Nothing
fdSize :: Integral n => Fd -> IO (Maybe (Window n))
fdSize = Posix.fdSize

-- | Get terminal window width and height for @stdout@.
--
-- >>> import System.Console.Terminal.Size
-- >>> size
-- Just (Window {height = 60, width = 112})
size :: Integral n => IO (Maybe (Window n))
size = Posix.size
fdSize = Host.fdSize

-- | Same as 'fdSize', but takes 'Handle' instead of 'Fd' (file descriptor).
-- | /Not available on Windows:/
-- Same as 'fdSize', but takes 'Handle' instead of 'Fd' (file descriptor).
--
-- >>> import System.Console.Terminal.Size
-- >>> import System.IO
-- >>> hSize stdout
-- Just (Window {height = 56, width = 85})
hSize :: Integral n => Handle -> IO (Maybe (Window n))
hSize = Posix.hSize
hSize = Host.hSize
#endif
41 changes: 41 additions & 0 deletions src/System/Console/Terminal/Windows.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

module System.Console.Terminal.Windows(size) where

import System.Console.Terminal.Common

import Control.Monad
import Data.Word
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Alloc

type HANDLE = Ptr ()

data CONSOLE_SCREEN_BUFFER_INFO

sizeCONSOLE_SCREEN_BUFFER_INFO :: Int
sizeCONSOLE_SCREEN_BUFFER_INFO = 22

posCONSOLE_SCREEN_BUFFER_INFO_srWindow :: Int
posCONSOLE_SCREEN_BUFFER_INFO_srWindow = 10 -- 4 x Word16 Left,Top,Right,Bottom

c_STD_OUTPUT_HANDLE :: Word32
c_STD_OUTPUT_HANDLE = -11

foreign import stdcall unsafe "windows.h GetConsoleScreenBufferInfo"
c_GetConsoleScreenBufferInfo :: HANDLE -> Ptr CONSOLE_SCREEN_BUFFER_INFO -> IO Bool

foreign import stdcall unsafe "windows.h GetStdHandle"
c_GetStdHandle :: Word32 -> IO HANDLE


size :: Integral n => IO (Maybe (Window n))
size = do
hdl <- c_GetStdHandle c_STD_OUTPUT_HANDLE
allocaBytes sizeCONSOLE_SCREEN_BUFFER_INFO $ \p -> do
b <- c_GetConsoleScreenBufferInfo hdl p
if not b then return Nothing else do
[left,top,right,bottom] <- forM [0..3] $ \i -> do
v <- peekByteOff p ((i*2) + posCONSOLE_SCREEN_BUFFER_INFO_srWindow)
return $ fromIntegral (v :: Word16)
return $ Just $ Window (1+bottom-top) (1+right-left)
11 changes: 6 additions & 5 deletions terminal-size.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ name: terminal-size
version: 0.2.1.0
synopsis: Get terminal window height and width
description:
Get terminal window height and width without ncurses dependency
.
Only tested to work on GNU/Linux systems
Get terminal window height and width without ncurses dependency.
license: BSD3
license-file: LICENSE
author: Andreas Hammar, Matvey Aksenov
Expand All @@ -19,8 +17,11 @@ library
build-tools: hsc2hs
hs-source-dirs: src
exposed-modules: System.Console.Terminal.Size
other-modules: System.Console.Terminal.Posix
System.Console.Terminal.Common
other-modules: System.Console.Terminal.Common
if os(Windows)
other-modules: System.Console.Terminal.Windows
else
other-modules: System.Console.Terminal.Posix
ghc-options: -Wall
-fno-warn-unused-do-bind

Expand Down

0 comments on commit ea72545

Please sign in to comment.