module HsInspect.LSP.Util where import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Except (ExceptT(..)) import Data.List (intercalate) import qualified Data.List as L import System.Directory (listDirectory) import System.Environment (getEnvironment) import System.Exit (ExitCode(..)) import System.FilePath import qualified System.Log.Logger as L import qualified System.Process as P -- the first parent directory where a file or directory name matches the predicate locateDominatingDir :: (String -> Bool) -> FilePath -> IO (Maybe FilePath) locateDominatingDir p dir = do file' <- locateDominatingFile p dir pure $ takeDirectory <$> file' -- same as locateDominating but returns the first file that matches the predicate locateDominatingFile :: (String -> Bool) -> FilePath -> IO (Maybe FilePath) locateDominatingFile p dir = do files <- listDirectory dir let parent = takeDirectory dir case L.find p $ takeFileName <$> files of Just file -> pure . Just $ dir file Nothing -> if parent == dir then pure Nothing else locateDominatingFile p parent shell :: String -> [String] -> Maybe FilePath -> Maybe String -> [(String, String)] -> ExceptT String IO String shell command args cwd path env_extra = ExceptT $ do env <- getEnvironment let env' = maybe env (\p -> ("PATH", p) : env) path process = (P.proc command args) { P.env = Just (env_extra <> env') , P.cwd = cwd } liftIO $ L.debugM "haskell-lsp" $ "hsinspect-lsp:shell:" <> command <> " " <> intercalate " " args (code, stdout, stderr) <- P.readCreateProcessWithExitCode process "" case code of ExitFailure i -> pure . Left $ concat [ "exit code: ", show i , "\n stdout: ", stdout , "\n stderr: ", stderr ] ExitSuccess -> pure $ Right stdout