module Chromatin.Run( runRplugin, RunRpluginResult(..), pypiPluginPackage, ) where import Control.Monad.IO.Class (liftIO) import Data.List.Split (linesBy) import Data.MessagePack (Object) import UnliftIO.Exception (catch) import System.FilePath (()) import qualified System.FilePath.Glob as Glob (globDir1, compile) import Neovim (NeovimException, toObject, fromObject', vim_call_function') import qualified Neovim as NeovimException (NeovimException(ErrorMessage, ErrorResult)) import qualified Data.Map as Map (fromList) import Chromatin.Data.Rplugin (Rplugin(Rplugin)) import Chromatin.Data.RpluginName (RpluginName(RpluginName)) import Chromatin.Data.ActiveRplugin (ActiveRplugin(ActiveRplugin)) import Chromatin.Data.RpluginSource (RpluginSource(Stack, Pypi)) import Chromatin.Data.Chromatin (Chromatin) import Chromatin.Rebuild.Build (venvDir) data RunRpluginResult = Success ActiveRplugin | Failure [String] deriving (Show, Eq) jobstartFailure :: NeovimException -> Either String a jobstartFailure (NeovimException.ErrorMessage doc) = Left (show doc) jobstartFailure (NeovimException.ErrorResult obj) = Left (show obj) unsafeJobstart :: [Object] -> Chromatin Int unsafeJobstart args = do result <- vim_call_function' "jobstart" args fromObject' result jobstart :: [Object] -> Chromatin (Either String Int) jobstart args = catch (Right <$> unsafeJobstart args) (return . jobstartFailure) runRpluginStack :: RpluginName -> FilePath -> Chromatin (Either String Int) runRpluginStack (RpluginName name) path = do let opts = Map.fromList [("cwd", toObject path), ("rpc", toObject True)] jobstart [toObject $ "stack exec " ++ name, toObject opts] pypiPluginExecutable :: RpluginName -> Chromatin FilePath pypiPluginExecutable name = do dir <- venvDir name return $ dir "bin" "ribosome_start_plugin" pypiSiteDir :: RpluginName -> Chromatin (Maybe FilePath) pypiSiteDir name = do venv <- venvDir name matches <- liftIO $ Glob.globDir1 (Glob.compile "python3.?") (venv "lib") return $ case matches of dir : _ -> Just $ dir "site-packages" _ -> Nothing pypiPluginPackage :: RpluginName -> Chromatin (Maybe FilePath) pypiPluginPackage rpluginName@(RpluginName name) = do dir <- pypiSiteDir rpluginName return $ fmap ( name) dir runRpluginPypi :: RpluginName -> Chromatin (Either String Int) runRpluginPypi rpluginName@(RpluginName name) = do dir <- venvDir rpluginName let exe = dir "bin" "python" let opts = Map.fromList [("rpc", toObject True)] start <- pypiPluginExecutable rpluginName mayPackage <- pypiPluginPackage rpluginName case mayPackage of Just package -> jobstart [toObject [toObject exe, toObject start, toObject package], toObject opts] Nothing -> return $ Left $ "no `lib/python` directory in virtualenv for `" ++ name ++ "`" runRplugin' :: RpluginName -> RpluginSource -> Chromatin (Either String Int) runRplugin' name (Stack path) = runRpluginStack name path runRplugin' name (Pypi _) = runRpluginPypi name runRplugin' _ _ = return (Left "NI") runRplugin :: Rplugin -> Chromatin RunRpluginResult runRplugin rplugin@(Rplugin name source) = do result <- runRplugin' name source return $ case result of Right channelId -> Success (ActiveRplugin channelId rplugin) Left err -> Failure (linesBy (=='\n') err)