on 033acfa help sign in
vty/src/Graphics/Vty/Terminal.hs
128 lines 6.2 kB history raw
1-- Copyright 2009 Corey O'Connor
2-- * Graphics.Vty.Terminal: This instantiates an abtract interface to the terminal interface
3-- based on the TERM and COLORTERM environment variables.
4-- * Graphics.Vty.Terminal.Generic: Defines the generic interface all terminals need to implement.
5-- * Graphics.Vty.Terminal.TerminfoBased: Defines a terminal instance that uses terminfo for all
6-- control strings.
7-- - No attempt is made to change the character set to UTF-8 for these terminals. I don't
8-- know a way to reliably determine if that is required or how to do so.
9-- * Graphics.Vty.Terminal.XTermColor: This module contains an interface suitable for
10-- xterm-like terminals. These are the terminals where TERM == xterm. This does use terminfo
11-- for as many control codes as possible. H: This should derive functionality from the
12-- TerminfoBased terminal.
13--
14--
15{-# LANGUAGE ScopedTypeVariables #-}
16module Graphics.Vty.Terminal ( module Graphics.Vty.Terminal
17 , Terminal(..)
18 , TerminalHandle(..)
19 , DisplayHandle(..)
20 , output_picture
21 , display_context
22 )
23 where
26import Graphics.Vty.Terminal.Generic
27import Graphics.Vty.Terminal.MacOSX as MacOSX
28import Graphics.Vty.Terminal.XTermColor as XTermColor
29import Graphics.Vty.Terminal.TerminfoBased as TerminfoBased
31import Control.Applicative
32import Control.Exception ( SomeException, try )
33import Control.Monad.Trans
35import Data.List ( isPrefixOf )
36import Data.Word
38import System.Environment
40-- | Returns a TerminalHandle (an abstract Terminal instance) for the current terminal.
41--
42-- The specific Terminal implementation used is hidden from the API user. All terminal
43-- implementations are assumed to perform more, or less, the same. Currently all implementations use
44-- terminfo for at least some terminal specific information. This is why platforms without terminfo
45-- are not supported. However, as mentioned before, any specifics about it being based on terminfo
46-- are hidden from the API user. If a terminal implementation is developed for a terminal for a
47-- platform without terminfo support then Vty should work as expected on that terminal.
48--
49-- Selection of a terminal is done as follows:
50--
51-- * If TERM == xterm
52-- then the terminal might be one of the Mac OS X .app terminals. Check if that might be
53-- the case and use MacOSX if so.
54-- otherwise use XTermColor.
55--
56-- * for any other TERM value TerminfoBased is used.
57--
58--
59-- The terminal has to be determined dynamically at runtime. To satisfy this requirement all
60-- terminals instances are lifted into an abstract terminal handle via existential qualification.
61-- This implies that the only equations that can used are those in the terminal class.
62--
63-- To differentiate between Mac OS X terminals this uses the TERM_PROGRAM environment variable.
64-- However, an xterm started by Terminal or iTerm *also* has TERM_PROGRAM defined since the
65-- environment variable is not reset/cleared by xterm. However a Terminal.app or iTerm.app started
66-- from an xterm under X11 on mac os x will likely be done via open. Since this does not propogate
67-- environment variables (I think?) this assumes that XTERM_VERSION will never be set for a true
68-- Terminal.app or iTerm.app session.
69--
70-- todo: add an implementation for windows that does not depend on terminfo. Should be installable
71-- with only what is provided in the haskell platform.
72--
73-- todo: The Terminal interface does not provide any input support.
74terminal_handle :: ( Applicative m, MonadIO m ) => m TerminalHandle
75terminal_handle = do
76 term_type <- liftIO $ getEnv "TERM"
77 t <- if "xterm" `isPrefixOf` term_type
78 then do
79 maybe_terminal_app <- get_env "TERM_PROGRAM"
80 case maybe_terminal_app of
81 Nothing
82 -> XTermColor.terminal_instance term_type >>= new_terminal_handle
83 Just v | v == "Apple_Terminal" || v == "iTerm.app"
84 -> do
85 maybe_xterm <- get_env "XTERM_VERSION"
86 case maybe_xterm of
87 Nothing -> MacOSX.terminal_instance v >>= new_terminal_handle
88 Just _ -> XTermColor.terminal_instance term_type >>= new_terminal_handle
89 -- Assume any other terminal that sets TERM_PROGRAM to not be an OS X terminal.app
90 -- like terminal?
91 _ -> XTermColor.terminal_instance term_type >>= new_terminal_handle
92 -- Not an xterm-like terminal. try for generic terminfo.
93 else TerminfoBased.terminal_instance term_type >>= new_terminal_handle
94 return t
95 where
96 get_env var = do
97 mv <- liftIO $ try $ getEnv var
98 case mv of
99 Left (_e :: SomeException) -> return $ Nothing
100 Right v -> return $ Just v
102-- | Sets the cursor position to the given output column and row.
103--
104-- This is not necessarially the same as the character position with the same coordinates.
105-- Characters can be a variable number of columns in width.
106--
107-- Currently, the only way to set the cursor position to a given character coordinate is to specify
108-- the coordinate in the Picture instance provided to output_picture or refresh.
109set_cursor_pos :: MonadIO m => TerminalHandle -> Word -> Word -> m ()
110set_cursor_pos t x y = do
111 bounds <- display_bounds t
112 d <- display_context t bounds
113 liftIO $ marshall_to_terminal t (move_cursor_required_bytes d x y) (serialize_move_cursor d x y)
115-- | Hides the cursor
116hide_cursor :: MonadIO m => TerminalHandle -> m ()
117hide_cursor t = do
118 bounds <- display_bounds t
119 d <- display_context t bounds
120 liftIO $ marshall_to_terminal t (hide_cursor_required_bytes d) (serialize_hide_cursor d)
122-- | Shows the cursor
123show_cursor :: MonadIO m => TerminalHandle -> m ()
124show_cursor t = do
125 bounds <- display_bounds t
126 d <- display_context t bounds
127 liftIO $ marshall_to_terminal t (show_cursor_required_bytes d) (serialize_show_cursor d)