Hedi 0.1 → 0.1.1
raw patch · 9 files changed
+208/−238 lines, 9 filesdep +editlinedep −readlinePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: editline
Dependencies removed: readline
API changes (from Hackage documentation)
- Buffer: Append :: Either [String] [String] -> InsideAppend
- Buffer: Inside :: [String] -> String -> [String] -> InsideAppend
- Buffer: cursor :: InsideAppend -> String
- Buffer: data InsideAppend
- Buffer: elems :: InsideAppend -> Either [String] [String]
- Buffer: instance Engine InsideAppend
- Buffer: instance Eq InsideAppend
- Buffer: instance Show InsideAppend
- Buffer: left :: InsideAppend -> [String]
- Buffer: right :: InsideAppend -> [String]
- Editor: instance (Engine w, SIO m, HCtx m (Stato w)) => Ctx m w
- Editor: instance (Eq w) => Eq (Stato w)
- Editor: instance (Show w) => Show (Stato w)
- Engine: W :: w -> W w
- Engine: class (Eq a) => Engine a
- Engine: instance (Eq w, Engine w) => Arbitrary (W w)
- Engine: instance (Show w) => Show (W w)
- Engine: instance Arbitrary Char
- Engine: newtype W w
- Engine: prop_E1 :: (Engine w) => W w -> String -> Bool
- Test: Console :: [Line] -> [Line] -> [Line] -> [Line] -> Console
- Test: data Console
- Test: instance Show Console
+ Editor: instance (SIO m, HCtx m Stato) => Ctx m
+ Editor: instance Eq Stato
+ Editor: instance Show Stato
+ Engine: Corner :: Either [String] [String] -> Engine
+ Engine: Inside :: [String] -> String -> [String] -> Engine
+ Engine: cursor :: Engine -> String
+ Engine: data Engine
+ Engine: elems :: Engine -> Either [String] [String]
+ Engine: instance Eq Engine
+ Engine: instance Show Engine
+ Engine: isInside :: Engine -> Bool
+ Engine: left :: Engine -> [String]
+ Engine: right :: Engine -> [String]
+ Engine: runner :: Change Engine -> Engine -> [Engine]
+ Main: handleWith :: (IOError -> k) -> IO a -> ErrorT k IO a
+ Main: strictReadFile :: String -> IO String
+ Test: Emulator :: [Line] -> [Line] -> [Line] -> [Line] -> Emulator
+ Test: data Emulator
+ Test: instance Show Emulator
- Editor: Stato :: w -> String -> Maybe String -> Maybe Command -> Maybe w -> Stato w
+ Editor: Stato :: Engine -> String -> Maybe String -> Maybe Command -> Maybe Engine -> Stato
- Editor: backend :: (Ctx m w) => Maybe a -> Editor m w a
+ Editor: backend :: (Ctx m) => Maybe a -> Editor m a
- Editor: class (Engine w, SIO m, HCtx m (Stato w)) => Ctx m w
+ Editor: class (SIO m, HCtx m (Stato)) => Ctx m
- Editor: data Stato w
+ Editor: data Stato
- Editor: errorlog :: (Ctx m w) => String -> Editor m w ()
+ Editor: errorlog :: (Ctx m) => String -> Editor m ()
- Editor: file :: Stato w -> w
+ Editor: file :: Stato -> Engine
- Editor: filename :: Stato w -> Maybe String
+ Editor: filename :: Stato -> Maybe String
- Editor: history :: (Ctx m w) => String -> Editor m w ()
+ Editor: history :: (Ctx m) => String -> Editor m ()
- Editor: hputfile :: (Ctx m w) => w -> Editor m w ()
+ Editor: hputfile :: (Ctx m) => Engine -> Editor m ()
- Editor: input :: (Ctx m w) => Editor m w (Maybe String)
+ Editor: input :: (Ctx m) => Editor m (Maybe String)
- Editor: lastre :: Stato w -> String
+ Editor: lastre :: Stato -> String
- Editor: lastsaved :: Stato w -> Maybe w
+ Editor: lastsaved :: Stato -> Maybe Engine
- Editor: liftSio :: (Ctx m w) => m a -> Editor m w a
+ Editor: liftSio :: (Ctx m) => m a -> Editor m a
- Editor: liftStatoE :: (Ctx m w) => StatoE m w a -> Editor m w a
+ Editor: liftStatoE :: (Ctx m) => StatoE m a -> Editor m a
- Editor: output :: (Ctx m w) => String -> Editor m w ()
+ Editor: output :: (Ctx m) => String -> Editor m ()
- Editor: pending :: Stato w -> Maybe Command
+ Editor: pending :: Stato -> Maybe Command
- Editor: pinput :: (Ctx m w) => String -> Editor m w (Maybe String)
+ Editor: pinput :: (Ctx m) => String -> Editor m (Maybe String)
- Editor: run :: (Ctx m w) => Editor m w a -> Stato w -> m (Stato w)
+ Editor: run :: (Ctx m) => Editor m a -> Stato -> m (Stato)
- Editor: through :: (Ctx m w) => (w -> Maybe a) -> Editor m w a
+ Editor: through :: (Ctx m) => (Engine -> Maybe a) -> Editor m a
- Editor: type Editor m w = ErrorT Err (StatoE m w)
+ Editor: type Editor m = ErrorT Err (StatoE m)
- Editor: type StatoE m w = UndoT (Stato w) m
+ Editor: type StatoE m = UndoT Stato m
- Engine: add :: (Engine a) => [String] -> Change a
+ Engine: add :: [String] -> Change Engine
- Engine: bwdcycle :: (Engine a) => a -> [a]
+ Engine: bwdcycle :: Engine -> [Engine]
- Engine: del :: (Engine a) => Change a
+ Engine: del :: Change Engine
- Engine: deln :: (Engine a) => Int -> Change a
+ Engine: deln :: Int -> Change Engine
- Engine: empty :: (Engine a) => a
+ Engine: empty :: Engine
- Engine: end :: (Engine a) => Change a
+ Engine: end :: Change Engine
- Engine: first :: (Engine w) => Change w
+ Engine: first :: Change Engine
- Engine: fromstart :: (Engine a) => a -> [a]
+ Engine: fromstart :: Engine -> [Engine]
- Engine: fwdcycle :: (Engine a) => a -> [a]
+ Engine: fwdcycle :: Engine -> [Engine]
- Engine: ins :: (Engine a) => [String] -> Change a
+ Engine: ins :: [String] -> Change Engine
- Engine: jump :: (Engine a) => Int -> Change a
+ Engine: jump :: Int -> Change Engine
- Engine: last :: (Engine w) => Change w
+ Engine: last :: Change Engine
- Engine: line :: (Engine a) => a -> Maybe String
+ Engine: line :: Engine -> Maybe String
- Engine: linen :: (Engine a) => Int -> a -> Maybe [String]
+ Engine: linen :: Int -> Engine -> Maybe [String]
- Engine: listIn :: (Engine a) => [String] -> a
+ Engine: listIn :: [String] -> Engine
- Engine: listOut :: (Engine a) => a -> Maybe [String]
+ Engine: listOut :: Engine -> Maybe [String]
- Engine: next :: (Engine a) => Change a
+ Engine: next :: Change Engine
- Engine: nextn :: (Engine a) => Int -> Change a
+ Engine: nextn :: Int -> Change Engine
- Engine: pos :: (Engine a) => a -> Pos
+ Engine: pos :: Engine -> Pos
- Engine: prev :: (Engine a) => Change a
+ Engine: prev :: Change Engine
- Engine: prevn :: (Engine a) => Int -> Change a
+ Engine: prevn :: Int -> Change Engine
- Engine: rjump :: (Engine a) => Int -> Change a
+ Engine: rjump :: Int -> Change Engine
- Engine: start :: (Engine a) => Change a
+ Engine: start :: Change Engine
- Engine: tillend :: (Engine a) => a -> [a]
+ Engine: tillend :: Engine -> [Engine]
- Eval: eval :: (Ctx m w) => CompleteCommand -> Editor m w ()
+ Eval: eval :: (Ctx m) => CompleteCommand -> Editor m ()
- Eval: getname :: (Ctx m w) => Editor m w String -> Editor m w String
+ Eval: getname :: (Ctx m) => Editor m String -> Editor m String
- Eval: write :: (Ctx m w) => String -> Editor m w ()
+ Eval: write :: (Ctx m) => String -> Editor m ()
- Eval: writefail :: (Ctx m w) => Either String () -> Editor m w ()
+ Eval: writefail :: (Ctx m) => Either String () -> Editor m ()
- Offset: doOffset :: (Ctx m w) => Offset -> (a -> Editor m w b) -> (w -> Maybe a) -> Editor m w b
+ Offset: doOffset :: (Ctx m) => Offset -> (a -> Editor m b) -> (Engine -> Maybe a) -> Editor m b
- Offset: doRange :: (Ctx m w) => Range -> (a -> Editor m w b) -> (Int -> w -> Maybe a) -> Editor m w b
+ Offset: doRange :: (Ctx m) => Range -> (a -> Editor m b) -> (Int -> Engine -> Maybe a) -> Editor m b
- Offset: editOffset :: (Ctx m w) => Offset -> (w -> Maybe w) -> Editor m w ()
+ Offset: editOffset :: (Ctx m) => Offset -> (Engine -> Maybe Engine) -> Editor m ()
- Offset: editRange :: (Ctx m w) => Range -> (Int -> w -> Maybe w) -> Editor m w ()
+ Offset: editRange :: (Ctx m) => Range -> (Int -> Engine -> Maybe Engine) -> Editor m ()
- Offset: jumpE :: (Ctx m w) => Offset -> Editor m w w
+ Offset: jumpE :: (Ctx m) => Offset -> Editor m Engine
- Offset: rangeResolve :: (Ctx m w) => Range -> Editor m w (Int, w)
+ Offset: rangeResolve :: (Ctx m) => Range -> Editor m (Int, Engine)
- Operation: checkPendings :: (Ctx m w) => Editor m w () -> Editor m w ()
+ Operation: checkPendings :: (Ctx m) => Editor m () -> Editor m ()
- Operation: commandLoop :: (Ctx m w) => (String -> Either String CompleteCommand) -> (CompleteCommand -> Editor m w ()) -> Editor m w ()
+ Operation: commandLoop :: (Ctx m) => (String -> Either String CompleteCommand) -> (CompleteCommand -> Editor m ()) -> Editor m ()
- Operation: commandMode :: (Ctx m w) => (String -> Either String CompleteCommand) -> (CompleteCommand -> Editor m w ()) -> Editor m w ()
+ Operation: commandMode :: (Ctx m) => (String -> Either String CompleteCommand) -> (CompleteCommand -> Editor m ()) -> Editor m ()
- Operation: evalSensible :: (Ctx m w) => Command -> Editor m w () -> Editor m w ()
+ Operation: evalSensible :: (Ctx m) => Command -> Editor m () -> Editor m ()
- Operation: inputMode :: (Ctx m w) => Editor m w [String]
+ Operation: inputMode :: (Ctx m) => Editor m [String]
- Operation: modified :: (Ctx m w) => Editor m w Bool
+ Operation: modified :: (Ctx m) => Editor m Bool
- Operation: resetpending :: (Ctx m w) => Editor m w ()
+ Operation: resetpending :: (Ctx m) => Editor m ()
- Test: cerror :: Console -> [Line]
+ Test: cerror :: Emulator -> [Line]
- Test: chistory :: Console -> [Line]
+ Test: chistory :: Emulator -> [Line]
- Test: cinput :: Console -> [Line]
+ Test: cinput :: Emulator -> [Line]
- Test: coutput :: Console -> [Line]
+ Test: coutput :: Emulator -> [Line]
- Test: type CState = State Console
+ Test: type CState = State Emulator
Files
- Buffer.hs +0/−77
- Editor.hs +25/−25
- Engine.hs +117/−81
- Eval.hs +6/−6
- Hedi.cabal +5/−5
- Main.hs +5/−4
- Offset.hs +23/−23
- Operation.hs +11/−11
- Test.hs +16/−6
− Buffer.hs
@@ -1,77 +0,0 @@--- | An Editor backend implementation, made of the instance of Engine of InsideAppend.-module Buffer (InsideAppend (..))-where--import Data.Maybe-import Engine-import Test.QuickCheck---- |See the "Engine" class docs -data InsideAppend - -- | the cursor when its pointing to a real line (eg line function doesn't fail)- = Inside {- left :: [String], -- ^ lines before the cursor (reversed order)- cursor ::String , -- ^ addressed line- right :: [String] -- ^ lines after the cursor- }- -- | the cursor is pointing either to insert at the front of the file or - -- append at the end of the file.- | Append - { - elems :: Either [String] [String] -- ^ Left lines is in append mode, Right is in insert at front mode.- }- deriving (Show , Eq)--instance Engine InsideAppend where- listIn xs = Append (Right xs)- prev (Append (Right _ )) = Nothing - prev (Append (Left [] )) = error "empty Append Left"- prev (Append (Left (l:ls))) = Just $ Inside ls l [] - prev (Inside [] x ls) = Just $ Append (Right (x:ls)) - prev (Inside (l:ls) x rs) = Just $ Inside ls l (x:rs) - next (Append (Right [] )) = Nothing- next (Append (Right (r:rs))) = Just $ Inside [] r rs - next (Append (Left [] )) = error "empty Append Left"- next (Append (Left _ )) = Nothing- next (Inside ls x [] ) = Just $ Append (Left (x:ls)) - next (Inside ls x (r:rs)) = Just $ Inside (x:ls) r rs - end w@ (Append (Left _)) = Just w- end w = next w >>= end- start w@ (Append (Right _)) = Just w- start w = prev w >>= start - pos (Append (Left ls)) = End (length ls + 1)- pos (Append (Right _)) = Begin- pos (Inside ls _ _) = Line $ length ls + 1- del (Append _) = Nothing- del (Inside [] _ [] ) = Just $ Append (Right []) - del (Inside ls _ [] ) = Just $ Append (Left ls) - del (Inside ls _ (r:rs)) = Just $ Inside ls r rs- deln n w | n == 0 = Just w- | True = del w >>= deln (n-1)- add xs (Append (Left _ )) = Nothing- add xs (Append (Right rs)) = Just $ Append $ Right (xs ++ rs)- add xs (Inside ls x rs) = Just $ Inside ls x (xs ++ rs) - ins xs w = prev w >>= add xs >>= next - jump n w = start w >>= rjump n - listOut w = start w >>= \(Append (Right rs)) -> return rs- linen 0 _ = Just []- linen _ (Append _) = Nothing- linen n w@ (Inside _ x _ ) = next w >>= linen (n - 1) >>= Just . (x:)- - tillend w = filter isInside (runner next w)-- fromstart w = reverse $ filter isInside (runner prev w)-- fwdcycle w = filter isInside $ runner next w ++ reverse (runner prev w) ++ [w]- bwdcycle w = filter isInside $ runner prev w ++ reverse (runner next w) ++ [w] --isInside :: InsideAppend -> Bool-isInside (Inside _ _ _) = True-isInside _ = False--runner :: Change InsideAppend -> InsideAppend -> [InsideAppend]-runner op w = maybe [] (\w -> (w : runner op w)) (op w)--prop_E1_IA = prop_E1 :: (W InsideAppend) -> String -> Bool ---prop_Empty_IA = prop_Empty :: -t = listIn ["paolo","va","in","bici"] :: InsideAppend
Editor.hs view
@@ -13,25 +13,25 @@ -- | Stato is parametrized on an Engine instance and hold the engine with the last regex entered , regex G and g are not implemented now-data Stato w = Stato {- file :: w, -- ^ data holding the file +data Stato = Stato {+ file :: Engine, -- ^ data holding the file lastre :: String, -- ^ a regex filename :: Maybe String, -- ^ the file we are editing pending :: Maybe Command, -- ^ a sensible state for data lost- lastsaved :: Maybe w+ lastsaved :: Maybe Engine } deriving (Show,Eq) zeroState = Stato empty "" Nothing Nothing Nothing--- | the core editor runs under the state monad with state (Stato w) .+-- | the core editor runs under the state monad with state (Stato) . -- Wrapped around a monad (IO mainly) to permit console input and output of commands with IO -- and testing with State-type StatoE m w = UndoT (Stato w) m+type StatoE m = UndoT Stato m -liftStatoE :: Ctx m w => StatoE m w a -> Editor m w a+liftStatoE :: Ctx m => StatoE m a -> Editor m a liftStatoE = lift -- | push a new file (data 'Engine' instance) in the core State, pushing the old state in the undo stack-hputfile :: Ctx m w => w -> Editor m w ()+hputfile :: Ctx m => Engine -> Editor m () hputfile x = get >>= \y -> liftStatoE $ hput y {file = x} putfile x = get >>= \y -> put y {file = x}@@ -45,8 +45,8 @@ -- | placeholder for the two constraints-class (Engine w , SIO m, HCtx m (Stato w) ) => Ctx m w -instance (Engine w , SIO m, HCtx m (Stato w) ) => Ctx m w +class (SIO m, HCtx m (Stato) ) => Ctx m +instance (SIO m, HCtx m (Stato) ) => Ctx m -- | the errors (monad failers) which can break the monad flow data Err @@ -86,7 +86,7 @@ -- the path for the command help file commandhelpSIO :: m FilePath -liftSio :: Ctx m w => m a -> Editor m w a+liftSio :: Ctx m => m a -> Editor m a liftSio = lift . lift -- | commands for the editor @@ -167,48 +167,48 @@ -- | main datatype for the program-- beyond the core state, a simulation layer 'SIO' can be read -- and errors 'Err' can be thrown to kill the monad flow-type Editor m w = ErrorT Err (StatoE m w)+type Editor m = ErrorT Err (StatoE m) -- | wrap a maybe action and throw a backend error on a Nothing -backend :: Ctx m w +backend :: Ctx m => Maybe a -- ^ maybe action- -> Editor m w a -- ^ monading + -> Editor m a -- ^ monading backend = maybe (throwError BackendErr) return -- | execute an action on the file-through :: Ctx m w- => (w -> Maybe a) -- ^ an action from an engine w to a maybe- -> Editor m w a -- ^ the result from Just in the Editor monad+through :: Ctx m+ => (Engine -> Maybe a) -- ^ an action from an engine w to a maybe+ -> Editor m a -- ^ the result from Just in the Editor monad through f = gets file >>= backend . f -- | the inputSio action lifted to Editor-pinput :: Ctx m w => String -> Editor m w (Maybe String) +pinput :: Ctx m => String -> Editor m (Maybe String) pinput = liftSio . inputSio -- | the inputSio action lifted to Editor with empty prompt-input :: Ctx m w => Editor m w (Maybe String)+input :: Ctx m => Editor m (Maybe String) input = pinput "" -- | the outputSio action lifted to Editor-output :: Ctx m w => String -> Editor m w () +output :: Ctx m => String -> Editor m () output = liftSio . outputSio -- | the historySIO action lifted to Editor -history :: Ctx m w => String -> Editor m w ()+history :: Ctx m => String -> Editor m () history = liftSio . historySio -- | the errorSIO action lifted to Editor-errorlog :: Ctx m w => String -> Editor m w ()+errorlog :: Ctx m => String -> Editor m () errorlog = liftSio . errorSIO -- | editor runner . -- resolve the all monad from a core state to another-run :: Ctx m w - => Editor m w a -- ^ the action to run- -> Stato w -- ^ the initial state - -> m (Stato w) -- ^ the final state wrapped in the monad choosen for the SIO+run :: Ctx m + => Editor m a -- ^ the action to run+ -> Stato -- ^ the initial state + -> m (Stato) -- ^ the final state wrapped in the monad choosen for the SIO run editor w = flip execUndoT w $ runErrorT editor >>= \x -> case x of Left err -> lift $ errorSIO (show err)
Engine.hs view
@@ -1,5 +1,4 @@--- | Abstraction on a "zipped" list. Use these instances to have a list cursored on a position, also --- called double linked list.+-- | A zipped list with special cursor at the ends. In fact it handles inserting at start and appending at end where the cursor is pointing to non existing lines. module Engine where import Test.QuickCheck@@ -30,93 +29,130 @@ distance Begin (End m) = m distance _ _ = 0 --- | the class to implement for holding a list of elements with a cursor on them-class Eq a => Engine a where- - -- | An empty engine- empty :: a - empty = listIn []- -- | An engine is isomorphic to a list- listIn :: [String] -> a - -- | Extract the list from the engine- listOut :: a -> Maybe [String] - -- | Extract n lines from the position addressed- linen :: Int -> a -> Maybe [String] - -- | Extract the addressed line- line :: a -> Maybe String - line w = head `fmap` linen 1 w- -- | Possibly set the addressed line to the nth line- jump :: Int -> Change a - -- | Insert some lines before the addressed line- ins :: [String] -> Change a - -- | Insert some lines after the addressed line- add :: [String] -> Change a - -- | Delete the addressed line , address the next one- del :: Change a - -- | Delete n lines from the addressed position- deln :: Int -> Change a - -- | Address an append position- end :: Change a - -- | Address before the first line- start :: Change a - -- | The number of the addressed line- pos :: a -> Pos - -- | Address the next line- next :: Change a - -- | Address the prev line- prev :: Change a - -- | Jump back n lines - prevn :: Int -> Change a - prevn 0 w = Just w - prevn n w = prev w >>= prevn (n-1) - -- | Jump ahead n lines- nextn :: Int -> Change a - nextn 0 w = Just w- nextn n w = next w >>= nextn (n-1) - -- | Jump n lines relative to the addredded line- rjump :: Int -> Change a - rjump n = iterateM n (if n > 0 then next else prev) where- iterateM n f w | n > 0 = f w >>= iterateM (n - 1) f- | True = Just w- -- | Create all the engines from the addressed one to the last one - tillend :: a -> [a]- -- | all the next engines from the addressed next to itself , wrapping around- fwdcycle :: a -> [a]- -- | Create all the engines from the start to the addressed one included- fromstart :: a -> [a]- -- | all the prev engines from the addressed prev to itself , wrapping around- bwdcycle :: a -> [a] +data Engine + -- | the cursor when its pointing to a real line (eg line function doesn't fail)+ = Inside {+ left :: [String], -- ^ lines before the cursor (reversed order)+ cursor ::String , -- ^ addressed line+ right :: [String] -- ^ lines after the cursor+ }+ -- | the cursor is pointing either to insert at the front of the file or + -- append at the end of the file.+ | Corner + { + elems :: Either [String] [String] -- ^ Left lines is in append mode, Right is in insert at front mode.+ }+ deriving (Show , Eq)+-- | An empty engine+empty :: Engine +empty = listIn []+-- | An engine is isomorphic to Engine list+listIn :: [String] -> Engine +-- | Extract the list from the engine+listOut :: Engine -> Maybe [String] +-- | Extract n lines from the position addressed+linen :: Int -> Engine -> Maybe [String] +-- | Extract the addressed line+line :: Engine -> Maybe String +line w = head `fmap` linen 1 w+-- | Possibly set the addressed line to the nth line+jump :: Int -> Change Engine +-- | Insert some lines before the addressed line+ins :: [String] -> Change Engine +-- | Insert some lines after the addressed line+add :: [String] -> Change Engine +-- | Delete the addressed line , address the next one+del :: Change Engine +-- | Delete n lines from the addressed position+deln :: Int -> Change Engine +-- | Address an append position+end :: Change Engine +-- | Address before the first line+start :: Change Engine +-- | The number of the addressed line+pos :: Engine -> Pos +-- | Address the next line+next :: Change Engine +-- | Address the prev line+prev :: Change Engine +-- | Jump back n lines +prevn :: Int -> Change Engine +prevn 0 w = Just w +prevn n w = prev w >>= prevn (n-1) +-- | Jump ahead n lines+nextn :: Int -> Change Engine +nextn 0 w = Just w+nextn n w = next w >>= nextn (n-1) +-- | Jump n lines relative to the addredded line+rjump :: Int -> Change Engine +rjump n = iterateM n (if n > 0 then next else prev) where+ iterateM n f w | n > 0 = f w >>= iterateM (n - 1) f+ | True = Just w+-- | Create all the engines from the addressed one to the last one +tillend :: Engine -> [Engine]+-- | all the next engines from the addressed next to itself , wrapping around+fwdcycle :: Engine -> [Engine]+-- | Create all the engines from the start to the addressed one included+fromstart :: Engine -> [Engine]+-- | all the prev engines from the addressed prev to itself , wrapping around+bwdcycle :: Engine -> [Engine]+ -- | last element if present-last :: Engine w => Change w+last :: Change Engine last t = end t >>= prev -- | first element if present-first :: Engine w => Change w+first :: Change Engine first t = start t >>= next -newtype W w = W w deriving Show-instance (Eq w,Engine w) => Arbitrary (W w) where- arbitrary = do n <- choose (0,10)- ws <- replicateM n $ replicateM 15 $ choose ('a','z')- return $ W $ listIn ws- coarbitrary = undefined -instance Arbitrary Char where- arbitrary = choose ('a','z')- coarbitrary = undefined +listIn xs = Corner (Right xs)+prev (Corner (Right _ )) = Nothing +prev (Corner (Left [] )) = error "empty Corner Left"+prev (Corner (Left (l:ls))) = Just $ Inside ls l [] +prev (Inside [] x ls) = Just $ Corner (Right (x:ls)) +prev (Inside (l:ls) x rs) = Just $ Inside ls l (x:rs) +next (Corner (Right [] )) = Nothing+next (Corner (Right (r:rs))) = Just $ Inside [] r rs +next (Corner (Left [] )) = error "empty Corner Left"+next (Corner (Left _ )) = Nothing+next (Inside ls x [] ) = Just $ Corner (Left (x:ls)) +next (Inside ls x (r:rs)) = Just $ Inside (x:ls) r rs +end w@ (Corner (Left _)) = Just w+end w = next w >>= end+start w@ (Corner (Right _)) = Just w+start w = prev w >>= start +pos (Corner (Left ls)) = End (length ls + 1)+pos (Corner (Right _)) = Begin+pos (Inside ls _ _) = Line $ length ls + 1+del (Corner _) = Nothing+del (Inside [] _ [] ) = Just $ Corner (Right []) +del (Inside ls _ [] ) = Just $ Corner (Left ls) +del (Inside ls _ (r:rs)) = Just $ Inside ls r rs+deln n w | n == 0 = Just w+ | True = del w >>= deln (n-1)+add xs (Corner (Left _ )) = Nothing+add xs (Corner (Right rs)) = Just $ Corner $ Right (xs ++ rs)+add xs (Inside ls x rs) = Just $ Inside ls x (xs ++ rs) +ins xs w = prev w >>= add xs >>= next +jump n w = start w >>= rjump n +listOut w = start w >>= \(Corner (Right rs)) -> return rs+linen 0 _ = Just []+linen _ (Corner _) = Nothing+linen n w@ (Inside _ x _ ) = next w >>= linen (n - 1) >>= Just . (x:) +tillend w = filter isInside (runner next w) +fromstart w = reverse $ filter isInside (runner prev w) -prop_E1 :: (Engine w) => W w -> String -> Bool-prop_E1 (W y) = \x -> (add [x] y >>= listOut) == Just (x:fromJust (listOut y))+fwdcycle w = filter isInside $ runner next w ++ reverse (runner prev w) ++ [w]+bwdcycle w = filter isInside $ runner prev w ++ reverse (runner next w) ++ [w] -propInOut f xs = Just $ listIn xs >>= f >>= listOut -prop_Empty (W y) = (y == empty) ==> prev y == Nothing && next y == Nothing-prop_toEnd (W y) = (y /= empty) ==> let Just ls = length `fmap` listOut y - in collect ls $ nextn (ls +1) y == end y && nextn ls y == (end y >>= prev)-prop_toEndAndBack (W y) = (y /= empty) ==> let Just ls = length `fmap` listOut y - in collect ls $ (end y >>= start) == Just y-prop_add (W y) xs = (add xs y >>= listOut) == Just xs ---prop_ins (W y) xs = (listIn xs >>= end >>= ins xs >>= listOut) == Just (head xs:head------ data Prop w = forall p . (Engine w) => Prop w (\w -> \p -> Property)+isInside :: Engine -> Bool+isInside (Inside _ _ _) = True+isInside _ = False++runner :: Change Engine -> Engine -> [Engine]+runner op w = maybe [] (\w -> (w : runner op w)) (op w)++
Eval.hs view
@@ -15,9 +15,9 @@ -- | every command is run with eval. See 'Editor.Command' datatype for docs-eval :: Ctx m w +eval :: Ctx m => CompleteCommand -- ^ the command to match for execution- -> Editor m w () -- ^ monading ..+ -> Editor m () -- ^ monading .. eval (CC Append (ORO o)) = inputMode >>= editOffset o . add@@ -67,17 +67,17 @@ bool x y b = if b then x else y -- | throw a 'writerSio' error to Editor-writefail :: Ctx m w => Either String () -> Editor m w ()+writefail :: Ctx m => Either String () -> Editor m () writefail = either (throwError . FileWriteErr) return -- | dump the engine content to a file via writefileSio-write :: Ctx m w +write :: Ctx m => String -- ^ filename- -> Editor m w () -- ^ monading+ -> Editor m () -- ^ monading write name = do contents <- unlines `fmap` through listOut (liftSio . runErrorT) (writefileSio name contents) >>= writefail setlastsaved -- | get the filename defaulting to some other action to produce one-getname :: Ctx m w => Editor m w String -> Editor m w String+getname :: Ctx m => Editor m String -> Editor m String getname defaul = gets filename >>= maybe defaul return
Hedi.cabal view
@@ -1,5 +1,5 @@ Name: Hedi-Version: 0.1+Version: 0.1.1 Cabal-Version: >= 1.2 Description: Haskell line editor. Cloned from ed manual. Category: Editor@@ -13,16 +13,16 @@ Library Exposed-Modules: Engine,Editor,Operation,Eval,Parser,Helper,Offset,- Main,Test,Buffer,Undo- Build-Depends: base,mtl,parsec,regex-posix,readline,QuickCheck,+ Main,Test,Undo+ Build-Depends: editline,base,mtl,parsec,regex-posix,QuickCheck, process,pretty Executable hedi- Build-Depends: base,mtl,parsec,regex-posix,readline,QuickCheck,+ Build-Depends: editline,base,mtl,parsec,regex-posix,QuickCheck, process,pretty Main-is: Main.hs other-modules: Engine,Editor,Operation,Eval,Parser,Helper,Offset,- Test,Buffer,Undo+ Test,Undo extensions: NoMonomorphismRestriction,MultiParamTypeClasses, FlexibleContexts,FlexibleInstances, GeneralizedNewtypeDeriving
Main.hs view
@@ -1,14 +1,13 @@ {-# LANGUAGE MultiParamTypeClasses,FlexibleInstances #-} module Main where -import System.Console.Readline+import System.Console.Editline.Readline import Control.Exception as Exc import System.Process import System.Exit import System.IO import Control.Monad.Error import Text.PrettyPrint (render,text,nest, (<>),(<+>),($$),sep)-import Buffer import Editor import Operation import Eval@@ -28,7 +27,9 @@ externalSio = externalCommand commandhelpSIO = getDataFileName "command.help" +handleWith :: (IOError -> k) -> IO a -> ErrorT k IO a handleWith h f = ErrorT $ Exc.catch (Right `fmap` f) (return . Left . h)+strictReadFile :: String -> IO String strictReadFile x = readFile x >>= \x -> Exc.evaluate (length x) >> return x -- |launches an external program , catching output and errors, return on exit@@ -46,7 +47,7 @@ greetings :: IO () greetings = putStrLn . render $ text "Hedi command line editor. " <> (- text "Version 0.1" $$+ text "Version 0.1.1" $$ text "Released under BSD licence." $$ text "Copyright 2008 Paolo Veronelli" $$ text "Homepage http://code.haskell.org/Hedi")@@ -57,6 +58,6 @@ main :: IO () main = do run (liftIO greetings >> commandLoop parse eval) - (Stato empty "" Nothing Nothing Nothing) :: IO (Stato InsideAppend)+ (Stato empty "" Nothing Nothing Nothing) return ()
Offset.hs view
@@ -1,4 +1,4 @@--- | Operations involving Offset and Range through Engine interface+-- | Operations involving Offset and Range through an Engine module Offset where import Text.Regex.Posix import Data.List (find)@@ -8,9 +8,9 @@ import Engine -- | move the cursor in the engine-jumpE :: Ctx m w +jumpE :: Ctx m => Offset -- ^ the new position for the cursor- -> Editor m w w -- ^ the modified engine under the Editor+ -> Editor m Engine -- ^ the modified engine under the Editor jumpE Current = through Just jumpE LastLine = through Engine.last @@ -26,9 +26,9 @@ finder f s = find ((=~ s) . fromJust . line) . f -- | From a range to the tuple (nelements,starting range element)-rangeResolve :: Ctx m w +rangeResolve :: Ctx m => Range -- ^ the range to focus- -> Editor m w (Int, w) -- ^ the tuple (nelements,engine placed+ -> Editor m (Int, Engine) -- ^ the tuple (nelements,engine placed -- at first offset of range) rangeResolve (Range o1 o2) = do w1 <- jumpE o1 @@ -36,32 +36,32 @@ return (distance (pos w1) (pos w2) , w1) -- | a complete backend + Editor action on an Offset-doOffset :: Ctx m w - => Offset -- ^ Offset for the action- -> (a -> Editor m w b) -- ^ the final action- -> ( w -> Maybe a) -- ^ the backend ation- -> Editor m w b -- ^ ..+doOffset :: Ctx m + => Offset -- ^ Offset for the action+ -> (a -> Editor m b) -- ^ the final action+ -> (Engine -> Maybe a) -- ^ the backend ation+ -> Editor m b -- ^ .. doOffset o ef mf = jumpE o >>= backend . mf >>= ef -- | a backend action ending in a save state for the file-editOffset :: Ctx m w - => Offset -- ^ Offset for the backend action- -> ( w -> Maybe w) -- ^ the backend ation- -> Editor m w () -- ^ modified monad+editOffset :: Ctx m + => Offset -- ^ Offset for the backend action+ -> (Engine -> Maybe Engine) -- ^ the backend ation+ -> Editor m () -- ^ modified monad editOffset o = doOffset o hputfile -- | a complete backend + Editor action on a Range-doRange :: Ctx m w- => Range -- ^ the addressed range- -> (a -> Editor m w b) -- ^ the closing Editor action- -> (Int -> w -> Maybe a) -- ^ the backend action - -> Editor m w b -- ^ ... +doRange :: Ctx m+ => Range -- ^ the addressed range+ -> (a -> Editor m b) -- ^ the closing Editor action+ -> (Int -> Engine -> Maybe a) -- ^ the backend action + -> Editor m b -- ^ ... doRange r ef mf = rangeResolve r >>= backend . uncurry mf >>= ef -editRange :: Ctx m w- => Range -- ^ the addressed range- -> (Int -> w -> Maybe w) -- ^ the backend action - -> Editor m w () -- ^ modified monad+editRange :: Ctx m+ => Range -- ^ the addressed range+ -> (Int -> Engine -> Maybe Engine) -- ^ the backend action + -> Editor m () -- ^ modified monad editRange r = doRange r hputfile
Operation.hs view
@@ -9,17 +9,17 @@ import Offset -- | a real check for file modification-modified :: Ctx m w => Editor m w Bool+modified :: Ctx m => Editor m Bool modified = do lastw <- gets lastsaved now <- gets file return $ maybe True (== now) lastw -resetpending :: Ctx m w => Editor m w ()+resetpending :: Ctx m => Editor m () resetpending = setpending Nothing -- | a wrapper for commands evaluation which can discard changes-evalSensible :: Ctx m w => Command -> Editor m w () -> Editor m w ()+evalSensible :: Ctx m => Command -> Editor m () -> Editor m () evalSensible c action = do mod <- modified if mod then @@ -30,7 +30,7 @@ else action >> resetpending -- | a wrapper for commands evaluation which cannot discard changes-checkPendings :: Ctx m w => Editor m w () -> Editor m w ()+checkPendings :: Ctx m => Editor m () -> Editor m () checkPendings action = do pends <- gets pending action @@ -39,10 +39,10 @@ -- | a step in main mode for the editor-commandMode :: Ctx m w +commandMode :: Ctx m => (String -> Either String CompleteCommand) -- ^ the parser for the command on the line- -> (CompleteCommand -> Editor m w ()) -- ^ the evaluator for the parsed command- -> Editor m w () -- ^ updated beast+ -> (CompleteCommand -> Editor m ()) -- ^ the evaluator for the parsed command+ -> Editor m () -- ^ updated beast commandMode parse eval = let parseval line = either (throwError . ParserErr ) ((history line >>). checkPendings . eval) @@ -56,10 +56,10 @@ in prompt >>= maybe (throwError StopErr) parseval -- | looping in main mode with error log on output-commandLoop :: Ctx m w +commandLoop :: Ctx m => (String -> Either String CompleteCommand) -- ^ the parser for the command on the line- -> (CompleteCommand -> Editor m w ()) -- ^ the evaluator for the parsed command- -> Editor m w () -- ^ updated beast+ -> (CompleteCommand -> Editor m ()) -- ^ the evaluator for the parsed command+ -> Editor m () -- ^ updated beast commandLoop parse eval = let reaction StopErr = errorlog "End" >> return False@@ -71,7 +71,7 @@ if run then commandLoop parse eval else return () -- | the secondary mode for the editor where lines are inserted as input. It returns the lines.Use CTRL-D to exit -inputMode :: Ctx m w => Editor m w [String] +inputMode :: Ctx m => Editor m [String] inputMode = input >>= maybe (aline "") aline where aline jl = case jl of "." -> return []
Test.hs view
@@ -7,7 +7,6 @@ import Control.Monad.Writer -import Buffer import Editor import Eval import Operation@@ -18,13 +17,13 @@ [ebuffer,eend] = ["Buffer index error","End"] -data Console = Console {+data Emulator = Emulator { cinput :: [Line], coutput :: [Line], cerror :: [Line], chistory:: [Line] } deriving Show-type CState = State Console+type CState = State Emulator outputT :: String -> CState () outputT x = modify (\y -> y{coutput = x:coutput y})@@ -47,8 +46,19 @@ externalSio = undefined commandhelpSIO = undefined -runT is os es hs = execState (run (commandLoop parse eval) zeroState :: CState (Stato InsideAppend)) (Console is os es hs)-test is mos mes mhs = let Console _ os es hs = runT is [] [] []- in maybe True (== os) mos && maybe True (== es) mes && maybe True (== hs) mhs+runT = execState (run (commandLoop parse eval) zeroState :: CState Stato)+--test is mos mes mhs = let Emulator _ os es hs = runT is [] [] []+ -- in maybe True (== os) mos && maybe True (== es) mes && maybe True (== hs) mhs +{-+tStrings xs field = Just $ (\e -> field e == reverse xs+type TestT = Maybe (Emulator -> Writer String Bool)++andTest :: Emulator -> [TestT] -> Writer [String] Bool+andTest _ [] = return True+andTest e (t:ts) = do s <- andTest e ts+ r <- maybe (return True) (t e) + return (r && s)+ loadFile x = readFile x >>= return . ("a" :) . lines+-}