on master help sign in
Merge pull request #97 from jtdaugherty/feature/bracketed-paste-mode

Add support for bracketed paste mode in XtermColor-driven terminals (fixes #50)

commit6e591693b8415c5e696e7c732abcfc69c73ddfd1 authorJonathan Daugherty <cygnus@foobox.com> dateSat 25 Jun 2016, 13:24 (10 years ago) parentb74a8b8f2a4744
6 files changed+70−2
src/Graphics/Vty/Input/Classify.hs+6−1 src/Graphics/Vty/Input/Events.hs+6 src/Graphics/Vty/Input/Mouse.hs−1 src/Graphics/Vty/Input/Paste.hs+46 src/Graphics/Vty/Output/XTermColor.hs+11 vty.cabal+1
src/Graphics/Vty/Input/Classify.hs+6−1
@@ -13,11 +13,12 @@ module Graphics.Vty.Input.Classify
1313
1414import Graphics.Vty.Input.Events
1515import Graphics.Vty.Input.Mouse
16+import Graphics.Vty.Input.Paste
1617import Graphics.Vty.Input.Classify.Types
1718
1819import Codec.Binary.UTF8.Generic (decode)
1920
20−import Data.List(inits)
21+import Data.List (inits)
2122import qualified Data.Map as M( fromList, lookup )
2223import Data.Maybe ( mapMaybe )
2324import qualified Data.Set as S( fromList, member )
@@ -56,6 +57,10 @@ classify :: ClassifyMap -> [Char] -> KClass
5657classify table =
5758 let standardClassifier = compile table
5859 in \s -> case s of
60+ _ | bracketedPasteStarted s ->
61+ if bracketedPasteFinished s
62+ then parseBracketedPaste s
63+ else Prefix
5964 _ | isMouseEvent s -> classifyMouseEvent s
6065 c:cs | ord c >= 0xC2 -> classifyUtf8 c cs
6166 _ -> standardClassifier s
src/Graphics/Vty/Input/Events.hs+6
@@ -42,6 +42,12 @@ data Event
4242 -- signal. If read from 'nextEvent' this is the size at the time the
4343 -- event was processed by Vty. Typically these are the same, but if
4444 -- somebody is resizing the terminal quickly they can be different.
45+ | EvPaste String
46+ -- ^ A paste event occurs when a bracketed paste input sequence is
47+ -- received. For terminals that support bracketed paste mode, these
48+ -- events will be triggered on a paste event. Terminals that do not
49+ -- support bracketed pastes will send the paste contents as ordinary
50+ -- input (which is probably bad, so beware!)
4551 deriving (Eq,Show,Read,Ord)
4652
4753type ClassifyMap = [(String,Event)]
src/Graphics/Vty/Input/Mouse.hs−1
@@ -13,7 +13,6 @@ import Graphics.Vty.Input.Events
1313import Graphics.Vty.Input.Classify.Types
1414import Graphics.Vty.Input.Classify.Parse
1515
16−import Control.Monad.Trans.Maybe
1716import Control.Monad.State
1817import Data.List (isPrefixOf)
1918import Data.Maybe (catMaybes)
src/Graphics/Vty/Input/Paste.hsnew file+46
@@ -0,0 +1,46 @@
1+-- | This module provides bracketed paste support as described at
2+--
3+-- http://cirw.in/blog/bracketed-paste
4+module Graphics.Vty.Input.Paste
5+ ( parseBracketedPaste
6+ , bracketedPasteStarted
7+ , bracketedPasteFinished
8+ ) where
9+
10+import Graphics.Vty.Input.Events
11+import Graphics.Vty.Input.Classify.Types
12+
13+import Data.List (isPrefixOf, isInfixOf)
14+
15+bracketedPasteStart :: String
16+bracketedPasteStart = "\ESC[200~"
17+
18+bracketedPasteEnd :: String
19+bracketedPasteEnd = "\ESC[201~"
20+
21+-- | Does the input start a bracketed paste?
22+bracketedPasteStarted :: String -> Bool
23+bracketedPasteStarted = isPrefixOf bracketedPasteStart
24+
25+-- | Does the input contain a complete bracketed paste?
26+bracketedPasteFinished :: String -> Bool
27+bracketedPasteFinished = isInfixOf bracketedPasteEnd
28+
29+-- | Parse a bracketed paste. This should only be called on a string if
30+-- both 'bracketedPasteStarted' and 'bracketedPasteFinished' return
31+-- 'True'.
32+parseBracketedPaste :: String -> KClass
33+parseBracketedPaste s =
34+ let (p, rest) = takeUntil (drop (length bracketedPasteStart) s) bracketedPasteEnd
35+ rest' = if bracketedPasteEnd `isPrefixOf` rest
36+ then drop (length bracketedPasteEnd) rest
37+ else rest
38+ in Valid (EvPaste p) rest'
39+
40+takeUntil :: (Eq a) => [a] -> [a] -> ([a],[a])
41+takeUntil [] _ = ([], [])
42+takeUntil cs sub
43+ | length cs < length sub = (cs, [])
44+ | take (length sub) cs == sub = ([], drop (length sub) cs)
45+ | otherwise = let (pre, suf) = takeUntil (tail cs) sub
46+ in (head cs:pre, suf)
src/Graphics/Vty/Output/XTermColor.hs+11
@@ -34,12 +34,14 @@ reserveTerminal variant outFd = liftIO $ do
3434 -- xterm-color is broken.
3535 let variant' = if variant == "xterm-color" then "xterm" else variant
3636 flushedPut setUtf8CharSet
37+ flushedPut enableBracketedPastes
3738 flushedPut requestMouseEvents
3839 t <- TerminfoBased.reserveTerminal variant' outFd
3940 let t' = t
4041 { terminalID = terminalID t ++ " (xterm-color)"
4142 , releaseTerminal = do
4243 liftIO $ flushedPut setDefaultCharSet
44+ liftIO $ flushedPut disableBracketedPastes
4345 liftIO $ flushedPut disableMouseEvents
4446 releaseTerminal t
4547 , mkDisplayContext = \tActual r -> do
@@ -48,6 +50,15 @@ reserveTerminal variant outFd = liftIO $ do
4850 }
4951 return t'
5052
53+-- | Enable bracketed paste mode:
54+-- http://cirw.in/blog/bracketed-paste
55+enableBracketedPastes :: String
56+enableBracketedPastes = "\ESC[?2004h"
57+
58+-- | Disable bracketed paste mode:
59+disableBracketedPastes :: String
60+disableBracketedPastes = "\ESC[?2004l"
61+
5162-- | These sequences set xterm based terminals to UTF-8 output.
5263--
5364-- \todo I don't know of a terminfo cap that is equivalent to this.
vty.cabal+1
@@ -98,6 +98,7 @@ library
9898 Graphics.Vty.Input.Classify.Parse
9999 Graphics.Vty.Input.Loop
100100 Graphics.Vty.Input.Mouse
101+ Graphics.Vty.Input.Paste
101102 Graphics.Vty.Input.Terminfo
102103 Graphics.Vty.PictureToSpans
103104 Graphics.Vty.Span