diff --git a/src/Yi/Rope.hs b/src/Yi/Rope.hs
--- a/src/Yi/Rope.hs
+++ b/src/Yi/Rope.hs
@@ -1,9 +1,11 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE ViewPatterns #-}
-{-# OPTIONS_HADDOCK show-extensions #-}
+{-# language BangPatterns #-}
+{-# language DeriveDataTypeable #-}
+{-# language LambdaCase #-}
+{-# language MultiParamTypeClasses #-}
+{-# language OverloadedStrings #-}
+{-# language ScopedTypeVariables #-}
+{-# language ViewPatterns #-}
+{-# options_haddock show-extensions #-}
 
 -- |
 -- Module      :  Yi.Rope
@@ -52,8 +54,7 @@
    Yi.Rope.replicate, Yi.Rope.replicateChar,
 
    -- * IO
-   ConverterName, unCn, Yi.Rope.readFile, Yi.Rope.writeFile,
-   Yi.Rope.writeFileUsingText, Yi.Rope.writeFileWithConverter,
+   Yi.Rope.readFile, Yi.Rope.writeFile,
 
    -- * Escape latches to underlying content. Note that these are safe
    -- to use but it does not mean they should.
@@ -61,25 +62,22 @@
 
   ) where
 
-
-import           Codec.Text.Detect (detectEncodingName)
 import           Control.DeepSeq
+import           Control.Exception (try)
 import           Data.Binary
-import qualified Data.ByteString as BS
 import qualified Data.ByteString.Lazy as BSL
 import           Data.Char (isSpace)
-import           Data.Default
 import qualified Data.FingerTree as T
 import           Data.FingerTree hiding (null, empty, reverse, split)
-import           Data.Function (fix)
 import qualified Data.List as L (foldl')
 import           Data.Maybe
 import           Data.Monoid
 import           Data.String (IsString(..))
 import qualified Data.Text as TX
-import qualified Data.Text.Encoding as TXE
-import           Data.Text.ICU.Convert
-import qualified Data.Text.IO as TF (writeFile)
+import qualified Data.Text.Encoding.Error as TXEE
+import qualified Data.Text.Lazy as TXL
+import qualified Data.Text.Lazy.Encoding as TXLE
+import qualified Data.Text.IO as TXIO (writeFile)
 import           Data.Typeable
 import           Prelude hiding (drop)
 
@@ -124,7 +122,7 @@
 instance Measured Size YiChunk where
   measure (Chunk l t) = Indices l (countNl t)
 
--- | A 'YiString' is a 'FingerTree' with cached column and line counts
+-- | A 'YiString' is a 'FingerTree' with cached char and line counts
 -- over chunks of 'TX.Text'.
 newtype YiString = YiString { fromRope :: FingerTree Size YiChunk }
                  deriving (Show, Typeable)
@@ -163,9 +161,6 @@
 instance Ord YiString where
   compare x y = toText x `compare` toText y
 
-instance Default YiString where
-  def = mempty
-
 (-|) :: YiChunk -> FingerTree Size YiChunk -> FingerTree Size YiChunk
 b -| t | chunkSize b == 0 = t
        | otherwise        = b <| t
@@ -240,6 +235,9 @@
 fromText :: TX.Text -> YiString
 fromText = fromText' defaultChunkSize
 
+fromLazyText :: TXL.Text -> YiString
+fromLazyText = YiString . T.fromList . fmap (mkChunk TX.length) . TXL.toChunks
+
 -- | Consider whether you really need to use this!
 toText :: YiString -> TX.Text
 toText = TX.concat . go . fromRope
@@ -365,12 +363,12 @@
 
 -- | Takes the first n given characters.
 take :: Int -> YiString -> YiString
-take 1 = maybe def Yi.Rope.singleton . Yi.Rope.head
+take 1 = maybe mempty Yi.Rope.singleton . Yi.Rope.head
 take n = fst . Yi.Rope.splitAt n
 
 -- | Drops the first n characters.
 drop :: Int -> YiString -> YiString
-drop 1 = fromMaybe def . Yi.Rope.tail
+drop 1 = fromMaybe mempty . Yi.Rope.tail
 drop n = snd . Yi.Rope.splitAt n
 
 -- | The usual 'Prelude.dropWhile' optimised for 'YiString's.
@@ -565,11 +563,26 @@
 
 -- | This is like 'lines'' but it does *not* preserve newlines.
 --
--- Implementation note: GHC does a pretty good job of optimizing
--- this naive version. Hand coding a loop should be unnecessary
--- here.
+-- Specifically, we just strip the newlines from the result of
+-- 'lines''.
+--
+-- This behaves slightly differently than the old split: the number of
+-- resulting strings here is equal to the number of newline characters
+-- in the underlying string. This is much more consistent than the old
+-- behaviour which blindly used @ByteString@s split and stitched the
+-- result back together which was inconsistent with the rest of the
+-- interface which worked with number of newlines.
 lines :: YiString -> [YiString]
-lines = fmap fromText . TX.lines . toText
+lines = Prelude.map dropNl . lines'
+  where
+    dropNl (YiString t)  = case viewr t of
+      EmptyR -> Yi.Rope.empty
+      ts :> ch@(Chunk l tx) ->
+        YiString $ ts |- if TX.null tx
+                         then ch
+                         else case TX.last tx of
+                           '\n' -> Chunk (l - 1) (TX.init tx)
+                           _ -> ch
 
 -- | Splits the 'YiString' into a list of 'YiString' each containing a
 -- line.
@@ -584,15 +597,13 @@
 --
 -- > 'toText' . 'concat' . 'lines'' ≡ 'toText'
 --
+-- but the underlying structure might change: notably, chunks will
+-- most likely change sizes.
 lines' :: YiString -> [YiString]
-lines' = splitByKeepingDelim '\n'
-
-splitByKeepingDelim :: Char -> YiString -> [YiString]
-splitByKeepingDelim x = fmap fromText . fix go x . toText
-  where
-    go :: (Char -> TX.Text -> [TX.Text]) -> Char -> TX.Text -> [TX.Text]
-    go _ c (TX.span (/=c) -> (_, TX.null -> True)) = []
-    go f c (TX.span (/=c) -> (a,b)) = a `TX.snoc` c : f c (TX.tail b)
+lines' t = let (YiString f, YiString s) = splitAtLine' 0 t
+           in if T.null s
+              then if T.null f then [] else [YiString f]
+              else YiString f : lines' (YiString s)
 
 -- | Joins up lines by a newline character. It does not leave a
 -- newline after the last line. If you want a more classical
@@ -629,60 +640,11 @@
   put = put . toString
   get = Yi.Rope.fromString <$> get
 
--- | 'ConverterName' is used to convey information about the
--- underlying 'Converter' used within the buffer to encode and decode
--- text. It is mostly here due to the lack of 'Binary' instance for
--- 'Converter' itself.
-newtype ConverterName = CN String deriving (Show, Eq, Ord, Read, Typeable)
-
--- | Returns the underlying string.
-unCn :: ConverterName -> String
-unCn (CN s) = s
-
--- | Simply 'put's/'get's the underlying 'String'.
-instance Binary ConverterName where
-  put (CN s) = put s
-  get = CN <$> get
-
--- | Writes the given 'YiString' to the given file, according to the
--- 'Converter' specified by 'ConverterName'. You can obtain a
--- 'ConverterName' through 'readFile'. If you have a 'Converter', use
--- 'writeFileWithConverter' instead.
---
--- If you don't care about the encoding used such as when creating a
--- brand new file, you can use 'writeFileUsingText'.
---
--- It's up to the user to handle exceptions.
---
--- Returns an error message if conversion failed, otherwise Nothing
--- on success.
-writeFile :: FilePath -> YiString -> ConverterName -> IO (Maybe TX.Text)
-writeFile f s (CN cn) = open cn (Just True) >>= writeFileWithConverter f s
-
--- | As 'writeFile' but using the provided 'Converter' rather than
--- creating one from a 'ConverterName'.
---
--- It's up to the user to handle exceptions.
-writeFileWithConverter :: FilePath -> YiString -> Converter -> IO (Maybe TX.Text)
-writeFileWithConverter f s c = do
-    let bytes = fromUnicode c $ toText s
-        errorMsg = "Could not encode text with specified encoding"
-    enc <- detectEncoding errorMsg $ BSL.fromChunks [bytes]
-    case enc of
-        Left err -> return $ Just err
-        Right (_, (CN cn)) -> do
-            if cn == getName c
-                then BS.writeFile f bytes >> return Nothing
-                else return . Just $ errorMsg
-
--- | Write a 'YiString' into the given file. This function uses
--- 'TF.writeFile' to do the writing: if you have special needs for
--- preserving encoding/decoding, use 'writeFile' instead.
+-- | Write a 'YiString' into the given file.
 --
 -- It's up to the user to handle exceptions.
-writeFileUsingText :: FilePath -> YiString -> IO ()
-writeFileUsingText f = TF.writeFile f . toText
-
+writeFile :: FilePath -> YiString -> IO ()
+writeFile f = TXIO.writeFile f . toText
 
 -- | Reads file into the rope, also returning the 'ConverterName' that
 -- was used for decoding. You should resupply this to 'writeFile' if
@@ -693,34 +655,22 @@
 --
 -- It is up to the user to handle exceptions not directly related to
 -- character decoding.
-readFile :: FilePath -> IO (Either TX.Text (YiString, ConverterName))
-readFile fp = BSL.readFile fp >>= detectEncoding err
-    where err = "Could not guess the encoding of " <> TX.pack fp
-
--- | Detects the encoding of a sequence of bytes.
---
--- Presumably the calculating the 'YiString' is lazy so it is fine
--- to use this to only get the converter name.
---
--- Also allows specification of the error to return if the encoding
--- of the bytes cannot be detected. The error returns won't necessarily
--- be this error - it is used only if no encoding name is detected at all.
-detectEncoding :: TX.Text -> BSL.ByteString
-               -> IO (Either TX.Text (YiString, ConverterName))
-detectEncoding err cs =
-  case detectEncodingName cs of
-   Nothing -> return $ case TXE.decodeUtf8' $ BSL.toStrict cs of
-      -- The detection failed but stay optimistic and try as UTF8 anyway.
-     Left _ -> Left err
-     Right tx -> Right (fromText tx, CN "UTF-8")
-   Just enc -> do
-     let ke = if enc == "ASCII" then Just "UTF-8" else listToMaybe $ aliases enc
-     case ke of
-      Nothing -> return . Left . TX.pack $ "Don't know how to decode as " <> enc
-      Just s -> do
-        c <- open s (Just True)
-        let st = BSL.toStrict cs
-        return $ Right (fromText $ toUnicode c st, CN $ getName c)
+readFile :: FilePath -> IO (Either TX.Text YiString)
+readFile fp = BSL.readFile fp >>= go decoders
+  where
+  go [] _ = pure (Left err)
+  go (d : ds) bytes =
+      try (pure (d bytes)) >>= \case
+          Left (_ :: TXEE.UnicodeException) -> go ds bytes
+          Right text -> pure (Right (fromLazyText text))
+  err = "Could not guess the encoding of " <> TX.pack fp
+  decoders =
+      [ TXLE.decodeUtf8
+      , TXLE.decodeUtf16LE
+      , TXLE.decodeUtf16BE
+      , TXLE.decodeUtf32LE
+      , TXLE.decodeUtf32BE
+      ]
 
 -- | Filters the characters from the underlying string.
 --
diff --git a/test/Yi/RopeSpec.hs b/test/Yi/RopeSpec.hs
--- a/test/Yi/RopeSpec.hs
+++ b/test/Yi/RopeSpec.hs
@@ -37,6 +37,8 @@
     prop "R.length ~ T.length" $ R.length `isLike` T.length
     prop "R.null ~ T.null" $ R.null `isLike` T.null
     prop "R.countNewLines ~ T.count \\n" $ R.countNewLines `isLike` T.count "\n"
+    prop "R.concat . R.lines' = id" $ (R.toText . R.concat . R.lines') `isLike` id
+    prop "R.lines ~ T.lines" $ (fmap R.toText . R.lines) `isLike` T.lines
     prop "R.empty ~ T.empty" $ R.toText R.empty `shouldBe` T.empty
     prop "fst . R.splitAt ~ fst . T.splitAt" $ \i ->
       fst . R.splitAt i `isLikeT` fst . T.splitAt i
diff --git a/yi-rope.cabal b/yi-rope.cabal
--- a/yi-rope.cabal
+++ b/yi-rope.cabal
@@ -1,5 +1,5 @@
 name:                yi-rope
-version:             0.9
+version:             0.10
 synopsis:            A rope data structure used by Yi
 description:         A rope data structure used by Yi
 license:             GPL-2
@@ -19,13 +19,10 @@
   build-depends:
       base >=4.8 && <5
     , binary
-    , bytestring
-    , charsetdetect-ae >= 1.0.1
-    , data-default
+    , bytestring >= 0.10
     , deepseq
-    , fingertree
-    , text
-    , text-icu
+    , fingertree >= 0.1.1
+    , text >= 1.2
 
   hs-source-dirs:      src
   default-language:    Haskell2010
