matchOnceEnd :: Regex -> Rope -> Maybe (Int, Int)
matchOnceEnd regex (R.Rope rope) = matchOnceEnd' [] rope F.empty
  where
    matchOnceEnd' matches rest rope
        | length matches > 1 || F.null rest =
            setOffset `fmap` (!0) `fmap` listToMaybe (reverse matches)
        | otherwise =
            let rest' :> chunk = F.viewr rest
                rope' = chunk <| rope
            in  matchOnceEnd' (matchAll regex $ R.Rope rope') rest' rope'
      where
        restLen = R.length (R.Rope rest)
        setOffset (offset, len) = (restLen + offset, len)
matchOnceEnd :: Regex -> Rope -> Maybe (Int, Int)
matchOnceEnd regex (R.Rope rope) = matchOnceEnd' [] rope F.empty
  where
    matchOnceEnd' matches rest rope
        | length matches > 1 || F.null rest =
            setOffset `fmap` (!0) `fmap` listToMaybe (reverse matches)
        | otherwise =
            let rest' :> chunk = F.viewr rest
                rope' = chunk <| rope
            in  matchOnceEnd' (matchAll regex $ R.Rope rope') rest' rope'
      where
        restLen = R.length (R.Rope rest)
        setOffset (offset, len) = (restLen + offset, len)
matchOnceEnd regex (R.Rope rope) = matchOnceEnd' [] rope F.empty
  where
    matchOnceEnd' matches rest rope
        | length matches > 1 || F.null rest =
            setOffset `fmap` (!0) `fmap` listToMaybe (reverse matches)
        | otherwise =
            let rest' :> chunk = F.viewr rest
                rope' = chunk <| rope
            in  matchOnceEnd' (matchAll regex $ R.Rope rope') rest' rope'
      where
        restLen = R.length (R.Rope rest)
        setOffset (offset, len) = (restLen + offset, len)