@@ -15,7 +15,7 @@ module Graphics.Vty.Output.TerminfoBased ( reserveTerminal )
16import Graphics.Vty.Prelude
16import Graphics.Vty.Prelude
18−import qualified Data.ByteString as BS
18+import Data.ByteString.Internal (toForeignPtr)
19import Data.Terminfo.Parse
19import Data.Terminfo.Parse
20import Data.Terminfo.Eval
20import Data.Terminfo.Eval
@@ -34,29 +34,10 @@ import Data.Maybe (isJust, isNothing, fromJust)
34import Data.Monoid
34import Data.Monoid
36import Foreign.C.Types ( CInt(..), CLong(..) )
36import Foreign.C.Types ( CInt(..), CLong(..) )
37−
37+import Foreign.ForeignPtr (withForeignPtr)
39−#ifdef __GLASGOW_HASKELL__
40−#if __GLASGOW_HASKELL__ >= 611
41−import GHC.IO.Handle.Internals (withHandle_)
42−import GHC.IO.Handle.Types (Handle__(..))
43−import qualified GHC.IO.FD as FD
44−-- import qualified GHC.IO.Handle.FD as FD
45−import GHC.IO.Exception
46−import Data.Typeable (cast)
49−import GHC.Handle hiding (fdToHandle)
50−import qualified GHC.Handle
54import qualified System.Console.Terminfo as Terminfo
39import qualified System.Console.Terminfo as Terminfo
55−#ifdef __GLASGOW_HASKELL__
56−#if __GLASGOW_HASKELL__ >= 611
57−import System.IO.Error
40+import System.Posix.IO (fdWriteBuf)
60import System.Posix.Types (Fd(..))
41import System.Posix.Types (Fd(..))
62data TerminfoCaps = TerminfoCaps
43data TerminfoCaps = TerminfoCaps
@@ -101,9 +82,9 @@ sendCapToTerminal t cap capParams = do
101 - todo: Some display attributes like underline and bold have independent string capabilities that
82 - todo: Some display attributes like underline and bold have independent string capabilities that
102 - should be used instead of the generic "sgr" string capability.
83 - should be used instead of the generic "sgr" string capability.
104−reserveTerminal :: ( Applicative m, MonadIO m ) => String -> Handle -> m Output
85+reserveTerminal :: ( Applicative m, MonadIO m ) => String -> Fd -> m Output
105−reserveTerminal inID outHandle = liftIO $ do
86+reserveTerminal termName outFd = liftIO $ do
106− ti <- Terminfo.setupTerm inID
87+ ti <- Terminfo.setupTerm termName
107 -- assumes set foreground always implies set background exists.
88 -- assumes set foreground always implies set background exists.
108 -- if set foreground is not set then all color changing style attributes are filtered.
89 -- if set foreground is not set then all color changing style attributes are filtered.
109 msetaf <- probeCap ti "setaf"
90 msetaf <- probeCap ti "setaf"
@@ -113,14 +94,14 @@ reserveTerminal inID outHandle = liftIO $ do
113 Just setaf -> (False, False, setaf)
94 Just setaf -> (False, False, setaf)
114 Nothing -> case msetf of
95 Nothing -> case msetf of
115 Just setf -> (False, True, setf)
96 Just setf -> (False, True, setf)
116− Nothing -> (True, True, error $ "no fore color support for terminal " ++ inID)
97+ Nothing -> (True, True, error $ "no fore color support for terminal " ++ termName)
117 msetab <- probeCap ti "setab"
98 msetab <- probeCap ti "setab"
118 msetb <- probeCap ti "setb"
99 msetb <- probeCap ti "setb"
119 let set_back_cap
100 let set_back_cap
120 = case msetab of
101 = case msetab of
121 Nothing -> case msetb of
102 Nothing -> case msetb of
122 Just setb -> setb
103 Just setb -> setb
123− Nothing -> error $ "no back color support for terminal " ++ inID
104+ Nothing -> error $ "no back color support for terminal " ++ termName
124 Just setab -> setab
105 Just setab -> setab
125 terminfoCaps <- pure TerminfoCaps
106 terminfoCaps <- pure TerminfoCaps
126 <*> probeCap ti "smcup"
107 <*> probeCap ti "smcup"
@@ -138,28 +119,28 @@ reserveTerminal inID outHandle = liftIO $ do
138 <*> currentDisplayAttrCaps ti
119 <*> currentDisplayAttrCaps ti
139 newAssumedStateRef <- newIORef initialAssumedState
120 newAssumedStateRef <- newIORef initialAssumedState
140 let t = Output
121 let t = Output
141− { terminalID = inID
122+ { terminalID = termName
142 , releaseTerminal = liftIO $ do
123 , releaseTerminal = liftIO $ do
143 sendCap setDefaultAttr []
124 sendCap setDefaultAttr []
144 maybeSendCap cnorm []
125 maybeSendCap cnorm []
146 , reserveDisplay = liftIO $ do
126 , reserveDisplay = liftIO $ do
147 -- If there is no support for smcup: Clear the screen and then move the mouse to the
127 -- If there is no support for smcup: Clear the screen and then move the mouse to the
148 -- home position to approximate the behavior.
128 -- home position to approximate the behavior.
149 maybeSendCap smcup []
129 maybeSendCap smcup []
151 sendCap clearScreen []
130 sendCap clearScreen []
152 , releaseDisplay = liftIO $ do
131 , releaseDisplay = liftIO $ do
153 maybeSendCap rmcup []
132 maybeSendCap rmcup []
154 maybeSendCap cnorm []
133 maybeSendCap cnorm []
155 , displayBounds = do
134 , displayBounds = do
156− rawSize <- liftIO $ withFd outHandle getWindowSize
135+ rawSize <- liftIO $ getWindowSize outFd
157 case rawSize of
136 case rawSize of
158 (w, h) | w < 0 || h < 0 -> fail $ "getwinsize returned < 0 : " ++ show rawSize
137 (w, h) | w < 0 || h < 0 -> fail $ "getwinsize returned < 0 : " ++ show rawSize
159 | otherwise -> return (w,h)
138 | otherwise -> return (w,h)
160 , outputByteBuffer = \outBytes -> do
139 , outputByteBuffer = \outBytes -> do
161− BS.hPut outHandle outBytes
140+ let (fptr, _offset, len) = toForeignPtr outBytes
162− hFlush outHandle
141+ actualLen <- withForeignPtr fptr $ \ptr -> fdWriteBuf outFd ptr (toEnum len)
142+ when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer length "
143+ ++ "mismatch. Please report a bug to vty project."
163 , contextColorCount
144 , contextColorCount
164 = case supportsNoColors terminfoCaps of
145 = case supportsNoColors terminfoCaps of
165 False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
146 False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
@@ -462,22 +443,3 @@ styleToApplySeq s = concat
463 else [op]
444 else [op]
465−-- from https://patch-tag.com/r/mae/sendfile/snapshot/current/content/pretty/src/Network/Socket/SendFile/Internal.hs
466−-- The Fd should not be used after the action returns because the
467−-- Handler may be garbage collected and than will cause the finalizer
469−withFd :: Handle -> (Fd -> IO a) -> IO a
470−#ifdef __GLASGOW_HASKELL__
471−#if __GLASGOW_HASKELL__ >= 611
472−withFd h f = withHandle_ "withFd" h $ \ Handle__{..} -> do
473− case cast haDevice of
474− Nothing -> ioError (ioeSetErrorString (mkIOError IllegalOperation
475− "withFd" (Just h) Nothing)
476− "handle is not a file descriptor")
477− Just fd -> f (Fd (fromIntegral (FD.fdFD fd)))
480− withHandle_ "withFd" h $ \ h_ ->
481− f (Fd (fromIntegral (haFD h_)))