diff --git a/ghc-7.10.3.orig/libraries/haskeline/Changelog b/ghc-7.10.3/libraries/haskeline/Changelog index 5cb7cc5..7b1f5e2 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/Changelog +++ b/ghc-7.10.3/libraries/haskeline/Changelog @@ -1,3 +1,15 @@ +Changed in version 0.7.2.3: + * Fix hsc2hs-related warning on ghc-8 + * Fix the behavior of ctrl-W in the emacs bindings + * Point to github instead of trac + +Changed in version 0.7.2.2: + * Fix Linux to Windows cross-compile + * Canonicalize AMP instances to make the code more future proof + * Generalize constraints for InputT instances + * Bump upper bounds on base and transformers + * Make Haskeline `-Wtabs` clean + Changed in version 0.7.2.1: * Fix build on Windows. diff --git a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Backend/Win32.hsc b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Backend/Win32.hsc index 61c9ab2..d9c0934 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Backend/Win32.hsc +++ b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Backend/Win32.hsc @@ -1,546 +1,548 @@ -module System.Console.Haskeline.Backend.Win32( - win32Term, - win32TermStdin, - fileRunTerm - )where - - -import System.IO -import Foreign -import Foreign.C -import System.Win32 hiding (multiByteToWideChar) -import Graphics.Win32.Misc(getStdHandle, sTD_OUTPUT_HANDLE) -import Data.List(intercalate) -import Control.Concurrent hiding (throwTo) -import Data.Char(isPrint) -import Data.Maybe(mapMaybe) -import Control.Applicative -import Control.Monad - -import System.Console.Haskeline.Key -import System.Console.Haskeline.Monads hiding (Handler) -import System.Console.Haskeline.LineState -import System.Console.Haskeline.Term -import System.Console.Haskeline.Backend.WCWidth - -import Data.ByteString.Internal (createAndTrim) -import qualified Data.ByteString as B - -##if defined(i386_HOST_ARCH) -## define WINDOWS_CCONV stdcall -##elif defined(x86_64_HOST_ARCH) -## define WINDOWS_CCONV ccall -##else -## error Unknown mingw32 arch -##endif - -#include "win_console.h" - -foreign import WINDOWS_CCONV "windows.h ReadConsoleInputW" c_ReadConsoleInput - :: HANDLE -> Ptr () -> DWORD -> Ptr DWORD -> IO Bool - -foreign import WINDOWS_CCONV "windows.h WaitForSingleObject" c_WaitForSingleObject - :: HANDLE -> DWORD -> IO DWORD - -foreign import WINDOWS_CCONV "windows.h GetNumberOfConsoleInputEvents" - c_GetNumberOfConsoleInputEvents :: HANDLE -> Ptr DWORD -> IO Bool - -getNumberOfEvents :: HANDLE -> IO Int -getNumberOfEvents h = alloca $ \numEventsPtr -> do - failIfFalse_ "GetNumberOfConsoleInputEvents" - $ c_GetNumberOfConsoleInputEvents h numEventsPtr - fmap fromEnum $ peek numEventsPtr - -getEvent :: HANDLE -> Chan Event -> IO Event -getEvent h = keyEventLoop (eventReader h) - -eventReader :: HANDLE -> IO [Event] -eventReader h = do - let waitTime = 500 -- milliseconds - ret <- c_WaitForSingleObject h waitTime - yield -- otherwise, the above foreign call causes the loop to never - -- respond to the killThread - if ret /= (#const WAIT_OBJECT_0) - then eventReader h - else do - es <- readEvents h - return $ mapMaybe processEvent es - -consoleHandles :: MaybeT IO Handles -consoleHandles = do - h_in <- open "CONIN$" - h_out <- open "CONOUT$" - return Handles { hIn = h_in, hOut = h_out } - where - open file = handle (\(_::IOException) -> mzero) $ liftIO - $ createFile file (gENERIC_READ .|. gENERIC_WRITE) - (fILE_SHARE_READ .|. fILE_SHARE_WRITE) Nothing - oPEN_EXISTING 0 Nothing - - -processEvent :: InputEvent -> Maybe Event -processEvent KeyEvent {keyDown = True, unicodeChar = c, virtualKeyCode = vc, - controlKeyState = cstate} - = fmap (\e -> KeyInput [Key modifier' e]) $ keyFromCode vc `mplus` simpleKeyChar - where - simpleKeyChar = guard (c /= '\NUL') >> return (KeyChar c) - testMod ck = (cstate .&. ck) /= 0 - modifier' = if hasMeta modifier && hasControl modifier - then noModifier {hasShift = hasShift modifier} - else modifier - modifier = Modifier {hasMeta = testMod ((#const RIGHT_ALT_PRESSED) - .|. (#const LEFT_ALT_PRESSED)) - ,hasControl = testMod ((#const RIGHT_CTRL_PRESSED) - .|. (#const LEFT_CTRL_PRESSED)) - && not (c > '\NUL' && c <= '\031') - ,hasShift = testMod (#const SHIFT_PRESSED) - && not (isPrint c) - } - -processEvent WindowEvent = Just WindowResize -processEvent _ = Nothing - -keyFromCode :: WORD -> Maybe BaseKey -keyFromCode (#const VK_BACK) = Just Backspace -keyFromCode (#const VK_LEFT) = Just LeftKey -keyFromCode (#const VK_RIGHT) = Just RightKey -keyFromCode (#const VK_UP) = Just UpKey -keyFromCode (#const VK_DOWN) = Just DownKey -keyFromCode (#const VK_DELETE) = Just Delete -keyFromCode (#const VK_HOME) = Just Home -keyFromCode (#const VK_END) = Just End -keyFromCode (#const VK_PRIOR) = Just PageUp -keyFromCode (#const VK_NEXT) = Just PageDown --- The Windows console will return '\r' when return is pressed. -keyFromCode (#const VK_RETURN) = Just (KeyChar '\n') --- TODO: KillLine? --- TODO: function keys. -keyFromCode _ = Nothing - -data InputEvent = KeyEvent {keyDown :: BOOL, - repeatCount :: WORD, - virtualKeyCode :: WORD, - virtualScanCode :: WORD, - unicodeChar :: Char, - controlKeyState :: DWORD} - -- TODO: WINDOW_BUFFER_SIZE_RECORD - -- I cant figure out how the user generates them. - | WindowEvent - | OtherEvent - deriving Show - -peekEvent :: Ptr () -> IO InputEvent -peekEvent pRecord = do - eventType :: WORD <- (#peek INPUT_RECORD, EventType) pRecord - let eventPtr = (#ptr INPUT_RECORD, Event) pRecord - case eventType of - (#const KEY_EVENT) -> getKeyEvent eventPtr - (#const WINDOW_BUFFER_SIZE_EVENT) -> return WindowEvent - _ -> return OtherEvent - -readEvents :: HANDLE -> IO [InputEvent] -readEvents h = do - n <- getNumberOfEvents h - alloca $ \numEventsPtr -> - allocaBytes (n * #size INPUT_RECORD) $ \pRecord -> do - failIfFalse_ "ReadConsoleInput" - $ c_ReadConsoleInput h pRecord (toEnum n) numEventsPtr - numRead <- fmap fromEnum $ peek numEventsPtr - forM [0..toEnum numRead-1] $ \i -> peekEvent - $ pRecord `plusPtr` (i * #size INPUT_RECORD) - -getKeyEvent :: Ptr () -> IO InputEvent -getKeyEvent p = do - kDown' <- (#peek KEY_EVENT_RECORD, bKeyDown) p - repeat' <- (#peek KEY_EVENT_RECORD, wRepeatCount) p - keyCode <- (#peek KEY_EVENT_RECORD, wVirtualKeyCode) p - scanCode <- (#peek KEY_EVENT_RECORD, wVirtualScanCode) p - char :: CWchar <- (#peek KEY_EVENT_RECORD, uChar) p - state <- (#peek KEY_EVENT_RECORD, dwControlKeyState) p - return KeyEvent {keyDown = kDown', - repeatCount = repeat', - virtualKeyCode = keyCode, - virtualScanCode = scanCode, - unicodeChar = toEnum (fromEnum char), - controlKeyState = state} - -data Coord = Coord {coordX, coordY :: Int} - deriving Show - -#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__) -instance Storable Coord where - sizeOf _ = (#size COORD) - alignment _ = (#alignment COORD) - peek p = do - x :: CShort <- (#peek COORD, X) p - y :: CShort <- (#peek COORD, Y) p - return Coord {coordX = fromEnum x, coordY = fromEnum y} - poke p c = do - (#poke COORD, X) p (toEnum (coordX c) :: CShort) - (#poke COORD, Y) p (toEnum (coordY c) :: CShort) - - -foreign import ccall "haskeline_SetPosition" - c_SetPosition :: HANDLE -> Ptr Coord -> IO Bool - -setPosition :: HANDLE -> Coord -> IO () -setPosition h c = with c $ failIfFalse_ "SetConsoleCursorPosition" - . c_SetPosition h - -foreign import WINDOWS_CCONV "windows.h GetConsoleScreenBufferInfo" - c_GetScreenBufferInfo :: HANDLE -> Ptr () -> IO Bool - -getPosition :: HANDLE -> IO Coord -getPosition = withScreenBufferInfo $ - (#peek CONSOLE_SCREEN_BUFFER_INFO, dwCursorPosition) - -withScreenBufferInfo :: (Ptr () -> IO a) -> HANDLE -> IO a -withScreenBufferInfo f h = allocaBytes (#size CONSOLE_SCREEN_BUFFER_INFO) - $ \infoPtr -> do - failIfFalse_ "GetConsoleScreenBufferInfo" - $ c_GetScreenBufferInfo h infoPtr - f infoPtr - -getBufferSize :: HANDLE -> IO Layout -getBufferSize = withScreenBufferInfo $ \p -> do - c <- (#peek CONSOLE_SCREEN_BUFFER_INFO, dwSize) p - return Layout {width = coordX c, height = coordY c} - -foreign import WINDOWS_CCONV "windows.h WriteConsoleW" c_WriteConsoleW - :: HANDLE -> Ptr TCHAR -> DWORD -> Ptr DWORD -> Ptr () -> IO Bool - -writeConsole :: HANDLE -> String -> IO () --- For some reason, Wine returns False when WriteConsoleW is called on an empty --- string. Easiest fix: just don't call that function. -writeConsole _ "" = return () -writeConsole h str = writeConsole' >> writeConsole h ys - where - (xs,ys) = splitAt limit str - -- WriteConsoleW has a buffer limit which is documented as 32768 word8's, - -- but bug reports from online suggest that the limit may be lower (~25000). - -- To be safe, we pick a round number we know to be less than the limit. - limit = 20000 -- known to be less than WriteConsoleW's buffer limit - writeConsole' - = withArray (map (toEnum . fromEnum) xs) - $ \t_arr -> alloca $ \numWritten -> do - failIfFalse_ "WriteConsoleW" - $ c_WriteConsoleW h t_arr (toEnum $ length xs) - numWritten nullPtr - -foreign import WINDOWS_CCONV "windows.h MessageBeep" c_messageBeep :: UINT -> IO Bool - -messageBeep :: IO () -messageBeep = c_messageBeep (-1) >> return ()-- intentionally ignore failures. - - ----------- --- Console mode -foreign import WINDOWS_CCONV "windows.h GetConsoleMode" c_GetConsoleMode - :: HANDLE -> Ptr DWORD -> IO Bool - -foreign import WINDOWS_CCONV "windows.h SetConsoleMode" c_SetConsoleMode - :: HANDLE -> DWORD -> IO Bool - -withWindowMode :: MonadException m => Handles -> m a -> m a -withWindowMode hs f = do - let h = hIn hs - bracket (getConsoleMode h) (setConsoleMode h) - $ \m -> setConsoleMode h (m .|. (#const ENABLE_WINDOW_INPUT)) >> f - where - getConsoleMode h = liftIO $ alloca $ \p -> do - failIfFalse_ "GetConsoleMode" $ c_GetConsoleMode h p - peek p - setConsoleMode h m = liftIO $ failIfFalse_ "SetConsoleMode" $ c_SetConsoleMode h m - ----------------------------- --- Drawing - -data Handles = Handles { hIn, hOut :: HANDLE } - -closeHandles :: Handles -> IO () -closeHandles hs = closeHandle (hIn hs) >> closeHandle (hOut hs) - -newtype Draw m a = Draw {runDraw :: ReaderT Handles m a} - deriving (Functor, Applicative, Monad, MonadIO, MonadException, MonadReader Handles) - -type DrawM a = forall m . (MonadIO m, MonadReader Layout m) => Draw m a - -instance MonadTrans Draw where - lift = Draw . lift - -getPos :: MonadIO m => Draw m Coord -getPos = asks hOut >>= liftIO . getPosition - -setPos :: Coord -> DrawM () -setPos c = do - h <- asks hOut - -- SetPosition will fail if you give it something out of bounds of - -- the window buffer (i.e., the input line doesn't fit in the window). - -- So we do a simple guard against that uncommon case. - -- However, we don't throw away the x coord since it produces sensible - -- results for some cases. - maxY <- liftM (subtract 1) $ asks height - liftIO $ setPosition h c { coordY = max 0 $ min maxY $ coordY c } - -printText :: MonadIO m => String -> Draw m () -printText txt = do - h <- asks hOut - liftIO (writeConsole h txt) - -printAfter :: [Grapheme] -> DrawM () -printAfter gs = do - -- NOTE: you may be tempted to write - -- do {p <- getPos; printText (...); setPos p} - -- Unfortunately, that would be WRONG, because if printText wraps - -- a line at the bottom of the window, causing the window to scroll, - -- then the old value of p will be incorrect. - printText (graphemesToString gs) - movePosLeft gs - -drawLineDiffWin :: LineChars -> LineChars -> DrawM () -drawLineDiffWin (xs1,ys1) (xs2,ys2) = case matchInit xs1 xs2 of - ([],[]) | ys1 == ys2 -> return () - (xs1',[]) | xs1' ++ ys1 == ys2 -> movePosLeft xs1' - ([],xs2') | ys1 == xs2' ++ ys2 -> movePosRight xs2' - (xs1',xs2') -> do - movePosLeft xs1' - let m = gsWidth xs1' + gsWidth ys1 - (gsWidth xs2' + gsWidth ys2) - let deadText = stringToGraphemes $ replicate m ' ' - printText (graphemesToString xs2') - printAfter (ys2 ++ deadText) - -movePosRight, movePosLeft :: [Grapheme] -> DrawM () -movePosRight str = do - p <- getPos - w <- asks width - setPos $ moveCoord w p str - where - moveCoord _ p [] = p - moveCoord w p cs = case splitAtWidth (w - coordX p) cs of - (_,[],len) | len < w - coordX p -- stayed on same line - -> Coord { coordY = coordY p, - coordX = coordX p + len - } - (_,cs',_) -- moved to next line - -> moveCoord w Coord { - coordY = coordY p + 1, - coordX = 0 - } cs' - -movePosLeft str = do - p <- getPos - w <- asks width - setPos $ moveCoord w p str - where - moveCoord _ p [] = p - moveCoord w p cs = case splitAtWidth (coordX p) cs of - (_,[],len) -- stayed on same line - -> Coord { coordY = coordY p, - coordX = coordX p - len - } - (_,_:cs',_) -- moved to previous line - -> moveCoord w Coord { - coordY = coordY p - 1, - coordX = w-1 - } cs' - -crlf :: String -crlf = "\r\n" - -instance (MonadException m, MonadReader Layout m) => Term (Draw m) where - drawLineDiff (xs1,ys1) (xs2,ys2) = let - fixEsc = filter ((/= '\ESC') . baseChar) - in drawLineDiffWin (fixEsc xs1, fixEsc ys1) (fixEsc xs2, fixEsc ys2) - -- TODO now that we capture resize events. - -- first, looks like the cursor stays on the same line but jumps - -- to the beginning if cut off. - reposition _ _ = return () - - printLines [] = return () - printLines ls = printText $ intercalate crlf ls ++ crlf - - clearLayout = clearScreen - - moveToNextLine s = do - movePosRight (snd s) - printText "\r\n" -- make the console take care of creating a new line - - ringBell True = liftIO messageBeep - ringBell False = return () -- TODO - -win32TermStdin :: MaybeT IO RunTerm -win32TermStdin = do - liftIO (hIsTerminalDevice stdin) >>= guard - win32Term - -win32Term :: MaybeT IO RunTerm -win32Term = do - hs <- consoleHandles - ch <- liftIO newChan - fileRT <- liftIO $ fileRunTerm stdin - return fileRT { - termOps = Left TermOps { - getLayout = getBufferSize (hOut hs) - , withGetEvent = withWindowMode hs - . win32WithEvent hs ch - , saveUnusedKeys = saveKeys ch - , evalTerm = EvalTerm (runReaderT' hs . runDraw) - (Draw . lift) - }, - closeTerm = closeHandles hs - } - -win32WithEvent :: MonadException m => Handles -> Chan Event - -> (m Event -> m a) -> m a -win32WithEvent h eventChan f = f $ liftIO $ getEvent (hIn h) eventChan - --- stdin is not a terminal, but we still need to check the right way to output unicode to stdout. -fileRunTerm :: Handle -> IO RunTerm -fileRunTerm h_in = do - putter <- putOut - cp <- getCodePage - return RunTerm { - closeTerm = return (), - putStrOut = putter, - wrapInterrupt = withCtrlCHandler, - termOps = Right FileOps - { inputHandle = h_in - , wrapFileInput = hWithBinaryMode h_in - , getLocaleChar = getMultiByteChar cp h_in - , maybeReadNewline = hMaybeReadNewline h_in - , getLocaleLine = hGetLocaleLine h_in - >>= liftIO . codePageToUnicode cp - } - - } - --- On Windows, Unicode written to the console must be written with the WriteConsole API call. --- And to make the API cross-platform consistent, Unicode to a file should be UTF-8. -putOut :: IO (String -> IO ()) -putOut = do - outIsTerm <- hIsTerminalDevice stdout - if outIsTerm - then do - h <- getStdHandle sTD_OUTPUT_HANDLE - return (writeConsole h) - else do - cp <- getCodePage - return $ \str -> unicodeToCodePage cp str >>= B.putStr >> hFlush stdout - - -type Handler = DWORD -> IO BOOL - -foreign import ccall "wrapper" wrapHandler :: Handler -> IO (FunPtr Handler) - -foreign import WINDOWS_CCONV "windows.h SetConsoleCtrlHandler" c_SetConsoleCtrlHandler - :: FunPtr Handler -> BOOL -> IO BOOL - --- sets the tv to True when ctrl-c is pressed. -withCtrlCHandler :: MonadException m => m a -> m a -withCtrlCHandler f = bracket (liftIO $ do - tid <- myThreadId - fp <- wrapHandler (handler tid) - -- don't fail if we can't set the ctrl-c handler - -- for example, we might not be attached to a console? - _ <- c_SetConsoleCtrlHandler fp True - return fp) - (\fp -> liftIO $ c_SetConsoleCtrlHandler fp False) - (const f) - where - handler tid (#const CTRL_C_EVENT) = do - throwTo tid Interrupt - return True - handler _ _ = return False - - - ------------------------- --- Multi-byte conversion - -foreign import WINDOWS_CCONV "WideCharToMultiByte" wideCharToMultiByte - :: CodePage -> DWORD -> LPCWSTR -> CInt -> LPCSTR -> CInt - -> LPCSTR -> LPBOOL -> IO CInt - -unicodeToCodePage :: CodePage -> String -> IO B.ByteString -unicodeToCodePage cp wideStr = withCWStringLen wideStr $ \(wideBuff, wideLen) -> do - -- first, ask for the length without filling the buffer. - outSize <- wideCharToMultiByte cp 0 wideBuff (toEnum wideLen) - nullPtr 0 nullPtr nullPtr - -- then, actually perform the encoding. - createAndTrim (fromEnum outSize) $ \outBuff -> - fmap fromEnum $ wideCharToMultiByte cp 0 wideBuff (toEnum wideLen) - (castPtr outBuff) outSize nullPtr nullPtr - -foreign import WINDOWS_CCONV "MultiByteToWideChar" multiByteToWideChar - :: CodePage -> DWORD -> LPCSTR -> CInt -> LPWSTR -> CInt -> IO CInt - -codePageToUnicode :: CodePage -> B.ByteString -> IO String -codePageToUnicode cp bs = B.useAsCStringLen bs $ \(inBuff, inLen) -> do - -- first ask for the size without filling the buffer. - outSize <- multiByteToWideChar cp 0 inBuff (toEnum inLen) nullPtr 0 - -- then, actually perform the decoding. - allocaArray0 (fromEnum outSize) $ \outBuff -> do - outSize' <- multiByteToWideChar cp 0 inBuff (toEnum inLen) outBuff outSize - peekCWStringLen (outBuff, fromEnum outSize') - - -getCodePage :: IO CodePage -getCodePage = do - conCP <- getConsoleCP - if conCP > 0 - then return conCP - else getACP - -foreign import WINDOWS_CCONV "IsDBCSLeadByteEx" c_IsDBCSLeadByteEx - :: CodePage -> BYTE -> BOOL - -getMultiByteChar :: CodePage -> Handle -> MaybeT IO Char -getMultiByteChar cp h = do - b1 <- hGetByte h - bs <- if c_IsDBCSLeadByteEx cp b1 - then hGetByte h >>= \b2 -> return [b1,b2] - else return [b1] - cs <- liftIO $ codePageToUnicode cp (B.pack bs) - case cs of - [] -> getMultiByteChar cp h - (c:_) -> return c - ----------------------------------- --- Clearing screen --- WriteConsole has a limit of ~20,000-30000 characters, which is --- less than a 200x200 window, for example. --- So we'll use other Win32 functions to clear the screen. - -getAttribute :: HANDLE -> IO WORD -getAttribute = withScreenBufferInfo $ - (#peek CONSOLE_SCREEN_BUFFER_INFO, wAttributes) - -fillConsoleChar :: HANDLE -> Char -> Int -> Coord -> IO () -fillConsoleChar h c n start = with start $ \startPtr -> alloca $ \numWritten -> do - failIfFalse_ "FillConsoleOutputCharacter" - $ c_FillConsoleCharacter h (toEnum $ fromEnum c) - (toEnum n) startPtr numWritten - -foreign import ccall "haskeline_FillConsoleCharacter" c_FillConsoleCharacter - :: HANDLE -> TCHAR -> DWORD -> Ptr Coord -> Ptr DWORD -> IO BOOL - -fillConsoleAttribute :: HANDLE -> WORD -> Int -> Coord -> IO () -fillConsoleAttribute h a n start = with start $ \startPtr -> alloca $ \numWritten -> do - failIfFalse_ "FillConsoleOutputAttribute" - $ c_FillConsoleAttribute h a - (toEnum n) startPtr numWritten - -foreign import ccall "haskeline_FillConsoleAttribute" c_FillConsoleAttribute - :: HANDLE -> WORD -> DWORD -> Ptr Coord -> Ptr DWORD -> IO BOOL - -clearScreen :: DrawM () -clearScreen = do - lay <- ask - h <- asks hOut - let windowSize = width lay * height lay - let origin = Coord 0 0 - attr <- liftIO $ getAttribute h - liftIO $ fillConsoleChar h ' ' windowSize origin - liftIO $ fillConsoleAttribute h attr windowSize origin - setPos origin - +module System.Console.Haskeline.Backend.Win32( + win32Term, + win32TermStdin, + fileRunTerm + )where + + +import System.IO +import Foreign +import Foreign.C +import System.Win32 hiding (multiByteToWideChar) +import Graphics.Win32.Misc(getStdHandle, sTD_OUTPUT_HANDLE) +import Data.List(intercalate) +import Control.Concurrent hiding (throwTo) +import Data.Char(isPrint) +import Data.Maybe(mapMaybe) +import Control.Applicative +import Control.Monad + +import System.Console.Haskeline.Key +import System.Console.Haskeline.Monads hiding (Handler) +import System.Console.Haskeline.LineState +import System.Console.Haskeline.Term +import System.Console.Haskeline.Backend.WCWidth + +import Data.ByteString.Internal (createAndTrim) +import qualified Data.ByteString as B + +##if defined(i386_HOST_ARCH) +## define WINDOWS_CCONV stdcall +##elif defined(x86_64_HOST_ARCH) +## define WINDOWS_CCONV ccall +##else +## error Unknown mingw32 arch +##endif + +#include "win_console.h" + +foreign import WINDOWS_CCONV "windows.h ReadConsoleInputW" c_ReadConsoleInput + :: HANDLE -> Ptr () -> DWORD -> Ptr DWORD -> IO Bool + +foreign import WINDOWS_CCONV "windows.h WaitForSingleObject" c_WaitForSingleObject + :: HANDLE -> DWORD -> IO DWORD + +foreign import WINDOWS_CCONV "windows.h GetNumberOfConsoleInputEvents" + c_GetNumberOfConsoleInputEvents :: HANDLE -> Ptr DWORD -> IO Bool + +getNumberOfEvents :: HANDLE -> IO Int +getNumberOfEvents h = alloca $ \numEventsPtr -> do + failIfFalse_ "GetNumberOfConsoleInputEvents" + $ c_GetNumberOfConsoleInputEvents h numEventsPtr + fmap fromEnum $ peek numEventsPtr + +getEvent :: HANDLE -> Chan Event -> IO Event +getEvent h = keyEventLoop (eventReader h) + +eventReader :: HANDLE -> IO [Event] +eventReader h = do + let waitTime = 500 -- milliseconds + ret <- c_WaitForSingleObject h waitTime + yield -- otherwise, the above foreign call causes the loop to never + -- respond to the killThread + if ret /= (#const WAIT_OBJECT_0) + then eventReader h + else do + es <- readEvents h + return $ mapMaybe processEvent es + +consoleHandles :: MaybeT IO Handles +consoleHandles = do + h_in <- open "CONIN$" + h_out <- open "CONOUT$" + return Handles { hIn = h_in, hOut = h_out } + where + open file = handle (\(_::IOException) -> mzero) $ liftIO + $ createFile file (gENERIC_READ .|. gENERIC_WRITE) + (fILE_SHARE_READ .|. fILE_SHARE_WRITE) Nothing + oPEN_EXISTING 0 Nothing + + +processEvent :: InputEvent -> Maybe Event +processEvent KeyEvent {keyDown = True, unicodeChar = c, virtualKeyCode = vc, + controlKeyState = cstate} + = fmap (\e -> KeyInput [Key modifier' e]) $ keyFromCode vc `mplus` simpleKeyChar + where + simpleKeyChar = guard (c /= '\NUL') >> return (KeyChar c) + testMod ck = (cstate .&. ck) /= 0 + modifier' = if hasMeta modifier && hasControl modifier + then noModifier {hasShift = hasShift modifier} + else modifier + modifier = Modifier {hasMeta = testMod ((#const RIGHT_ALT_PRESSED) + .|. (#const LEFT_ALT_PRESSED)) + ,hasControl = testMod ((#const RIGHT_CTRL_PRESSED) + .|. (#const LEFT_CTRL_PRESSED)) + && not (c > '\NUL' && c <= '\031') + ,hasShift = testMod (#const SHIFT_PRESSED) + && not (isPrint c) + } + +processEvent WindowEvent = Just WindowResize +processEvent _ = Nothing + +keyFromCode :: WORD -> Maybe BaseKey +keyFromCode (#const VK_BACK) = Just Backspace +keyFromCode (#const VK_LEFT) = Just LeftKey +keyFromCode (#const VK_RIGHT) = Just RightKey +keyFromCode (#const VK_UP) = Just UpKey +keyFromCode (#const VK_DOWN) = Just DownKey +keyFromCode (#const VK_DELETE) = Just Delete +keyFromCode (#const VK_HOME) = Just Home +keyFromCode (#const VK_END) = Just End +keyFromCode (#const VK_PRIOR) = Just PageUp +keyFromCode (#const VK_NEXT) = Just PageDown +-- The Windows console will return '\r' when return is pressed. +keyFromCode (#const VK_RETURN) = Just (KeyChar '\n') +-- TODO: KillLine? +-- TODO: function keys. +keyFromCode _ = Nothing + +data InputEvent = KeyEvent {keyDown :: BOOL, + repeatCount :: WORD, + virtualKeyCode :: WORD, + virtualScanCode :: WORD, + unicodeChar :: Char, + controlKeyState :: DWORD} + -- TODO: WINDOW_BUFFER_SIZE_RECORD + -- I cant figure out how the user generates them. + | WindowEvent + | OtherEvent + deriving Show + +peekEvent :: Ptr () -> IO InputEvent +peekEvent pRecord = do + eventType :: WORD <- (#peek INPUT_RECORD, EventType) pRecord + let eventPtr = (#ptr INPUT_RECORD, Event) pRecord + case eventType of + (#const KEY_EVENT) -> getKeyEvent eventPtr + (#const WINDOW_BUFFER_SIZE_EVENT) -> return WindowEvent + _ -> return OtherEvent + +readEvents :: HANDLE -> IO [InputEvent] +readEvents h = do + n <- getNumberOfEvents h + alloca $ \numEventsPtr -> + allocaBytes (n * #size INPUT_RECORD) $ \pRecord -> do + failIfFalse_ "ReadConsoleInput" + $ c_ReadConsoleInput h pRecord (toEnum n) numEventsPtr + numRead <- fmap fromEnum $ peek numEventsPtr + forM [0..toEnum numRead-1] $ \i -> peekEvent + $ pRecord `plusPtr` (i * #size INPUT_RECORD) + +getKeyEvent :: Ptr () -> IO InputEvent +getKeyEvent p = do + kDown' <- (#peek KEY_EVENT_RECORD, bKeyDown) p + repeat' <- (#peek KEY_EVENT_RECORD, wRepeatCount) p + keyCode <- (#peek KEY_EVENT_RECORD, wVirtualKeyCode) p + scanCode <- (#peek KEY_EVENT_RECORD, wVirtualScanCode) p + char :: CWchar <- (#peek KEY_EVENT_RECORD, uChar) p + state <- (#peek KEY_EVENT_RECORD, dwControlKeyState) p + return KeyEvent {keyDown = kDown', + repeatCount = repeat', + virtualKeyCode = keyCode, + virtualScanCode = scanCode, + unicodeChar = toEnum (fromEnum char), + controlKeyState = state} + +data Coord = Coord {coordX, coordY :: Int} + deriving Show + +#if __GLASGOW_HASKELL__ < 711 +#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__) +#endif +instance Storable Coord where + sizeOf _ = (#size COORD) + alignment _ = (#alignment COORD) + peek p = do + x :: CShort <- (#peek COORD, X) p + y :: CShort <- (#peek COORD, Y) p + return Coord {coordX = fromEnum x, coordY = fromEnum y} + poke p c = do + (#poke COORD, X) p (toEnum (coordX c) :: CShort) + (#poke COORD, Y) p (toEnum (coordY c) :: CShort) + + +foreign import ccall "haskeline_SetPosition" + c_SetPosition :: HANDLE -> Ptr Coord -> IO Bool + +setPosition :: HANDLE -> Coord -> IO () +setPosition h c = with c $ failIfFalse_ "SetConsoleCursorPosition" + . c_SetPosition h + +foreign import WINDOWS_CCONV "windows.h GetConsoleScreenBufferInfo" + c_GetScreenBufferInfo :: HANDLE -> Ptr () -> IO Bool + +getPosition :: HANDLE -> IO Coord +getPosition = withScreenBufferInfo $ + (#peek CONSOLE_SCREEN_BUFFER_INFO, dwCursorPosition) + +withScreenBufferInfo :: (Ptr () -> IO a) -> HANDLE -> IO a +withScreenBufferInfo f h = allocaBytes (#size CONSOLE_SCREEN_BUFFER_INFO) + $ \infoPtr -> do + failIfFalse_ "GetConsoleScreenBufferInfo" + $ c_GetScreenBufferInfo h infoPtr + f infoPtr + +getBufferSize :: HANDLE -> IO Layout +getBufferSize = withScreenBufferInfo $ \p -> do + c <- (#peek CONSOLE_SCREEN_BUFFER_INFO, dwSize) p + return Layout {width = coordX c, height = coordY c} + +foreign import WINDOWS_CCONV "windows.h WriteConsoleW" c_WriteConsoleW + :: HANDLE -> Ptr TCHAR -> DWORD -> Ptr DWORD -> Ptr () -> IO Bool + +writeConsole :: HANDLE -> String -> IO () +-- For some reason, Wine returns False when WriteConsoleW is called on an empty +-- string. Easiest fix: just don't call that function. +writeConsole _ "" = return () +writeConsole h str = writeConsole' >> writeConsole h ys + where + (xs,ys) = splitAt limit str + -- WriteConsoleW has a buffer limit which is documented as 32768 word8's, + -- but bug reports from online suggest that the limit may be lower (~25000). + -- To be safe, we pick a round number we know to be less than the limit. + limit = 20000 -- known to be less than WriteConsoleW's buffer limit + writeConsole' + = withArray (map (toEnum . fromEnum) xs) + $ \t_arr -> alloca $ \numWritten -> do + failIfFalse_ "WriteConsoleW" + $ c_WriteConsoleW h t_arr (toEnum $ length xs) + numWritten nullPtr + +foreign import WINDOWS_CCONV "windows.h MessageBeep" c_messageBeep :: UINT -> IO Bool + +messageBeep :: IO () +messageBeep = c_messageBeep (-1) >> return ()-- intentionally ignore failures. + + +---------- +-- Console mode +foreign import WINDOWS_CCONV "windows.h GetConsoleMode" c_GetConsoleMode + :: HANDLE -> Ptr DWORD -> IO Bool + +foreign import WINDOWS_CCONV "windows.h SetConsoleMode" c_SetConsoleMode + :: HANDLE -> DWORD -> IO Bool + +withWindowMode :: MonadException m => Handles -> m a -> m a +withWindowMode hs f = do + let h = hIn hs + bracket (getConsoleMode h) (setConsoleMode h) + $ \m -> setConsoleMode h (m .|. (#const ENABLE_WINDOW_INPUT)) >> f + where + getConsoleMode h = liftIO $ alloca $ \p -> do + failIfFalse_ "GetConsoleMode" $ c_GetConsoleMode h p + peek p + setConsoleMode h m = liftIO $ failIfFalse_ "SetConsoleMode" $ c_SetConsoleMode h m + +---------------------------- +-- Drawing + +data Handles = Handles { hIn, hOut :: HANDLE } + +closeHandles :: Handles -> IO () +closeHandles hs = closeHandle (hIn hs) >> closeHandle (hOut hs) + +newtype Draw m a = Draw {runDraw :: ReaderT Handles m a} + deriving (Functor, Applicative, Monad, MonadIO, MonadException, MonadReader Handles) + +type DrawM a = forall m . (MonadIO m, MonadReader Layout m) => Draw m a + +instance MonadTrans Draw where + lift = Draw . lift + +getPos :: MonadIO m => Draw m Coord +getPos = asks hOut >>= liftIO . getPosition + +setPos :: Coord -> DrawM () +setPos c = do + h <- asks hOut + -- SetPosition will fail if you give it something out of bounds of + -- the window buffer (i.e., the input line doesn't fit in the window). + -- So we do a simple guard against that uncommon case. + -- However, we don't throw away the x coord since it produces sensible + -- results for some cases. + maxY <- liftM (subtract 1) $ asks height + liftIO $ setPosition h c { coordY = max 0 $ min maxY $ coordY c } + +printText :: MonadIO m => String -> Draw m () +printText txt = do + h <- asks hOut + liftIO (writeConsole h txt) + +printAfter :: [Grapheme] -> DrawM () +printAfter gs = do + -- NOTE: you may be tempted to write + -- do {p <- getPos; printText (...); setPos p} + -- Unfortunately, that would be WRONG, because if printText wraps + -- a line at the bottom of the window, causing the window to scroll, + -- then the old value of p will be incorrect. + printText (graphemesToString gs) + movePosLeft gs + +drawLineDiffWin :: LineChars -> LineChars -> DrawM () +drawLineDiffWin (xs1,ys1) (xs2,ys2) = case matchInit xs1 xs2 of + ([],[]) | ys1 == ys2 -> return () + (xs1',[]) | xs1' ++ ys1 == ys2 -> movePosLeft xs1' + ([],xs2') | ys1 == xs2' ++ ys2 -> movePosRight xs2' + (xs1',xs2') -> do + movePosLeft xs1' + let m = gsWidth xs1' + gsWidth ys1 - (gsWidth xs2' + gsWidth ys2) + let deadText = stringToGraphemes $ replicate m ' ' + printText (graphemesToString xs2') + printAfter (ys2 ++ deadText) + +movePosRight, movePosLeft :: [Grapheme] -> DrawM () +movePosRight str = do + p <- getPos + w <- asks width + setPos $ moveCoord w p str + where + moveCoord _ p [] = p + moveCoord w p cs = case splitAtWidth (w - coordX p) cs of + (_,[],len) | len < w - coordX p -- stayed on same line + -> Coord { coordY = coordY p, + coordX = coordX p + len + } + (_,cs',_) -- moved to next line + -> moveCoord w Coord { + coordY = coordY p + 1, + coordX = 0 + } cs' + +movePosLeft str = do + p <- getPos + w <- asks width + setPos $ moveCoord w p str + where + moveCoord _ p [] = p + moveCoord w p cs = case splitAtWidth (coordX p) cs of + (_,[],len) -- stayed on same line + -> Coord { coordY = coordY p, + coordX = coordX p - len + } + (_,_:cs',_) -- moved to previous line + -> moveCoord w Coord { + coordY = coordY p - 1, + coordX = w-1 + } cs' + +crlf :: String +crlf = "\r\n" + +instance (MonadException m, MonadReader Layout m) => Term (Draw m) where + drawLineDiff (xs1,ys1) (xs2,ys2) = let + fixEsc = filter ((/= '\ESC') . baseChar) + in drawLineDiffWin (fixEsc xs1, fixEsc ys1) (fixEsc xs2, fixEsc ys2) + -- TODO now that we capture resize events. + -- first, looks like the cursor stays on the same line but jumps + -- to the beginning if cut off. + reposition _ _ = return () + + printLines [] = return () + printLines ls = printText $ intercalate crlf ls ++ crlf + + clearLayout = clearScreen + + moveToNextLine s = do + movePosRight (snd s) + printText "\r\n" -- make the console take care of creating a new line + + ringBell True = liftIO messageBeep + ringBell False = return () -- TODO + +win32TermStdin :: MaybeT IO RunTerm +win32TermStdin = do + liftIO (hIsTerminalDevice stdin) >>= guard + win32Term + +win32Term :: MaybeT IO RunTerm +win32Term = do + hs <- consoleHandles + ch <- liftIO newChan + fileRT <- liftIO $ fileRunTerm stdin + return fileRT { + termOps = Left TermOps { + getLayout = getBufferSize (hOut hs) + , withGetEvent = withWindowMode hs + . win32WithEvent hs ch + , saveUnusedKeys = saveKeys ch + , evalTerm = EvalTerm (runReaderT' hs . runDraw) + (Draw . lift) + }, + closeTerm = closeHandles hs + } + +win32WithEvent :: MonadException m => Handles -> Chan Event + -> (m Event -> m a) -> m a +win32WithEvent h eventChan f = f $ liftIO $ getEvent (hIn h) eventChan + +-- stdin is not a terminal, but we still need to check the right way to output unicode to stdout. +fileRunTerm :: Handle -> IO RunTerm +fileRunTerm h_in = do + putter <- putOut + cp <- getCodePage + return RunTerm { + closeTerm = return (), + putStrOut = putter, + wrapInterrupt = withCtrlCHandler, + termOps = Right FileOps + { inputHandle = h_in + , wrapFileInput = hWithBinaryMode h_in + , getLocaleChar = getMultiByteChar cp h_in + , maybeReadNewline = hMaybeReadNewline h_in + , getLocaleLine = hGetLocaleLine h_in + >>= liftIO . codePageToUnicode cp + } + + } + +-- On Windows, Unicode written to the console must be written with the WriteConsole API call. +-- And to make the API cross-platform consistent, Unicode to a file should be UTF-8. +putOut :: IO (String -> IO ()) +putOut = do + outIsTerm <- hIsTerminalDevice stdout + if outIsTerm + then do + h <- getStdHandle sTD_OUTPUT_HANDLE + return (writeConsole h) + else do + cp <- getCodePage + return $ \str -> unicodeToCodePage cp str >>= B.putStr >> hFlush stdout + + +type Handler = DWORD -> IO BOOL + +foreign import ccall "wrapper" wrapHandler :: Handler -> IO (FunPtr Handler) + +foreign import WINDOWS_CCONV "windows.h SetConsoleCtrlHandler" c_SetConsoleCtrlHandler + :: FunPtr Handler -> BOOL -> IO BOOL + +-- sets the tv to True when ctrl-c is pressed. +withCtrlCHandler :: MonadException m => m a -> m a +withCtrlCHandler f = bracket (liftIO $ do + tid <- myThreadId + fp <- wrapHandler (handler tid) + -- don't fail if we can't set the ctrl-c handler + -- for example, we might not be attached to a console? + _ <- c_SetConsoleCtrlHandler fp True + return fp) + (\fp -> liftIO $ c_SetConsoleCtrlHandler fp False) + (const f) + where + handler tid (#const CTRL_C_EVENT) = do + throwTo tid Interrupt + return True + handler _ _ = return False + + + +------------------------ +-- Multi-byte conversion + +foreign import WINDOWS_CCONV "WideCharToMultiByte" wideCharToMultiByte + :: CodePage -> DWORD -> LPCWSTR -> CInt -> LPCSTR -> CInt + -> LPCSTR -> LPBOOL -> IO CInt + +unicodeToCodePage :: CodePage -> String -> IO B.ByteString +unicodeToCodePage cp wideStr = withCWStringLen wideStr $ \(wideBuff, wideLen) -> do + -- first, ask for the length without filling the buffer. + outSize <- wideCharToMultiByte cp 0 wideBuff (toEnum wideLen) + nullPtr 0 nullPtr nullPtr + -- then, actually perform the encoding. + createAndTrim (fromEnum outSize) $ \outBuff -> + fmap fromEnum $ wideCharToMultiByte cp 0 wideBuff (toEnum wideLen) + (castPtr outBuff) outSize nullPtr nullPtr + +foreign import WINDOWS_CCONV "MultiByteToWideChar" multiByteToWideChar + :: CodePage -> DWORD -> LPCSTR -> CInt -> LPWSTR -> CInt -> IO CInt + +codePageToUnicode :: CodePage -> B.ByteString -> IO String +codePageToUnicode cp bs = B.useAsCStringLen bs $ \(inBuff, inLen) -> do + -- first ask for the size without filling the buffer. + outSize <- multiByteToWideChar cp 0 inBuff (toEnum inLen) nullPtr 0 + -- then, actually perform the decoding. + allocaArray0 (fromEnum outSize) $ \outBuff -> do + outSize' <- multiByteToWideChar cp 0 inBuff (toEnum inLen) outBuff outSize + peekCWStringLen (outBuff, fromEnum outSize') + + +getCodePage :: IO CodePage +getCodePage = do + conCP <- getConsoleCP + if conCP > 0 + then return conCP + else getACP + +foreign import WINDOWS_CCONV "IsDBCSLeadByteEx" c_IsDBCSLeadByteEx + :: CodePage -> BYTE -> BOOL + +getMultiByteChar :: CodePage -> Handle -> MaybeT IO Char +getMultiByteChar cp h = do + b1 <- hGetByte h + bs <- if c_IsDBCSLeadByteEx cp b1 + then hGetByte h >>= \b2 -> return [b1,b2] + else return [b1] + cs <- liftIO $ codePageToUnicode cp (B.pack bs) + case cs of + [] -> getMultiByteChar cp h + (c:_) -> return c + +---------------------------------- +-- Clearing screen +-- WriteConsole has a limit of ~20,000-30000 characters, which is +-- less than a 200x200 window, for example. +-- So we'll use other Win32 functions to clear the screen. + +getAttribute :: HANDLE -> IO WORD +getAttribute = withScreenBufferInfo $ + (#peek CONSOLE_SCREEN_BUFFER_INFO, wAttributes) + +fillConsoleChar :: HANDLE -> Char -> Int -> Coord -> IO () +fillConsoleChar h c n start = with start $ \startPtr -> alloca $ \numWritten -> do + failIfFalse_ "FillConsoleOutputCharacter" + $ c_FillConsoleCharacter h (toEnum $ fromEnum c) + (toEnum n) startPtr numWritten + +foreign import ccall "haskeline_FillConsoleCharacter" c_FillConsoleCharacter + :: HANDLE -> TCHAR -> DWORD -> Ptr Coord -> Ptr DWORD -> IO BOOL + +fillConsoleAttribute :: HANDLE -> WORD -> Int -> Coord -> IO () +fillConsoleAttribute h a n start = with start $ \startPtr -> alloca $ \numWritten -> do + failIfFalse_ "FillConsoleOutputAttribute" + $ c_FillConsoleAttribute h a + (toEnum n) startPtr numWritten + +foreign import ccall "haskeline_FillConsoleAttribute" c_FillConsoleAttribute + :: HANDLE -> WORD -> DWORD -> Ptr Coord -> Ptr DWORD -> IO BOOL + +clearScreen :: DrawM () +clearScreen = do + lay <- ask + h <- asks hOut + let windowSize = width lay * height lay + let origin = Coord 0 0 + attr <- liftIO $ getAttribute h + liftIO $ fillConsoleChar h ' ' windowSize origin + liftIO $ fillConsoleAttribute h attr windowSize origin + setPos origin + diff --git a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Command/Completion.hs b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Command/Completion.hs index 97a887b..71a0f12 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Command/Completion.hs +++ b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Command/Completion.hs @@ -21,7 +21,7 @@ useCompletion im c = insertString r im where r | isFinished c = replacement c ++ " " | otherwise = replacement c -askIMCompletions :: CommandMonad m => +askIMCompletions :: CommandMonad m => Command m InsertMode (InsertMode, [Completion]) askIMCompletions (IMode xs ys) = do (rest, completions) <- lift $ runCompletion (withRev graphemesToString xs, @@ -72,7 +72,7 @@ pagingCompletion :: MonadReader Layout m => Key -> Prefs pagingCompletion k prefs completions = \im -> do ls <- asks $ makeLines (map display completions) let pageAction = do - askFirst prefs (length completions) $ + askFirst prefs (length completions) $ if completionPaging prefs then printPage ls else effect (PrintLines ls) @@ -134,7 +134,7 @@ padWords :: Int -> [String] -> String padWords _ [x] = x padWords _ [] = "" padWords len (x:xs) = x ++ replicate (len - glength x) ' ' - ++ padWords len xs + ++ padWords len xs where -- kludge: compute the length in graphemes, not chars. -- but don't use graphemes for the max length, since I'm not convinced @@ -159,5 +159,3 @@ splitIntoGroups n xs = transpose $ unfoldr f xs ceilDiv :: Integral a => a -> a -> a ceilDiv m n | m `rem` n == 0 = m `div` n | otherwise = m `div` n + 1 - - diff --git a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Command.hs b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Command.hs index 986fd42..1a0d915 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Command.hs +++ b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Command.hs @@ -66,11 +66,11 @@ instance Monad m => Functor (CmdM m) where fmap = liftM instance Monad m => Applicative (CmdM m) where - pure = return + pure = Result (<*>) = ap instance Monad m => Monad (CmdM m) where - return = Result + return = pure GetKey km >>= g = GetKey $ fmap (>>= g) km DoEffect e f >>= g = DoEffect e (f >>= g) diff --git a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Directory.hsc b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Directory.hsc index b2deb22..9eb0952 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Directory.hsc +++ b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Directory.hsc @@ -19,7 +19,7 @@ import qualified System.Directory #endif #include -#include +#include ##if defined(i386_HOST_ARCH) ## define WINDOWS_CCONV stdcall diff --git a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Emacs.hs b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Emacs.hs index d5e0622..66d3297 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Emacs.hs +++ b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Emacs.hs @@ -89,7 +89,7 @@ rotatePaste im = get >>= loop wordRight, wordLeft, bigWordLeft :: InsertMode -> InsertMode wordRight = goRightUntil (atStart (not . isAlphaNum)) wordLeft = goLeftUntil (atStart isAlphaNum) -bigWordLeft = goLeftUntil (atStart isSpace) +bigWordLeft = goLeftUntil (atStart (not . isSpace)) modifyWord :: ([Grapheme] -> [Grapheme]) -> InsertMode -> InsertMode modifyWord f im = IMode (reverse (f ys1) ++ xs) ys2 diff --git a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/InputT.hs b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/InputT.hs index 383cf5f..c1ee55e 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/InputT.hs +++ b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/InputT.hs @@ -47,19 +47,12 @@ newtype InputT m a = InputT {unInputT :: (ReaderT (IORef KillRing) (ReaderT Prefs (ReaderT (Settings m) m)))) a} - deriving (Monad, MonadIO, MonadException) + deriving (Functor, Applicative, Monad, MonadIO, MonadException) -- NOTE: we're explicitly *not* making InputT an instance of our -- internal MonadState/MonadReader classes. Otherwise haddock -- displays those instances to the user, and it makes it seem like -- we implement the mtl versions of those classes. -instance Monad m => Functor (InputT m) where - fmap = liftM - -instance Monad m => Applicative (InputT m) where - pure = return - (<*>) = ap - instance MonadTrans InputT where lift = InputT . lift . lift . lift . lift . lift diff --git a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Monads.hs b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Monads.hs index 6668e96..d5fc1bb 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/System/Console/Haskeline/Monads.hs +++ b/ghc-7.10.3/libraries/haskeline/System/Console/Haskeline/Monads.hs @@ -77,11 +77,11 @@ instance Monad m => Functor (StateT s m) where fmap = liftM instance Monad m => Applicative (StateT s m) where - pure = return + pure x = StateT $ \s -> return $ \f -> f x s (<*>) = ap instance Monad m => Monad (StateT s m) where - return x = StateT $ \s -> return $ \f -> f x s + return = pure StateT f >>= g = StateT $ \s -> do useX <- f s useX $ \x s' -> getStateTFunc (g x) s' diff --git a/ghc-7.10.3.orig/libraries/haskeline/haskeline.cabal b/ghc-7.10.3/libraries/haskeline/haskeline.cabal index b709ee3..35ecb26 100644 --- a/ghc-7.10.3.orig/libraries/haskeline/haskeline.cabal +++ b/ghc-7.10.3/libraries/haskeline/haskeline.cabal @@ -1,6 +1,6 @@ Name: haskeline Cabal-Version: >=1.10 -Version: 0.7.2.1 +Version: 0.7.2.3 Category: User Interfaces License: BSD3 License-File: LICENSE @@ -16,7 +16,8 @@ Description: Haskell programs. . Haskeline runs both on POSIX-compatible systems and on Windows. -Homepage: http://trac.haskell.org/haskeline +Homepage: https://github.com/judah/haskeline +Bug-Reports: https://github.com/judah/haskeline/issues Stability: Experimental Build-Type: Custom extra-source-files: examples/Test.hs Changelog @@ -50,9 +51,9 @@ flag legacy-encoding Default: False Library - Build-depends: base >=4.3 && < 4.9, containers>=0.4 && < 0.6, + Build-depends: base >=4.3 && < 4.10, containers>=0.4 && < 0.6, directory>=1.1 && < 1.3, bytestring>=0.9 && < 0.11, - filepath >= 1.2 && < 1.5, transformers >= 0.2 && < 0.5 + filepath >= 1.2 && < 1.5, transformers >= 0.2 && < 0.6 Default-Language: Haskell98 Default-Extensions: ForeignFunctionInterface, Rank2Types, FlexibleInstances,