packages feed

ribosome-0.9.9.9: lib/Ribosome/Api/Window.hs

-- |API functions for windows.
module Ribosome.Api.Window where

import Ribosome.Data.WindowView (PartialWindowView, WindowView)
import Ribosome.Host.Api.Data (Window)
import Ribosome.Host.Api.Effect (
  nvimBufGetOption,
  nvimCallFunction,
  nvimCommand,
  nvimGetCurrentWin,
  nvimWinClose,
  nvimWinGetBuf,
  nvimWinGetCursor,
  nvimWinSetCursor,
  vimCallFunction,
  vimGetWindows,
  vimSetCurrentWindow,
  windowIsValid,
  )
import Ribosome.Host.Class.Msgpack.Encode (toMsgpack)
import Ribosome.Host.Effect.Rpc (Rpc)
import Ribosome.Host.Modify (silentBang)

-- |Close a window if it is valid and not the last one.
closeWindow ::
  Member Rpc r =>
  Window ->
  Sem r ()
closeWindow window = do
  valid <- windowIsValid window
  last' <- (1 ==) . length <$> vimGetWindows
  when (valid && not last') $ nvimWinClose window True

-- |Get the zero-based position of the cursor in a window.
cursor ::
  Member Rpc r =>
  Window ->
  Sem r (Int, Int)
cursor window = do
  (line, col) <- nvimWinGetCursor window
  pure (line - 1, col)

-- |Get the zero-based position of the cursor in the active window.
currentCursor ::
  Member Rpc r =>
  Sem r (Int, Int)
currentCursor =
  cursor =<< nvimGetCurrentWin

-- |Get the zero-based line number of the cursor in a window.
windowLine ::
  Member Rpc r =>
  Window ->
  Sem r Int
windowLine window =
  fst <$> cursor window

-- |Get the zero-based line number of the cursor in the active window.
currentLine ::
  Member Rpc r =>
  Sem r Int
currentLine =
  windowLine =<< nvimGetCurrentWin

-- |Set the zero-based position of the cursor in a window.
setCursor ::
  Member Rpc r =>
  Window ->
  Int ->
  Int ->
  Sem r ()
setCursor window line col =
  nvimWinSetCursor window (line + 1, col)

-- |Set the zero-based position of the cursor in the current window.
setCurrentCursor ::
  Member Rpc r =>
  Int ->
  Int ->
  Sem r ()
setCurrentCursor line col = do
  window <- nvimGetCurrentWin
  setCursor window line col

-- |Set the zero-based line number of the cursor in a window, using the beginning of the line for the column.
setLine ::
  Member Rpc r =>
  Window ->
  Int ->
  Sem r ()
setLine window line =
  setCursor window line 0

-- |Set the zero-based line number of the cursor in the current window, using the beginning of the line for the column.
setCurrentLine ::
  Member Rpc r =>
  Int ->
  Sem r ()
setCurrentLine line =
  setCurrentCursor line 0

-- |Redraw the screen.
redraw ::
  Member Rpc r =>
  Sem r ()
redraw =
  silentBang do
    nvimCommand "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 ::
  Member Rpc r =>
  Sem r (Maybe Window)
findMainWindow =
  listToMaybe <$> (filterM isFile =<< vimGetWindows)
  where
    isFile w = do
      buf <- nvimWinGetBuf w
      (("" :: Text) ==) <$> nvimBufGetOption buf "buftype"

-- |Create a new window at the top if no existing window has empty @buftype@.
-- Focuses the window.
ensureMainWindow ::
  Member Rpc r =>
  Sem r Window
ensureMainWindow =
  maybe create focus =<< findMainWindow
  where
    create = do
      nvimCommand "aboveleft new"
      nvimGetCurrentWin <* nvimCommand "wincmd K"
    focus w =
      w <$ vimSetCurrentWindow w

-- |Call @winsaveview@.
saveView ::
  Member Rpc r =>
  Sem r WindowView
saveView =
  vimCallFunction "winsaveview" []

-- |Call @winrestview@ with a previously obtained view from 'saveView'.
restoreView ::
  Member Rpc r =>
  PartialWindowView ->
  Sem r ()
restoreView v =
  vimCallFunction "winrestview" [toMsgpack v]

-- |Execute a command in a window.
windowExec ::
  Member Rpc r =>
  Window ->
  Text ->
  Sem r ()
windowExec window cmd =
  nvimCallFunction "win_execute" [toMsgpack window, toMsgpack cmd]