module Ribosome.Api.Buffer where

import Data.MessagePack (Object)
import qualified Data.Text as Text (null)
import System.FilePath ((</>))

import Ribosome.Api.Atomic (atomicAs)
import Ribosome.Api.Path (nvimCwd)
import Ribosome.Control.Monad.Ribo (NvimE)
import Ribosome.Msgpack.Encode (toMsgpack)
import Ribosome.Msgpack.Error (DecodeError)
import Ribosome.Nvim.Api.Data (Buffer)
import qualified Ribosome.Nvim.Api.Data as ApiData (bufferGetName)
import Ribosome.Nvim.Api.IO (
  bufferGetLines,
  bufferGetName,
  bufferGetNumber,
  bufferGetOption,
  bufferIsValid,
  bufferSetLines,
  nvimWinSetBuf,
  vimCallFunction,
  vimCommand,
  vimGetBuffers,
  vimGetCurrentBuffer,
  vimGetCurrentWindow,
  )
import Ribosome.Nvim.Api.RpcCall (RpcError, syncRpcCall)

edit :: NvimE e m => FilePath -> m ()
edit :: FilePath -> m ()
edit FilePath
path = Text -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Text -> m ()
vimCommand (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Text
"silent! edit " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
forall a. ToText a => a -> Text
toText FilePath
path

nvimCallBool :: NvimE e m => Text -> [Object] -> m Bool
nvimCallBool :: Text -> [Object] -> m Bool
nvimCallBool =
  Text -> [Object] -> m Bool
forall (m :: * -> *) e a.
(Nvim m, MonadDeepError e RpcError m, MsgpackDecode a) =>
Text -> [Object] -> m a
vimCallFunction

buflisted :: NvimE e m => Buffer -> m Bool
buflisted :: Buffer -> m Bool
buflisted Buffer
buf = do
  Bool -> m Bool -> m Bool
forall e' e (m :: * -> *) a.
MonadDeepError e e' m =>
a -> m a -> m a
catchAs @RpcError Bool
False do
    Int
num <- Buffer -> m Int
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Buffer -> m Int
bufferGetNumber Buffer
buf
    Text -> [Object] -> m Bool
forall e (m :: * -> *). NvimE e m => Text -> [Object] -> m Bool
nvimCallBool Text
"buflisted" [Int -> Object
forall a. MsgpackEncode a => a -> Object
toMsgpack Int
num]

bufferContent :: NvimE e m => Buffer -> m [Text]
bufferContent :: Buffer -> m [Text]
bufferContent Buffer
buffer =
  Buffer -> Int -> Int -> Bool -> m [Text]
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Buffer -> Int -> Int -> Bool -> m [Text]
bufferGetLines Buffer
buffer Int
0 (-Int
1) Bool
False

currentBufferContent :: NvimE e m => m [Text]
currentBufferContent :: m [Text]
currentBufferContent =
  Buffer -> m [Text]
forall e (m :: * -> *). NvimE e m => Buffer -> m [Text]
bufferContent (Buffer -> m [Text]) -> m Buffer -> m [Text]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m Buffer
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m Buffer
vimGetCurrentBuffer

setBufferContent :: NvimE e m => Buffer -> [Text] -> m ()
setBufferContent :: Buffer -> [Text] -> m ()
setBufferContent Buffer
buffer =
  Buffer -> Int -> Int -> Bool -> [Text] -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Buffer -> Int -> Int -> Bool -> [Text] -> m ()
bufferSetLines Buffer
buffer Int
0 (-Int
1) Bool
False

setBufferLine :: NvimE e m => Buffer -> Int -> Text -> m ()
setBufferLine :: Buffer -> Int -> Text -> m ()
setBufferLine Buffer
buffer Int
line Text
text =
  Buffer -> Int -> Int -> Bool -> [Text] -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Buffer -> Int -> Int -> Bool -> [Text] -> m ()
bufferSetLines Buffer
buffer Int
line (Int
line Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Bool
False [Text
Item [Text]
text]

setCurrentBufferContent ::
  NvimE e m =>
  [Text] ->
  m ()
setCurrentBufferContent :: [Text] -> m ()
setCurrentBufferContent [Text]
content = do
  Buffer
buffer <- m Buffer
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m Buffer
vimGetCurrentBuffer
  Buffer -> [Text] -> m ()
forall e (m :: * -> *). NvimE e m => Buffer -> [Text] -> m ()
setBufferContent Buffer
buffer [Text]
content

withBufferNumber ::
  NvimE e m =>
  (Int -> m ()) ->
  Buffer ->
  m ()
withBufferNumber :: (Int -> m ()) -> Buffer -> m ()
withBufferNumber Int -> m ()
run Buffer
buffer =
  m Bool -> m () -> m ()
forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
whenM (Buffer -> m Bool
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Buffer -> m Bool
bufferIsValid Buffer
buffer) (Int -> m ()
run (Int -> m ()) -> m Int -> m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Buffer -> m Int
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Buffer -> m Int
bufferGetNumber Buffer
buffer)

closeBuffer ::
  NvimE e m =>
  Buffer ->
  m ()
closeBuffer :: Buffer -> m ()
closeBuffer =
  (Int -> m ()) -> Buffer -> m ()
forall e (m :: * -> *).
NvimE e m =>
(Int -> m ()) -> Buffer -> m ()
withBufferNumber Int -> m ()
forall (m :: * -> *) e a.
(Nvim m, MonadError e m, DeepPrisms e RpcError, Show a) =>
a -> m ()
del
  where
    del :: a -> m ()
del a
number =
      Text -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Text -> m ()
vimCommand (Text
"silent! bdelete! " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> a -> Text
forall b a. (Show a, IsString b) => a -> b
show a
number)

wipeBuffer ::
  NvimE e m =>
  Buffer ->
  m ()
wipeBuffer :: Buffer -> m ()
wipeBuffer =
  (Int -> m ()) -> Buffer -> m ()
forall e (m :: * -> *).
NvimE e m =>
(Int -> m ()) -> Buffer -> m ()
withBufferNumber Int -> m ()
forall (m :: * -> *) e a.
(Nvim m, MonadError e m, DeepPrisms e RpcError, Show a) =>
a -> m ()
wipe
  where
    wipe :: a -> m ()
wipe a
number =
      Text -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Text -> m ()
vimCommand (Text
"silent! bwipeout! " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> a -> Text
forall b a. (Show a, IsString b) => a -> b
show a
number)

unloadBuffer ::
  NvimE e m =>
  Buffer ->
  m ()
unloadBuffer :: Buffer -> m ()
unloadBuffer =
  (Int -> m ()) -> Buffer -> m ()
forall e (m :: * -> *).
NvimE e m =>
(Int -> m ()) -> Buffer -> m ()
withBufferNumber Int -> m ()
forall (m :: * -> *) e a.
(Nvim m, MonadError e m, DeepPrisms e RpcError, Show a) =>
a -> m ()
unload
  where
    unload :: a -> m ()
unload a
number =
      Text -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Text -> m ()
vimCommand (Text
"silent! bunload! " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> a -> Text
forall b a. (Show a, IsString b) => a -> b
show a
number)

addBuffer ::
  NvimE e m =>
  Text ->
  m ()
addBuffer :: Text -> m ()
addBuffer Text
path =
  Text -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Text -> m ()
vimCommand (Text
"badd " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
path)

buffersAndNames ::
  MonadIO m =>
  MonadDeepError e DecodeError m =>
  NvimE e m =>
  m [(Buffer, Text)]
buffersAndNames :: m [(Buffer, Text)]
buffersAndNames = do
  [Buffer]
buffers <- m [Buffer]
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m [Buffer]
vimGetBuffers
  [Text]
names <- [RpcCall] -> m [Text]
forall e (m :: * -> *) a.
(MonadDeepError e DecodeError m, MsgpackDecode a, NvimE e m) =>
[RpcCall] -> m [a]
atomicAs (SyncRpcCall -> RpcCall
syncRpcCall (SyncRpcCall -> RpcCall)
-> (Buffer -> SyncRpcCall) -> Buffer -> RpcCall
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Buffer -> SyncRpcCall
ApiData.bufferGetName (Buffer -> RpcCall) -> [Buffer] -> [RpcCall]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Buffer]
buffers)
  return ([Buffer] -> [Text] -> [(Buffer, Text)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Buffer]
buffers [Text]
names)

bufferForFile ::
  MonadIO m =>
  MonadDeepError e DecodeError m =>
  NvimE e m =>
  Text ->
  m (Maybe Buffer)
bufferForFile :: Text -> m (Maybe Buffer)
bufferForFile Text
target = do
  FilePath
cwd <- m FilePath
forall e (m :: * -> *). NvimE e m => m FilePath
nvimCwd
  ((Buffer, Text) -> Buffer) -> Maybe (Buffer, Text) -> Maybe Buffer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Buffer, Text) -> Buffer
