packages feed

cornelis-0.2.0.0: test/Utils.hs

{-# LANGUAGE NumDecimals       #-}
{-# LANGUAGE OverloadedStrings #-}

module Utils
  ( module Utils
  , Edit (..)
  ) where

import           Control.Concurrent (threadDelay)
import           Cornelis.Types
import           Cornelis.Offsets
import           Cornelis.Utils (withLocalEnv)
import           Cornelis.Vim
import           Data.Foldable.Levenshtein (levenshtein, Edit(..))
import qualified Data.Text as T
import qualified Data.Vector as V
import           Lib
import           Neovim
import           Neovim.API.Text
import           Neovim.Test
import           Plugin
import           System.FilePath (takeBaseName)
import           System.IO (hFlush, hPutStr)
import           System.IO.Temp (withSystemTempFile)
import           Test.Hspec hiding (after, before)


-- data Diff a
--   = Insert a
--   | Delete a
--   | Modify a a
--   deriving (Eq, Ord, Show, Functor)

isCopy :: Edit a -> Bool
isCopy Copy{} = True
isCopy _ = False

diff :: Show a => Eq a => [a] -> [a] -> [Edit a]
diff = ((filter (not . isCopy) . snd) .) . levenshtein @_ @_ @_ @Int
  -- (snd .) . go
  -- where
  --   go ([]) as = (length as, fmap Insert as)
  --   go bs [] = (length bs, fmap Delete bs)
  --   go (b : bs) (a : as)
  --     | b == a = go bs as
  --     | otherwise = do
  --         let x = traceShowId $ bimap (+1) (Delete b :) $ go bs (a : as)
  --             y = traceShowId $ bimap (+1) (Insert a :) $ go (b : bs) as
  --             z = traceShowId $ bimap (+1) (Modify b a :) $ go bs as
  --         minimumBy (comparing fst) [z, x, y]


differing :: Buffer -> Neovim env () -> Neovim env [Edit Text]
differing b m = do
  before <- fmap V.toList $ buffer_get_lines b 0 (-1) False
  m
  liftIO $ threadDelay 1e6
  after <- fmap V.toList $ buffer_get_lines b 0 (-1) False
  pure $ diff before after


intervention :: Buffer -> [Edit Text] -> Neovim env () -> Neovim env ()
intervention b d m = do
  d' <- differing b m
  liftIO $ d' `shouldBe` d

withVim :: Seconds -> (Window -> Buffer -> Neovim () ()) -> IO ()
withVim secs m = do
  let withNeovimEmbedded f = testWithEmbeddedNeovim f secs ()
  withNeovimEmbedded Nothing $ do
    b <- nvim_create_buf False False
    w <- vim_get_current_window
    nvim_win_set_buf w b
    m w b


diffSpec
    :: String
    -> Seconds
    -> FilePath
    -> [Edit Text]
    -> (Window -> Buffer -> Neovim CornelisEnv ())
    -> Spec
diffSpec name secs fp diffs m =
  vimSpec name secs fp $ \w b -> intervention b diffs $ m w b


vimSpec
    :: String
    -> Seconds
    -> FilePath
    -> (Window -> Buffer -> Neovim CornelisEnv ())
    -> Spec
vimSpec name secs fp m = do
  let withNeovimEmbedded f = testWithEmbeddedNeovim f secs ()
  it name $ do
    withSystemTempFile "test.agda" $ \fp' h -> do
      hPutStr h $ "module " <> takeBaseName fp' <> " where\n"
      hPutStr h . unlines . tail . lines =<< readFile fp
      hFlush h
      withNeovimEmbedded Nothing $ do
        env <- cornelisInit
        withLocalEnv env $ do
          vim_command $ "edit " <> T.pack fp'
          liftIO $ threadDelay 1e6
          w <- vim_get_current_window
          b <- nvim_win_get_buf w
          load
          liftIO $ threadDelay 5e6
          m w b

goto :: Window -> Int -> Int -> Neovim env ()
goto w row col = setWindowCursor w $ Pos (toOneIndexed row) (toOneIndexed col)