packages feed

haskeline 0.8.3.0 → 0.8.4.0

raw patch · 16 files changed

+237/−91 lines, 16 filesdep ~containersdep ~directoryPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: containers, directory

API changes (from Hackage documentation)

+ System.Console.Haskeline.ReaderT: data InputTEnv (m :: Type -> Type)
+ System.Console.Haskeline.ReaderT: fromReaderT :: forall (m :: Type -> Type) a. ReaderT (InputTEnv m) m a -> InputT m a
+ System.Console.Haskeline.ReaderT: mapInputTEnv :: (forall x. () => m x -> n x) -> InputTEnv m -> InputTEnv n
+ System.Console.Haskeline.ReaderT: toReaderT :: forall (m :: Type -> Type) a. InputT m a -> ReaderT (InputTEnv m) m a
- System.Console.Haskeline: Settings :: CompletionFunc m -> Maybe FilePath -> Bool -> Settings m
+ System.Console.Haskeline: Settings :: CompletionFunc m -> Maybe FilePath -> Bool -> Settings (m :: Type -> Type)
- System.Console.Haskeline: [autoAddHistory] :: Settings m -> Bool
+ System.Console.Haskeline: [autoAddHistory] :: Settings (m :: Type -> Type) -> Bool
- System.Console.Haskeline: [complete] :: Settings m -> CompletionFunc m
+ System.Console.Haskeline: [complete] :: Settings (m :: Type -> Type) -> CompletionFunc m
- System.Console.Haskeline: [historyFile] :: Settings m -> Maybe FilePath
+ System.Console.Haskeline: [historyFile] :: Settings (m :: Type -> Type) -> Maybe FilePath
- System.Console.Haskeline: data InputT m a
+ System.Console.Haskeline: data InputT (m :: Type -> Type) a
- System.Console.Haskeline: data Settings m
+ System.Console.Haskeline: data Settings (m :: Type -> Type)
- System.Console.Haskeline: defaultSettings :: MonadIO m => Settings m
+ System.Console.Haskeline: defaultSettings :: forall (m :: Type -> Type). MonadIO m => Settings m
- System.Console.Haskeline: getExternalPrint :: MonadIO m => InputT m (String -> IO ())
+ System.Console.Haskeline: getExternalPrint :: forall (m :: Type -> Type). MonadIO m => InputT m (String -> IO ())
- System.Console.Haskeline: getHistory :: MonadIO m => InputT m History
+ System.Console.Haskeline: getHistory :: forall (m :: Type -> Type). MonadIO m => InputT m History
- System.Console.Haskeline: getInputChar :: (MonadIO m, MonadMask m) => String -> InputT m (Maybe Char)
+ System.Console.Haskeline: getInputChar :: forall (m :: Type -> Type). (MonadIO m, MonadMask m) => String -> InputT m (Maybe Char)
- System.Console.Haskeline: getInputLine :: (MonadIO m, MonadMask m) => String -> InputT m (Maybe String)
+ System.Console.Haskeline: getInputLine :: forall (m :: Type -> Type). (MonadIO m, MonadMask m) => String -> InputT m (Maybe String)
- System.Console.Haskeline: getInputLineWithInitial :: (MonadIO m, MonadMask m) => String -> (String, String) -> InputT m (Maybe String)
+ System.Console.Haskeline: getInputLineWithInitial :: forall (m :: Type -> Type). (MonadIO m, MonadMask m) => String -> (String, String) -> InputT m (Maybe String)
- System.Console.Haskeline: getPassword :: (MonadIO m, MonadMask m) => Maybe Char -> String -> InputT m (Maybe String)
+ System.Console.Haskeline: getPassword :: forall (m :: Type -> Type). (MonadIO m, MonadMask m) => Maybe Char -> String -> InputT m (Maybe String)
- System.Console.Haskeline: haveTerminalUI :: Monad m => InputT m Bool
+ System.Console.Haskeline: haveTerminalUI :: forall (m :: Type -> Type). Monad m => InputT m Bool
- System.Console.Haskeline: mapInputT :: (forall b. m b -> m b) -> InputT m a -> InputT m a
+ System.Console.Haskeline: mapInputT :: (forall b. () => m b -> m b) -> InputT m a -> InputT m a
- System.Console.Haskeline: modifyHistory :: MonadIO m => (History -> History) -> InputT m ()
+ System.Console.Haskeline: modifyHistory :: forall (m :: Type -> Type). MonadIO m => (History -> History) -> InputT m ()
- System.Console.Haskeline: outputStr :: MonadIO m => String -> InputT m ()
+ System.Console.Haskeline: outputStr :: forall (m :: Type -> Type). MonadIO m => String -> InputT m ()
- System.Console.Haskeline: outputStrLn :: MonadIO m => String -> InputT m ()
+ System.Console.Haskeline: outputStrLn :: forall (m :: Type -> Type). MonadIO m => String -> InputT m ()
- System.Console.Haskeline: putHistory :: MonadIO m => History -> InputT m ()
+ System.Console.Haskeline: putHistory :: forall (m :: Type -> Type). MonadIO m => History -> InputT m ()
- System.Console.Haskeline: waitForAnyKey :: (MonadIO m, MonadMask m) => String -> InputT m Bool
+ System.Console.Haskeline: waitForAnyKey :: forall (m :: Type -> Type). (MonadIO m, MonadMask m) => String -> InputT m Bool
- System.Console.Haskeline: withInterrupt :: (MonadIO m, MonadMask m) => InputT m a -> InputT m a
+ System.Console.Haskeline: withInterrupt :: forall (m :: Type -> Type) a. (MonadIO m, MonadMask m) => InputT m a -> InputT m a
- System.Console.Haskeline: withRunInBase :: Monad m => ((forall a. InputT m a -> m a) -> m b) -> InputT m b
+ System.Console.Haskeline: withRunInBase :: Monad m => ((forall a. () => InputT m a -> m a) -> m b) -> InputT m b
- System.Console.Haskeline.Completion: type CompletionFunc m = (String, String) -> m (String, [Completion])
+ System.Console.Haskeline.Completion: type CompletionFunc (m :: Type -> Type) = (String, String) -> m (String, [Completion])