forall a b. (a, b) -> a
fst (Maybe (Buffer, Text) -> Maybe Buffer)
-> ([(Buffer, Text)] -> Maybe (Buffer, Text))
-> [(Buffer, Text)]
-> Maybe Buffer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Buffer, Text) -> Bool)
-> [(Buffer, Text)] -> Maybe (Buffer, Text)
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (Buffer, Text) -> Bool
sameBuffer ([(Buffer, Text)] -> Maybe (Buffer, Text))
-> ([(Buffer, Text)] -> [(Buffer, Text)])
-> [(Buffer, Text)]
-> Maybe (Buffer, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Buffer, Text) -> (Buffer, Text))
-> [(Buffer, Text)] -> [(Buffer, Text)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Text -> Text) -> (Buffer, Text) -> (Buffer, Text)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (FilePath -> Text
forall a. ToText a => a -> Text
toText (FilePath -> Text) -> (Text -> FilePath) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath -> FilePath
absolute FilePath
cwd (FilePath -> FilePath) -> (Text -> FilePath) -> Text -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
forall a. ToString a => a -> FilePath
toString)) ([(Buffer, Text)] -> Maybe Buffer)
-> m [(Buffer, Text)] -> m (Maybe Buffer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m [(Buffer, Text)]
forall (m :: * -> *) e.
(MonadIO m, MonadDeepError e DecodeError m, NvimE e m) =>
m [(Buffer, Text)]
buffersAndNames
  where
    sameBuffer :: (Buffer, Text) -> Bool
sameBuffer (Buffer
_, Text
name) = Text
name Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
target
    absolute :: FilePath -> FilePath -> FilePath
absolute FilePath
dir (Char
'.' : Char
'/' : FilePath
rest) =
      FilePath
dir FilePath -> FilePath -> FilePath
</> FilePath
rest
    absolute FilePath
_ p :: FilePath
p@(Char
'/' : FilePath
_) =
      FilePath
p
    absolute FilePath
dir FilePath
path =
      FilePath
dir FilePath -> FilePath -> FilePath
</> FilePath
path

currentBufferName ::
  NvimE e m =>
  m Text
currentBufferName :: m Text
currentBufferName =
  Buffer -> m Text
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Buffer -> m Text
bufferGetName (Buffer -> m Text) -> m Buffer -> m Text
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m Buffer
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m Buffer
vimGetCurrentBuffer

setCurrentBuffer ::
  NvimE e m =>
  Buffer ->
  m ()
setCurrentBuffer :: Buffer -> m ()
setCurrentBuffer Buffer
buf = do
  Window
win <- m Window
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m Window
vimGetCurrentWindow
  Window -> Buffer -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Window -> Buffer -> m ()
nvimWinSetBuf Window
win Buffer
buf

bufferIsFile ::
  NvimE e m =>
  Buffer ->
  m Bool
bufferIsFile :: Buffer -> m Bool
bufferIsFile Buffer
buf =
  Text -> Bool
Text.null (Text -> Bool) -> m Text -> m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Buffer -> Text -> m Text
forall (m :: * -> *) e a.
(Nvim m, MonadDeepError e RpcError m, MsgpackDecode a) =>
Buffer -> Text -> m a
bufferGetOption Buffer
buf Text
"buftype"

bufferCount ::
  NvimE e m =>
  m Natural
bufferCount :: m Natural
bufferCount =
  Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Natural) -> ([Buffer] -> Int) -> [Buffer] -> Natural
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Buffer] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Buffer] -> Natural) -> m [Buffer] -> m Natural
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m [Buffer]
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m [Buffer]
vimGetBuffers