on bcda3db help sign in
vty/src/Graphics/Vty/Terminal.hs
129 lines 6.3 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.Either
36import Data.List ( isPrefixOf )
37import Data.Word
39import System.Environment
41-- | Returns a TerminalHandle (an abstract Terminal instance) for the current terminal.
42--
43-- The specific Terminal implementation used is hidden from the API user. All terminal
44-- implementations are assumed to perform more, or less, the same. Currently all implementations use
45-- terminfo for at least some terminal specific information. This is why platforms without terminfo
46-- are not supported. However, as mentioned before, any specifics about it being based on terminfo
47-- are hidden from the API user. If a terminal implementation is developed for a terminal for a
48-- platform without terminfo support then Vty should work as expected on that terminal.
49--
50-- Selection of a terminal is done as follows:
51--
52-- * If TERM == xterm
53-- then the terminal might be one of the Mac OS X .app terminals. Check if that might be
54-- the case and use MacOSX if so.
55-- otherwise use XTermColor.
56--
57-- * for any other TERM value TerminfoBased is used.
58--
59--
60-- The terminal has to be determined dynamically at runtime. To satisfy this requirement all
61-- terminals instances are lifted into an abstract terminal handle via existential qualification.
62-- This implies that the only equations that can used are those in the terminal class.
63--
64-- To differentiate between Mac OS X terminals this uses the TERM_PROGRAM environment variable.
65-- However, an xterm started by Terminal or iTerm *also* has TERM_PROGRAM defined since the
66-- environment variable is not reset/cleared by xterm. However a Terminal.app or iTerm.app started
67-- from an xterm under X11 on mac os x will likely be done via open. Since this does not propogate
68-- environment variables (I think?) this assumes that XTERM_VERSION will never be set for a true
69-- Terminal.app or iTerm.app session.
70--
71-- todo: add an implementation for windows that does not depend on terminfo. Should be installable
72-- with only what is provided in the haskell platform.
73--
74-- todo: The Terminal interface does not provide any input support.
75terminal_handle :: ( Applicative m, MonadIO m ) => m TerminalHandle
76terminal_handle = do
77 term_type <- liftIO $ getEnv "TERM"
78 t <- if "xterm" `isPrefixOf` term_type
79 then do
80 maybe_terminal_app <- get_env "TERM_PROGRAM"
81 case maybe_terminal_app of
82 Nothing
83 -> XTermColor.terminal_instance term_type >>= new_terminal_handle
84 Just v | v == "Apple_Terminal" || v == "iTerm.app"
85 -> do
86 maybe_xterm <- get_env "XTERM_VERSION"
87 case maybe_xterm of
88 Nothing -> MacOSX.terminal_instance v >>= new_terminal_handle
89 Just _ -> XTermColor.terminal_instance term_type >>= new_terminal_handle
90 -- Assume any other terminal that sets TERM_PROGRAM to not be an OS X terminal.app
91 -- like terminal?
92 _ -> XTermColor.terminal_instance term_type >>= new_terminal_handle
93 -- Not an xterm-like terminal. try for generic terminfo.
94 else TerminfoBased.terminal_instance term_type >>= new_terminal_handle
95 return t
96 where
97 get_env var = do
98 mv <- liftIO $ try $ getEnv var
99 case mv of
100 Left (_e :: SomeException) -> return $ Nothing
101 Right v -> return $ Just v
103-- | Sets the cursor position to the given output column and row.
104--
105-- This is not necessarially the same as the character position with the same coordinates.
106-- Characters can be a variable number of columns in width.
107--
108-- Currently, the only way to set the cursor position to a given character coordinate is to specify
109-- the coordinate in the Picture instance provided to output_picture or refresh.
110set_cursor_pos :: MonadIO m => TerminalHandle -> Word -> Word -> m ()
111set_cursor_pos t x y = do
112 bounds <- display_bounds t
113 d <- display_context t bounds
114 liftIO $ marshall_to_terminal t (move_cursor_required_bytes d x y) (serialize_move_cursor d x y)
116-- | Hides the cursor
117hide_cursor :: MonadIO m => TerminalHandle -> m ()
118hide_cursor t = do
119 bounds <- display_bounds t
120 d <- display_context t bounds
121 liftIO $ marshall_to_terminal t (hide_cursor_required_bytes d) (serialize_hide_cursor d)
123-- | Shows the cursor
124show_cursor :: MonadIO m => TerminalHandle -> m ()
125show_cursor t = do
126 bounds <- display_bounds t
127 d <- display_context t bounds
128 liftIO $ marshall_to_terminal t (show_cursor_required_bytes d) (serialize_show_cursor d)