module Ribosome.Api.Window where

import Ribosome.Control.Monad.Ribo (NvimE)
import Ribosome.Nvim.Api.Data (Window)
import Ribosome.Nvim.Api.IO (
  nvimBufGetOption,
  nvimGetCurrentWin,
  nvimWinClose,
  nvimWinGetBuf,
  nvimWinGetCursor,
  nvimWinSetCursor,
  vimCommand,
  vimGetWindows,
  vimSetCurrentWindow,
  windowIsValid,
  )

closeWindow ::
  NvimE e m =>
  Window ->
  m ()
closeWindow :: Window -> m ()
closeWindow Window
window = do
  Bool
valid <- Window -> m Bool
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Window -> m Bool
windowIsValid Window
window
  Bool
last' <- (Int
1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
==) (Int -> Bool) -> ([Window] -> Int) -> [Window] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Window] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Window] -> Bool) -> m [Window] -> m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m [Window]
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m [Window]
vimGetWindows
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
valid Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
last') (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Window -> Bool -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Window -> Bool -> m ()
nvimWinClose Window
window Bool
True

cursor ::
  NvimE e m =>
  Window ->
  m (Int, Int)
cursor :: Window -> m (Int, Int)
cursor Window
window = do
  (Int
line, Int
col) <- Window -> m (Int, Int)
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Window -> m (Int, Int)
nvimWinGetCursor Window
window
  (Int, Int) -> m (Int, Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
line Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, Int
col)

currentCursor ::
  NvimE e m =>
  m (Int, Int)
currentCursor :: m (Int, Int)
currentCursor =
  Window -> m (Int, Int)
forall e (m :: * -> *). NvimE e m => Window -> m (Int, Int)
cursor (Window -> m (Int, Int)) -> m Window -> m (Int, Int)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m Window
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m Window
nvimGetCurrentWin

windowLine ::
  NvimE e m =>
  Window ->
  m Int
windowLine :: Window -> m Int
windowLine Window
window =
  (Int, Int) -> Int
forall a b. (a, b) -> a
fst ((Int, Int) -> Int) -> m (Int, Int) -> m Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Window -> m (Int, Int)
forall e (m :: * -> *). NvimE e m => Window -> m (Int, Int)
cursor Window
window

currentLine ::
  NvimE e m =>
  m Int
currentLine :: m Int
currentLine =
  Window -> m Int
forall e (m :: * -> *). NvimE e m => Window -> m Int
windowLine (Window -> m Int) -> m Window -> m Int
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m Window
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m Window
nvimGetCurrentWin

setCursor ::
  NvimE e m =>
  Window ->
  Int ->
  Int ->
  m ()
setCursor :: Window -> Int -> Int -> m ()
setCursor Window
window Int
line Int
col =
  Window -> (Int, Int) -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Window -> (Int, Int) -> m ()
nvimWinSetCursor Window
window (Int
line Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, Int
col)

setCurrentCursor ::
  NvimE e m =>
  Int ->
  Int ->
  m ()
setCurrentCursor :: Int -> Int -> m ()
setCurrentCursor Int
line Int
col = do
  Window
window <- m Window
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m Window
nvimGetCurrentWin
  Window -> Int -> Int -> m ()
forall e (m :: * -> *). NvimE e m => Window -> Int -> Int -> m ()
setCursor Window
window Int
line Int
col

setLine ::
  NvimE e m =>
  Window ->
  Int ->
  m ()
setLine :: Window -> Int -> m ()
setLine Window
window Int
line =
  Window -> Int -> Int -> m ()
forall e (m :: * -> *). NvimE e m => Window -> Int -> Int -> m ()
setCursor Window
window Int
line Int
0

setCurrentLine ::
  NvimE e m =>
  Int ->
  m ()
setCurrentLine :: Int -> m ()
setCurrentLine Int
line =
  Int -> Int -> m ()
forall e (m :: * -> *). NvimE e m => Int -> Int -> m ()
setCurrentCursor Int
line Int
0

redraw ::
  NvimE e m =>
  m ()
redraw :: m ()
redraw =
  Text -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Text -> m ()
vimCommand Text
"silent! redraw!"

-- |A main window means here any non-window that may be used to edit a file, i.e. one with an empty 'buftype'.
findMainWindow ::
  NvimE e m =>
  m (Maybe Window)
findMainWindow :: m (Maybe Window)
findMainWindow =
  [Window] -> Maybe Window
forall a. [a] -> Maybe a
listToMaybe ([Window] -> Maybe Window) -> m [Window] -> m (Maybe Window)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((Window -> m Bool) -> [Window] -> m [Window]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM Window -> m Bool
forall e (m :: * -> *).
(MonadError e m, Nvim m, DeepPrisms e RpcError) =>
Window -> m Bool
isFile ([Window] -> m [Window]) -> m [Window] -> m [Window]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m [Window]
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m [Window]
vimGetWindows)
  where
    isFile :: Window -> m Bool
isFile Window
w = do
      Buffer
buf <- Window -> m Buffer
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Window -> m Buffer
nvimWinGetBuf Window
w
      ((Text
"" :: Text) Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
==) (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
nvimBufGetOption Buffer
buf Text
"buftype"

-- |Create a new window at the top if no existing window has empty 'buftype'.
-- Focuses the window.
ensureMainWindow ::
  NvimE e m =>
  m Window
ensureMainWindow :: m Window
ensureMainWindow =
  m Window -> (Window -> m Window) -> Maybe Window -> m Window
forall b a. b -> (a -> b) -> Maybe a -> b
maybe m Window
create Window -> m Window
forall (f :: * -> *) e.
(Nvim f, MonadError e f, DeepPrisms e RpcError) =>
Window -> f Window
focus (Maybe Window -> m Window) -> m (Maybe Window) -> m Window
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m (Maybe Window)
forall e (m :: * -> *). NvimE e m => m (Maybe Window)
findMainWindow
  where
    create :: m Window
create = do
      Text -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Text -> m ()
vimCommand Text
"aboveleft new"
      Window
win <- m Window
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
m Window
nvimGetCurrentWin
      Text -> m ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Text -> m ()
vimCommand Text
"wincmd K"
      return Window
win
    focus :: Window -> f Window
focus Window
w =
      Window
w Window -> f () -> f Window
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Window -> f ()
forall (m :: * -> *) e.
(Nvim m, MonadDeepError e RpcError m) =>
Window -> m ()
vimSetCurrentWindow Window
w