packages feed

ot 0.1.1.1 → 0.1.2

raw patch · 2 files changed

+68/−6 lines, 2 filesdep +HUnitdep +test-framework-hunitPVP ok

version bump matches the API change (PVP)

Dependencies added: HUnit, test-framework-hunit

API changes (from Hackage documentation)

+ Control.OperationalTransformation.Text: AugmentedTextOperation :: Cursor -> TextOperation -> AugmentedTextOperation
+ Control.OperationalTransformation.Text: Cursor :: Int -> Int -> Cursor
+ Control.OperationalTransformation.Text: augmentedCursor :: AugmentedTextOperation -> Cursor
+ Control.OperationalTransformation.Text: augmentedOperation :: AugmentedTextOperation -> TextOperation
+ Control.OperationalTransformation.Text: cursorPosition :: Cursor -> Int
+ Control.OperationalTransformation.Text: cursorSelectionEnd :: Cursor -> Int
+ Control.OperationalTransformation.Text: data AugmentedTextOperation
+ Control.OperationalTransformation.Text: data Cursor
+ Control.OperationalTransformation.Text: instance Eq AugmentedTextOperation
+ Control.OperationalTransformation.Text: instance Eq Cursor
+ Control.OperationalTransformation.Text: instance FromJSON AugmentedTextOperation
+ Control.OperationalTransformation.Text: instance FromJSON Cursor
+ Control.OperationalTransformation.Text: instance OTComposableOperation AugmentedTextOperation
+ Control.OperationalTransformation.Text: instance OTOperation AugmentedTextOperation
+ Control.OperationalTransformation.Text: instance OTSystem doc TextOperation => OTSystem doc AugmentedTextOperation
+ Control.OperationalTransformation.Text: instance Read AugmentedTextOperation
+ Control.OperationalTransformation.Text: instance Read Cursor
+ Control.OperationalTransformation.Text: instance Show AugmentedTextOperation
+ Control.OperationalTransformation.Text: instance Show Cursor
+ Control.OperationalTransformation.Text: instance ToJSON AugmentedTextOperation
+ Control.OperationalTransformation.Text: instance ToJSON Cursor
+ Control.OperationalTransformation.Text: updateCursor :: Cursor -> TextOperation -> Cursor

Files

ot.cabal view
@@ -1,9 +1,9 @@ Name:                ot-Version:             0.1.1.1+Version:             0.1.2 Synopsis:            Real-time collaborative editing with Operational Transformation -- A longer description of the package. -- Description:         -Homepage:            https://github.com/timjb/ot.hs+Homepage:            https://github.com/operational-transformation/ot.hs License:             MIT License-file:        LICENSE Author:              Tim Baumann@@ -44,9 +44,11 @@   main-is:             TestSuite.hs   Build-depends:       ot,                        QuickCheck,+                       HUnit,                        base,                        text,                        aeson,                        test-framework >= 0.6 && < 0.7,                        test-framework-quickcheck2 >= 0.2.12.2 && < 0.3,+                       test-framework-hunit >= 0.2.7 && < 0.3,                        binary >= 0.5.1.0
src/Control/OperationalTransformation/Text.hs view
@@ -1,20 +1,26 @@-{-# LANGUAGE OverloadedStrings, MultiParamTypeClasses, GeneralizedNewtypeDeriving, DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings, MultiParamTypeClasses, GeneralizedNewtypeDeriving, DeriveDataTypeable, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}  module Control.OperationalTransformation.Text-  ( Action (..)+  (+    -- * Simple text operations+    Action (..)   , TextOperation (..)   , invertOperation+    -- * Text operations augmented with cursor information+  , Cursor (..)+  , updateCursor+  , AugmentedTextOperation (..)   ) where  import Control.OperationalTransformation import qualified Data.Text as T import Data.Monoid (mappend)-import Data.Aeson (Value (..), FromJSON (..), ToJSON (..))+import Data.Aeson (Value (..), FromJSON (..), ToJSON (..), (.=), object, (.:)) import Data.Binary (Binary (..), putWord8, getWord8) import Data.Attoparsec.Number (Number (..)) import Data.Typeable (Typeable) import Data.Text (pack, unpack)-import Control.Applicative ((<$>))+import Control.Applicative ((<$>), (<*>))   -- | An action changes the text at the current position or advances the cursor.@@ -149,3 +155,57 @@                     in loop ops after (Insert before : inv)     loop [] "" inv = Right . TextOperation . reverse $ inv     loop [] _ _ = Left "invert failed: text is longer than the operation"++-- | A cursor has a 'cursorPosition' and a 'cursorSelectionEnd'. Both are+-- zero-based indexes into the document. When nothing is selected,+-- 'cursorSelectionEnd' is equal to 'cursorPosition'. When there is a selection,+-- 'cursorPosition' is always the side of the selection that would move if you+-- pressed an arrow key.+data Cursor = Cursor { cursorPosition, cursorSelectionEnd :: Int } deriving (Eq, Show, Read)++-- | Update cursor with respect to an operation.+updateCursor :: Cursor -> TextOperation -> Cursor+updateCursor (Cursor p s) (TextOperation actions) = Cursor transformedP transformedS+  where+    transformedP = transformComponent p+    transformedS = if p == s then transformedP else transformComponent s+    transformComponent c = loop c c actions+    loop oldIndex newIndex _ | oldIndex < 0 = newIndex+    loop _ newIndex [] = newIndex+    loop oldIndex newIndex (op:ops) = case op of+      Retain r -> loop (oldIndex-r) newIndex ops+      Insert i -> loop oldIndex (newIndex + T.length i) ops+      Delete d -> loop (oldIndex-d) (newIndex - min oldIndex d) ops++instance ToJSON Cursor where+  toJSON (Cursor p s) = object [ "position" .= p, "selectionEnd" .= s ]++instance FromJSON Cursor where+  parseJSON (Object o) = Cursor <$> o .: "position" <*> o .: "selectionEnd"+  parseJSON _ = fail "expected an object"++-- | An operation bundled with the cursor position after the operation.+data AugmentedTextOperation = AugmentedTextOperation+  { augmentedCursor    :: Cursor+  , augmentedOperation :: TextOperation+  } deriving (Eq, Show, Read)++instance ToJSON AugmentedTextOperation where+  toJSON (AugmentedTextOperation cursor textOp) = object [ "meta" .= cursor, "operation" .= textOp ]++instance FromJSON AugmentedTextOperation where+  parseJSON (Object o) = AugmentedTextOperation <$> o .: "meta" <*> o .: "operation"+  parseJSON _ = fail "expected an object"++instance OTOperation AugmentedTextOperation where+  transform (AugmentedTextOperation cursorA opA) (AugmentedTextOperation cursorB opB) = do+    (opA', opB') <- transform opA opB+    return ( AugmentedTextOperation (updateCursor cursorA opB') opA'+           , AugmentedTextOperation (updateCursor cursorB opA') opB'+           )++instance OTComposableOperation AugmentedTextOperation where+  compose (AugmentedTextOperation _ a) (AugmentedTextOperation cursor b) = AugmentedTextOperation cursor <$> compose a b++instance (OTSystem doc TextOperation) => OTSystem doc AugmentedTextOperation where+  apply (AugmentedTextOperation _ textOp) = apply textOp