Files

Changelog view
@@ -1,3 +1,14 @@+Changed in version 0.8.4.0:++   * On Windows, when terminal-style and printing output, no longer skips+     `"\ESC...\STX"` sequences. (If used with legacy ConHost directly (for+     example, `conhost.exe cmd.exe`), it will require ConHost's ANSI-capability+     to be enabled separately.) (#126)++   * Added `System.Console.Haskeline.ReaderT` module for `ReaderT` interface.++   * `System.Console.Haskeline.Completion.listFiles` now returns a sorted list.+ Changed in version 0.8.3.0:     * User preferences are now read from $XDG_CONFIG_HOME/haskeline/haskeline.
System/Console/Haskeline.hs view
@@ -91,6 +91,7 @@ import System.Console.Haskeline.Key import System.Console.Haskeline.RunCommand +import Control.Monad ((>=>)) import Control.Monad.Catch (MonadMask, handle) import Data.Char (isSpace, isPrint) import Data.Maybe (isJust)@@ -144,6 +145,10 @@  If @'autoAddHistory' == 'True'@ and the line input is nonblank (i.e., is not all spaces), it will be automatically added to the history.++To include ANSI escape sequences in the input prompt, terminate them by @\STX@.+See <https://github.com/haskell/haskeline/wiki/ControlSequencesInPrompt> for+more information. -} getInputLine :: (MonadIO m, MonadMask m)             => String -- ^ The input prompt@@ -228,7 +233,7 @@ acceptOneChar :: Monad m => KeyCommand m InsertMode (Maybe Char) acceptOneChar = choiceCmd [useChar $ \c s -> change (insertChar c) s                                                 >> return (Just c)-                          , ctrlChar 'l' +> clearScreenCmd >|>+                          , ctrlChar 'l' +> clearScreenCmd >=>                                         keyCommand acceptOneChar                           , ctrlChar 'd' +> failCmd] @@ -282,12 +287,12 @@  where     loop = choiceCmd [ simpleChar '\n' +> finish                      , simpleKey Backspace +> change deletePasswordChar-                                                >|> loop'-                     , useChar $ \c -> change (addPasswordChar c) >|> loop'+                                                >=> loop'+                     , useChar $ \c -> change (addPasswordChar c) >=> loop'                      , ctrlChar 'd' +> \p -> if null (passwordState p)                                                 then failCmd p                                                 else finish p-                     , ctrlChar 'l' +> clearScreenCmd >|> loop'+                     , ctrlChar 'l' +> clearScreenCmd >=> loop'                      ]     loop' = keyCommand loop 
System/Console/Haskeline/Backend/Win32.hsc view
@@ -381,9 +381,7 @@ crlf = "\r\n"  instance (MonadMask m, MonadIO 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)+    drawLineDiff = drawLineDiffWin     -- 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.
System/Console/Haskeline/Command.hs view
@@ -8,7 +8,6 @@                         KeyConsumed(..),                         withoutConsuming,                         keyCommand,-                        (>|>),                         (>+>),                         try,                         effect,@@ -29,8 +28,7 @@                         ) where  import Data.Char(isPrint)-import Control.Applicative(Applicative(..))-import Control.Monad(ap, mplus, liftM)+import Control.Monad(ap, mplus, liftM, (>=>)) import Control.Monad.Trans.Class import System.Console.Haskeline.LineState import System.Console.Haskeline.Key@@ -45,7 +43,7 @@  data KeyMap a = KeyMap {lookupKM :: Key -> Maybe (KeyConsumed a)} -data KeyConsumed a = NotConsumed a | Consumed a+data KeyConsumed a = NotConsumed a | Consumed a deriving Show  instance Functor KeyMap where     fmap f km = KeyMap $ fmap (fmap f) . lookupKM km@@ -55,10 +53,10 @@     fmap f (Consumed x) = Consumed (f x)  -data CmdM m a   = GetKey (KeyMap (CmdM m a))-                | DoEffect Effect (CmdM m a)-                | CmdM (m (CmdM m a))-                | Result a+data CmdM m a = GetKey (KeyMap (CmdM m a))+              | DoEffect Effect (CmdM m a)+              | CmdM (m (CmdM m a))+              | Result a  type Command m s t = s -> CmdM m t @@ -112,20 +110,16 @@ keyChoiceCmdM :: [KeyMap (CmdM m a)] -> CmdM m a keyChoiceCmdM = GetKey . choiceCmd -infixr 6 >|>-(>|>) :: Monad m => Command m s t -> Command m t u -> Command m s u-f >|> g = \x -> f x >>= g- infixr 6 >+> (>+>) :: Monad m => KeyCommand m s t -> Command m t u -> KeyCommand m s u-km >+> g = fmap (>|> g) km+km >+> g = fmap (>=> g) km  -- attempt to run the command (predicated on getting a valid key); but if it fails, just keep -- going. try :: Monad m => KeyCommand m s s -> Command m s s try f = keyChoiceCmd [f,withoutConsuming return] -infixr 6 +>+infixr 0 +> (+>) :: Key -> a -> KeyMap a (+>) = useKey @@ -163,4 +157,4 @@ changeFromChar f = useChar $ change . f  doBefore :: Monad m => Command m s t -> KeyCommand m t u -> KeyCommand m s u-doBefore cmd = fmap (cmd >|>)+doBefore cmd = fmap (cmd >=>)
System/Console/Haskeline/Command/Completion.hs view
@@ -15,6 +15,7 @@ import System.Console.Haskeline.Completion import System.Console.Haskeline.Monads +import Control.Monad ((>=>)) import Data.List(transpose, unfoldr)  useCompletion :: InsertMode -> Completion -> InsertMode@@ -35,7 +36,7 @@ -- | Create a 'Command' for word completion. completionCmd :: (MonadState Undo m, CommandMonad m)                 => Key -> KeyCommand m InsertMode InsertMode-completionCmd k = k +> saveForUndo >|> \oldIM -> do+completionCmd k = k +> saveForUndo >=> \oldIM -> do     (rest,cs) <- askIMCompletions oldIM     case cs of         [] -> effect RingBell >> return oldIM@@ -59,7 +60,7 @@ menuCompletion k = loop     where         loop [] = setState-        loop (c:cs) = change (const c) >|> try (k +> loop cs)+        loop (c:cs) = change (const c) >=> try (k +> loop cs)  makePartialCompletion :: InsertMode -> [Completion] -> InsertMode makePartialCompletion im completions = insertString partial im
System/Console/Haskeline/Command/KillRing.hs view
@@ -55,14 +55,14 @@ killFromHelper :: (MonadState KillRing m, MonadState Undo m,                         Save s, Save t)                 => KillHelper -> Command m s t-killFromHelper helper = saveForUndo >|> \oldS -> do+killFromHelper helper = saveForUndo >=> \oldS -> do     let (gs,newIM) = applyHelper helper (save oldS)     modify (push gs)     setState (restore newIM)  killFromArgHelper :: (MonadState KillRing m, MonadState Undo m, Save s, Save t)                 => KillHelper -> Command m (ArgMode s) t-killFromArgHelper helper = saveForUndo >|> \oldS -> do+killFromArgHelper helper = saveForUndo >=> \oldS -> do     let (gs,newIM) = applyArgHelper helper (fmap save oldS)     modify (push gs)     setState (restore newIM)
System/Console/Haskeline/Completion.hs view
@@ -18,7 +18,7 @@   import System.FilePath-import Data.List(isPrefixOf)+import Data.List(isPrefixOf, sort) import Control.Monad(forM)  import System.Console.Haskeline.Directory@@ -186,7 +186,7 @@     -- get all of the files in that directory, as basenames     allFiles <- if not dirExists                     then return []-                    else fmap (map completion . filterPrefix)+                    else fmap (sort . map completion . filterPrefix)                             $ getDirectoryContents fixedDir     -- The replacement text should include the directory part, and also     -- have a trailing slash if it's itself a directory.
System/Console/Haskeline/Emacs.hs view
@@ -13,6 +13,7 @@ import System.Console.Haskeline.LineState import System.Console.Haskeline.InputT +import Control.Monad ((>=>)) import Control.Monad.Catch (MonadMask) import Data.Char @@ -32,7 +33,7 @@         deleteCharOrEOF s             | s == emptyIM  = return Nothing             | otherwise = change deleteNext s >>= justDelete-        justDelete = keyChoiceCmd [eotKey +> change deleteNext >|> justDelete+        justDelete = keyChoiceCmd [eotKey +> change deleteNext >=> justDelete                             , emacsCommands]  
System/Console/Haskeline/Internal.hs view
@@ -9,6 +9,8 @@ import System.Console.Haskeline.RunCommand import System.Console.Haskeline.Term +import Control.Monad ((>=>))+ -- | This function may be used to debug Haskeline's input. -- -- It loops indefinitely; every time a key is pressed, it will@@ -33,5 +35,5 @@                 effect (LineChange $ const ([],[]))                 effect (PrintLines [show k])                 setState emptyIM)-            >|> keyCommand loop+            >=> keyCommand loop     prompt = stringToGraphemes "> "
System/Console/Haskeline/Monads.hs view
@@ -84,7 +84,7 @@     put s = ask >>= liftIO . flip writeIORef s  evalStateT' :: Monad m => s -> StateT s m a -> m a-evalStateT' s f = liftM fst $ runStateT f s+evalStateT' = flip evalStateT  orElse :: Monad m => MaybeT m a -> m a -> m a orElse (MaybeT f) g = f >>= maybe g return
+ System/Console/Haskeline/ReaderT.hs view
@@ -0,0 +1,133 @@+-- | Provides an interface for 'ReaderT' rather than 'InputT'.+--+-- @since 0.8.4.0+module System.Console.Haskeline.ReaderT+    ( -- * ReaderT+      -- $reader+      toReaderT,+      fromReaderT,+      InputTEnv,+      mapInputTEnv,+    ) where++import Control.Monad.Trans.Reader (ReaderT (ReaderT, runReaderT))+import Data.IORef (IORef)+import System.Console.Haskeline.Command.KillRing (KillRing)+import System.Console.Haskeline.History (History)+import System.Console.Haskeline.InputT(+                         InputT(InputT),+                         Settings(+                            Settings,+                            autoAddHistory,+                            complete,+                            historyFile+                            )+                         )+import System.Console.Haskeline.Prefs (Prefs)+import System.Console.Haskeline.Term (RunTerm)+++-- $reader+--+-- These functions expose the 'InputT' type in terms of ordinary 'ReaderT'.+-- This allows for easier integration with applications that do not use a+-- concrete monad transformer stack, or do not want to commit to having+-- 'InputT' in the stack.++-- | The abstract environment used by 'InputT', for 'ReaderT'+-- usage.+--+-- @since 0.8.4.0+data InputTEnv m = MkInputTEnv+    { runTerm :: RunTerm,+      history :: IORef History,+      killRing :: IORef KillRing,+      prefs :: Prefs,+      settings :: Settings m+    }++-- | Maps the environment.+--+-- @since 0.8.4.0+mapInputTEnv :: (forall x. m x -> n x) -> InputTEnv m -> InputTEnv n+mapInputTEnv f (MkInputTEnv t h k p s) =+    MkInputTEnv+        { runTerm = t,+          history = h,+          killRing = k,+          prefs = p,+          settings = settings'+        }+    where+        settings' = Settings+            { complete = f . complete s,+              historyFile = historyFile s,+              autoAddHistory = autoAddHistory s+            }++-- | Maps an 'InputT' to a 'ReaderT'. Useful for lifting 'InputT' functions+-- into some other reader-like monad.+--+-- __Examples:__+--+-- @+-- import System.Console.Haskeline qualified as H+--+-- runApp :: ReaderT (InputTEnv IO) IO ()+-- runApp = do+--   input <- toReaderT (H.getInputLine "Enter your name: ")+--   ...+-- @+--+-- @+-- -- MTL-style polymorphism+-- class MonadHaskeline m where+--   getInputLine :: String -> m (Maybe String)+--+-- -- AppT is the core type over ReaderT.+-- instance MonadHaskeline (AppT m) where+--   getInputLine = lift . toReaderT . H.getInputLine+--+-- runApp :: (MonadHaskeline m) => m ()+-- runApp = do+--   input <- getInputLine "Enter your name: "+--   ...+-- @+--+-- @since 0.8.4.0+toReaderT :: InputT m a -> ReaderT (InputTEnv m) m a+toReaderT (InputT rdr) = ReaderT $ \st ->+    usingReaderT (settings st)+        . usingReaderT (prefs st)+        . usingReaderT (killRing st)+        . usingReaderT (history st)+        . usingReaderT (runTerm st)+        $ rdr++-- | Maps a 'ReaderT' to an 'InputT'. Allows defining an application in terms+-- of 'ReaderT'.+--+-- __Examples:__+--+-- @+-- import System.Console.Haskeline qualified as H+--+-- -- Could be generalized to MonadReader, effects libraries.+-- runApp :: ReaderT (InputTEnv IO) IO ()+--+-- main :: IO ()+-- main = H.runInputT H.defaultSettings $ fromReaderT runApp+-- @+--+-- @since 0.8.4.0+fromReaderT :: ReaderT (InputTEnv m) m a -> InputT m a+fromReaderT (ReaderT onEnv) = InputT $ ReaderT+    $ \runTerm' -> ReaderT+    $ \history' -> ReaderT+    $ \killRing' -> ReaderT+    $ \prefs' -> ReaderT+    $ \settings' ->+        onEnv (MkInputTEnv runTerm' history' killRing' prefs' settings')++usingReaderT :: env -> ReaderT env m a -> m a+usingReaderT = flip runReaderT
System/Console/Haskeline/Vi.hs view
@@ -1,7 +1,7 @@ #if __GLASGOW_HASKELL__ < 802 {-# OPTIONS_GHC -Wno-redundant-constraints #-} #endif-module System.Console.Haskeline.Vi where+module System.Console.Haskeline.Vi (emptyViState, viKeyCommands) where  import System.Console.Haskeline.Command import System.Console.Haskeline.Monads@@ -14,14 +14,14 @@ import System.Console.Haskeline.InputT  import Data.Char-import Control.Monad(liftM)+import Control.Monad(liftM, (>=>)) import Control.Monad.Catch (MonadMask)  type EitherMode = Either CommandMode InsertMode  type SavedCommand m = Command (ViT m) (ArgMode CommandMode) EitherMode -data ViState m = ViState { +data ViState m = ViState {             lastCommand :: SavedCommand m,             lastSearch :: [Grapheme]          }@@ -43,7 +43,7 @@                 , ctrlChar 'd' +> eofIfEmpty                 , simpleInsertions >+> viCommands                 , simpleChar '\ESC' +> change enterCommandMode-                    >|> viCommandActions+                    >=> viCommandActions                 ]  viCommands :: InputCmd InsertMode (Maybe String)@@ -51,10 +51,10 @@  simpleInsertions :: InputKeyCmd InsertMode InsertMode simpleInsertions = choiceCmd-                [  simpleKey LeftKey +> change goLeft +                [  simpleKey LeftKey +> change goLeft                    , simpleKey RightKey +> change goRight-                   , simpleKey Backspace +> change deletePrev -                   , simpleKey Delete +> change deleteNext +                   , simpleKey Backspace +> change deletePrev+                   , simpleKey Delete +> change deleteNext                    , simpleKey Home +> change moveToStart                    , simpleKey End +> change moveToEnd                    , insertChars@@ -72,13 +72,13 @@ insertChars :: InputKeyCmd InsertMode InsertMode insertChars = useChar $ loop []     where-        loop ds d = change (insertChar d) >|> keyChoiceCmd [+        loop ds d = change (insertChar d) >=> keyChoiceCmd [                         useChar $ loop (d:ds)                         , withoutConsuming (storeCharInsertion (reverse ds))                         ]-        storeCharInsertion s = storeLastCmd $ change (applyArg +        storeCharInsertion s = storeLastCmd $ change (applyArg                                                         $ withCommandMode $ insertString s)-                                                >|> return . Left+                                                >=> return . Left  -- If we receive a ^D and the line is empty, return Nothing -- otherwise, act like '\n' (mimicking how Readline behaves)@@ -101,7 +101,7 @@         chooseEitherMode (Right im) = viCommands im  exitingCommands :: InputKeyCmd CommandMode InsertMode-exitingCommands =  choiceCmd [ +exitingCommands =  choiceCmd [                       simpleChar 'i' +> change insertFromCommandMode                     , simpleChar 'I' +> change (moveToStart . insertFromCommandMode)                     , simpleKey Home +> change (moveToStart . insertFromCommandMode)@@ -109,29 +109,29 @@                     , simpleChar 'A' +> change (moveToEnd . appendFromCommandMode)                     , simpleKey End +> change (moveToStart  . insertFromCommandMode)                     , simpleChar 's' +> change (insertFromCommandMode . deleteChar)-                    , simpleChar 'S' +> noArg >|> killAndStoreI killAll-                    , simpleChar 'C' +> noArg >|> killAndStoreI (SimpleMove moveToEnd)+                    , simpleChar 'S' +> noArg >=> killAndStoreI killAll+                    , simpleChar 'C' +> noArg >=> killAndStoreI (SimpleMove moveToEnd)                     ]  simpleCmdActions :: InputKeyCmd CommandMode CommandMode-simpleCmdActions = choiceCmd [ +simpleCmdActions = choiceCmd [                     simpleChar '\ESC' +> change id -- helps break out of loops-                    , simpleChar 'r'   +> replaceOnce +                    , simpleChar 'r'   +> replaceOnce                     , simpleChar 'R'   +> replaceLoop-                    , simpleChar 'D' +> noArg >|> killAndStoreCmd (SimpleMove moveToEnd)+                    , simpleChar 'D' +> noArg >=> killAndStoreCmd (SimpleMove moveToEnd)                     , ctrlChar 'l' +> clearScreenCmd                     , simpleChar 'u' +> commandUndo                     , ctrlChar 'r' +> commandRedo                     -- vi-mode quirk: history is put at the start of the line.-                    , simpleChar 'j' +> historyForward >|> change moveToStart-                    , simpleChar 'k' +> historyBack >|> change moveToStart-                    , simpleKey DownKey +> historyForward  >|> change moveToStart-                    , simpleKey UpKey +> historyBack >|> change moveToStart+                    , simpleChar 'j' +> historyForward >=> change moveToStart+                    , simpleChar 'k' +> historyBack >=> change moveToStart+                    , simpleKey DownKey +> historyForward  >=> change moveToStart+                    , simpleKey UpKey +> historyBack >=> change moveToStart                     , simpleChar '/' +> viEnterSearch '/' Reverse                     , simpleChar '?' +> viEnterSearch '?' Forward                     , simpleChar 'n' +> viSearchHist Reverse []                     , simpleChar 'N' +> viSearchHist Forward []-                    , simpleKey KillLine +> noArg >|> killAndStoreCmd (SimpleMove moveToStart)+                    , simpleKey KillLine +> noArg >=> killAndStoreCmd (SimpleMove moveToStart)                     ]  replaceOnce :: InputCmd CommandMode CommandMode@@ -186,7 +186,7 @@ repeatableCommands = choiceCmd                         [ repeatableCmdToIMode                         , repeatableCmdMode >+> return . Left-                        , simpleChar '.' +> saveForUndo >|> runLastCommand+                        , simpleChar '.' +> saveForUndo >=> runLastCommand                         ]     where         runLastCommand s = liftM lastCommand get >>= ($ s)@@ -204,7 +204,7 @@                     , pureMovements                     ]     where-        repeatableChange f = storedCmdAction (saveForUndo >|> change (applyArg f))+        repeatableChange f = storedCmdAction (saveForUndo >=> change (applyArg f))  flipCase :: CommandMode -> CommandMode flipCase CEmpty = CEmpty@@ -288,14 +288,14 @@             , (simpleChar 'E', goRightUntil (atEnd isBigWordChar))             ] -{- +{- From IEEE 1003.1: A "bigword" consists of: a maximal sequence of non-blanks preceded and followed by blanks A "word" consists of either:  - a maximal sequence of wordChars, delimited at both ends by non-wordchars  - a maximal sequence of non-blank non-wordchars, delimited at both ends by either blanks    or a wordchar.--}            +-} isBigWordChar, isWordChar, isOtherChar :: Char -> Bool isBigWordChar = not . isSpace isWordChar = isAlphaNum .||. (=='_')@@ -304,7 +304,7 @@ (.||.) :: (a -> Bool) -> (a -> Bool) -> a -> Bool (f .||. g) x = f x || g x -foreachDigit :: (Monad m, LineState t) => (Int -> s -> t) -> [Char] +foreachDigit :: (Monad m, LineState t) => (Int -> s -> t) -> [Char]                 -> KeyCommand m s t foreachDigit f ds = choiceCmd $ map digitCmd ds     where digitCmd d = simpleChar d +> change (f (toDigit d))@@ -348,7 +348,7 @@                     | baseChar x == d = n-1                     | otherwise = n -matchingRightBrace, matchingLeftBrace :: Char -> Maybe Char +matchingRightBrace, matchingLeftBrace :: Char -> Maybe Char matchingRightBrace = flip lookup braceList matchingLeftBrace = flip lookup (map (\(c,d) -> (d,c)) braceList) @@ -358,8 +358,8 @@ --------------- -- Replace mode replaceLoop :: InputCmd CommandMode CommandMode-replaceLoop = saveForUndo >|> change insertFromCommandMode >|> loop-                >|> change enterCommandModeRight+replaceLoop = saveForUndo >=> change insertFromCommandMode >=> loop+                >=> change enterCommandModeRight     where         loop = try (oneReplaceCmd >+> loop)         oneReplaceCmd = choiceCmd [@@ -378,15 +378,15 @@         return s  storedAction :: Monad m => SavedCommand m -> SavedCommand m-storedAction act = storeLastCmd act >|> act+storedAction act = storeLastCmd act >=> act  storedCmdAction :: Monad m => Command (ViT m) (ArgMode CommandMode) CommandMode                             -> Command (ViT m) (ArgMode CommandMode) CommandMode-storedCmdAction act = storeLastCmd (liftM Left . act) >|> act+storedCmdAction act = storeLastCmd (liftM Left . act) >=> act  storedIAction :: Monad m => Command (ViT m) (ArgMode CommandMode) InsertMode                         -> Command (ViT m) (ArgMode CommandMode) InsertMode-storedIAction act = storeLastCmd (liftM Right . act) >|> act+storedIAction act = storeLastCmd (liftM Right . act) >=> act  killAndStoreCmd :: MonadIO m => KillHelper -> Command (ViT m) (ArgMode CommandMode) CommandMode killAndStoreCmd = storedCmdAction . killFromArgHelper@@ -395,7 +395,7 @@ killAndStoreI = storedIAction . killFromArgHelper  killAndStoreIE :: MonadIO m => KillHelper -> Command (ViT m) (ArgMode CommandMode) EitherMode-killAndStoreIE helper = storedAction (killFromArgHelper helper >|> return . Right)+killAndStoreIE helper = storedAction (killFromArgHelper helper >=> return . Right)  noArg :: Monad m => Command m s (ArgMode s) noArg = return . startArg 1@@ -423,7 +423,7 @@         modifySE f se = se {entryState = f (entryState se)}         loopEntry = keyChoiceCmd [                         editEntry >+> loopEntry-                        , simpleChar '\n' +> \se -> +                        , simpleChar '\n' +> \se ->                             viSearchHist dir (searchText se) s                         , withoutConsuming (change (const s))                         ]@@ -433,7 +433,7 @@                         , simpleKey RightKey +> change (modifySE goRight)                         , simpleKey Backspace +> change (modifySE deletePrev)                         , simpleKey Delete +> change (modifySE deleteNext)-                        ] +                        ]  viSearchHist :: forall m . Monad m     => Direction -> [Grapheme] -> Command (ViT m) CommandMode CommandMode
haskeline.cabal view
@@ -1,6 +1,6 @@ Name:           haskeline Cabal-Version:  >=1.10-Version:        0.8.3.0+Version:        0.8.4.0 Category:       User Interfaces License:        BSD3 License-File:   LICENSE@@ -21,6 +21,7 @@ Build-Type:     Simple  tested-with:+  GHC == 9.12.1   GHC == 9.10.1   GHC == 9.8.2   GHC == 9.6.5@@ -34,7 +35,7 @@   GHC == 8.2.2   GHC == 8.0.2 -extra-source-files: examples/Test.hs Changelog includes/*.h+extra-source-files: examples/Test.hs Changelog  source-repository head     type: git@@ -62,8 +63,8 @@  Library     Build-depends:-        base         >= 4.9 && < 4.21-      , containers   >= 0.4 && < 0.8+        base         >= 4.9 && < 4.23+      , containers   >= 0.4 && < 0.9       , directory    >= 1.1 && < 1.4       , bytestring   >= 0.9 && < 0.13       , filepath     >= 1.2 && < 1.6@@ -88,6 +89,7 @@                 System.Console.Haskeline.History                 System.Console.Haskeline.IO                 System.Console.Haskeline.Internal+                System.Console.Haskeline.ReaderT     Other-Modules:                 System.Console.Haskeline.Backend                 System.Console.Haskeline.Backend.WCWidth@@ -149,9 +151,10 @@     Main-Is:    Unit.hs     Build-depends:       -- shared dependencies with library-        base         >= 4.9 && < 4.21-      , containers   >= 0.4 && < 0.8+        base         >= 4.9 && < 4.23+      , containers   >= 0.4 && < 0.9       , bytestring   >= 0.9 && < 0.13+      , directory       , process      >= 1.0 && < 1.7       -- dependencies for test-suite       , HUnit
− includes/windows_cconv.h
@@ -1,12 +0,0 @@-#ifndef WINDOWS_CCONV_H-#define WINDOWS_CCONV_H--#if defined(i386_HOST_ARCH)-# define WINDOWS_CCONV stdcall-#elif defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)-# define WINDOWS_CCONV ccall-#else-# error Unknown mingw32 arch-#endif--#endif
tests/RunTTY.hs view
@@ -41,9 +41,9 @@   setUTF8 :: Invocation -> Invocation-setUTF8 = setLang "en_US.UTF-8"+setUTF8 = setLang "C.UTF-8" setLatin1 :: Invocation -> Invocation-setLatin1 = setLang "en_US.ISO8859-1"+setLatin1 = setLang "C.ISO8859-1"   runInvocation :: Invocation
tests/Unit.hs view
@@ -16,6 +16,7 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as E import Data.Monoid ((<>))+import System.Directory (createDirectoryIfMissing) import System.Exit (exitFailure) import System.Process (readProcess) import Test.HUnit@@ -34,6 +35,13 @@ whenLegacy :: BC.ByteString -> BC.ByteString whenLegacy s = if legacyEncoding then s else B.empty +-- These files are used to test tab completion.+makeTestFiles :: IO ()+makeTestFiles = do+  createDirectoryIfMissing True "tests/dummy-μασ"+  writeFile "tests/dummy-μασ/bar" ""+  writeFile "tests/dummy-μασ/ςερτ" ""+ main :: IO () main = do     -- forkProcess needs an absolute path to the binary.@@ -45,6 +53,7 @@                 runInTTY = True,                 environment = []             }+    makeTestFiles     result <- runTestTT $ test [interactionTests i, fileStyleTests i]     when (errors result > 0 || failures result > 0) exitFailure @@ -113,7 +122,7 @@ tabCompletion i = "tab completion" ~:     [ utf8Test i [ utf8 "tests/dummy-μ\t\t" ]         [ prompt 0, utf8 "tests/dummy-μασ/"-            <> nl <> utf8 "ςερτ  bar" <> nl+            <> nl <> utf8 "bar   ςερτ" <> nl             <> prompt' 0 <> utf8 "tests/dummy-μασ/"         ]     ]@@ -259,13 +268,14 @@         ]     , "line char input" ~: utf8Test (setCharInput i)         [utf8 "xαβ"]-        [ prompt' 0, utf8 "x" <> nl <> output 0 (utf8 "x")-          <> prompt' 1 <> utf8 "α" <> nl <> output 1 (utf8 "α")-          <> prompt' 2 <> utf8 "β" <> nl <> output 2 (utf8 "β")+        [ prompt' 0, utf8 "x" <> dumbnl <> output 0 (utf8 "x")+          <> prompt' 1 <> utf8 "α" <> dumbnl <> output 1 (utf8 "α")+          <> prompt' 2 <> utf8 "β" <> dumbnl <> output 2 (utf8 "β")           <> prompt' 3         ]     ]   where+    dumbnl = raw [13,10]     wideChar = T.concat $ replicate 10 $ "안기영"  -------------@@ -287,7 +297,7 @@ cr = raw [13]  nl :: B.ByteString-nl = raw [13,10] -- NB: see fixNL: this is really [13,13,10]+nl = raw [27, 69]  output :: Int -> B.ByteString -> B.ByteString output k s = utf8 (T.pack $ "line " ++ show k ++ ":")