@@ -15,7 +15,7 @@ module Graphics.Vty.Output.TerminfoBased ( reserveTerminal )
1515
1616import Graphics.Vty.Prelude
1717
18−import qualified Data.ByteString as BS
18+import Data.ByteString.Internal (toForeignPtr)
1919import Data.Terminfo.Parse
2020import Data.Terminfo.Eval
2121
@@ -34,29 +34,10 @@ import Data.Maybe (isJust, isNothing, fromJust)
3434import Data.Monoid
3535
3636import Foreign.C.Types ( CInt(..), CLong(..) )
37−
38−import GHC.IO.Handle
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)
47−#else
48−import GHC.IOBase
49−import GHC.Handle hiding (fdToHandle)
50−import qualified GHC.Handle
51−#endif
52−#endif
37+import Foreign.ForeignPtr (withForeignPtr)
5338
5439import qualified System.Console.Terminfo as Terminfo
55−#ifdef __GLASGOW_HASKELL__
56−#if __GLASGOW_HASKELL__ >= 611
57−import System.IO.Error
58−#endif
59−#endif
40+import System.Posix.IO (fdWriteBuf)
6041import System.Posix.Types (Fd(..))
6142
6243data TerminfoCaps = TerminfoCaps
@@ -101,9 +82,9 @@ sendCapToTerminal t cap capParams = do
10182 - todo: Some display attributes like underline and bold have independent string capabilities that
10283 - should be used instead of the generic "sgr" string capability.
10384 -}
104−reserveTerminal :: ( Applicative m, MonadIO m ) => String -> Handle -> m Output
105−reserveTerminal inID outHandle = liftIO $ do
106− ti <- Terminfo.setupTerm inID
85+reserveTerminal :: ( Applicative m, MonadIO m ) => String -> Fd -> m Output
86+reserveTerminal termName outFd = liftIO $ do
87+ ti <- Terminfo.setupTerm termName
10788 -- assumes set foreground always implies set background exists.
10889 -- if set foreground is not set then all color changing style attributes are filtered.
10990 msetaf <- probeCap ti "setaf"
@@ -113,14 +94,14 @@ reserveTerminal inID outHandle = liftIO $ do
11394 Just setaf -> (False, False, setaf)
11495 Nothing -> case msetf of
11596 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)
11798 msetab <- probeCap ti "setab"
11899 msetb <- probeCap ti "setb"
119100 let set_back_cap
120101 = case msetab of
121102 Nothing -> case msetb of
122103 Just setb -> setb
123− Nothing -> error $ "no back color support for terminal " ++ inID
104+ Nothing -> error $ "no back color support for terminal " ++ termName
124105 Just setab -> setab
125106 terminfoCaps <- pure TerminfoCaps
126107 <*> probeCap ti "smcup"
@@ -138,28 +119,28 @@ reserveTerminal inID outHandle = liftIO $ do
138119 <*> currentDisplayAttrCaps ti
139120 newAssumedStateRef <- newIORef initialAssumedState
140121 let t = Output
141− { terminalID = inID
122+ { terminalID = termName
142123 , releaseTerminal = liftIO $ do
143124 sendCap setDefaultAttr []
144125 maybeSendCap cnorm []
145− hClose outHandle
146126 , reserveDisplay = liftIO $ do
147127 -- If there is no support for smcup: Clear the screen and then move the mouse to the
148128 -- home position to approximate the behavior.
149129 maybeSendCap smcup []
150− hFlush outHandle
151130 sendCap clearScreen []
152131 , releaseDisplay = liftIO $ do
153132 maybeSendCap rmcup []
154133 maybeSendCap cnorm []
155134 , displayBounds = do
156− rawSize <- liftIO $ withFd outHandle getWindowSize
135+ rawSize <- liftIO $ getWindowSize outFd
157136 case rawSize of
158137 (w, h) | w < 0 || h < 0 -> fail $ "getwinsize returned < 0 : " ++ show rawSize
159138 | otherwise -> return (w,h)
160139 , outputByteBuffer = \outBytes -> do
161− BS.hPut outHandle outBytes
162− hFlush outHandle
140+ let (fptr, _offset, len) = toForeignPtr outBytes
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."
163144 , contextColorCount
164145 = case supportsNoColors terminfoCaps of
165146 False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
@@ -462,22 +443,3 @@ styleToApplySeq s = concat
462443 then []
463444 else [op]
464445
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
468−-- to close the fd.
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)))
478−#else
479−withFd h f =
480− withHandle_ "withFd" h $ \ h_ ->
481− f (Fd (fromIntegral (haFD h_)))
482−#endif
483−#endif