2019-08-13 19:23:03 +03:00
|
|
|
-- Copyright (c) 2019 The DAML Authors. All rights reserved.
|
2019-05-20 18:36:08 +03:00
|
|
|
-- SPDX-License-Identifier: Apache-2.0
|
2019-09-07 17:23:14 +03:00
|
|
|
{-# OPTIONS_GHC -Wno-dodgy-imports #-} -- GHC no longer exports def in GHC 8.6 and above
|
2019-05-20 18:36:08 +03:00
|
|
|
|
2019-06-26 19:07:08 +03:00
|
|
|
module Main(main) where
|
2019-05-20 18:36:08 +03:00
|
|
|
|
2019-06-26 19:07:08 +03:00
|
|
|
import Arguments
|
2019-06-15 11:29:40 +03:00
|
|
|
import Data.Maybe
|
2019-06-26 19:07:08 +03:00
|
|
|
import Data.List.Extra
|
|
|
|
import System.FilePath
|
2019-05-20 18:36:08 +03:00
|
|
|
import Control.Concurrent.Extra
|
2019-06-26 19:07:08 +03:00
|
|
|
import Control.Monad.Extra
|
2019-06-26 11:04:10 +03:00
|
|
|
import Data.Default
|
2019-05-20 18:36:08 +03:00
|
|
|
import System.Time.Extra
|
2019-06-22 11:21:59 +03:00
|
|
|
import Development.IDE.Core.FileStore
|
2019-06-25 12:09:42 +03:00
|
|
|
import Development.IDE.Core.OfInterest
|
2019-06-22 11:21:59 +03:00
|
|
|
import Development.IDE.Core.Service
|
|
|
|
import Development.IDE.Core.Rules
|
|
|
|
import Development.IDE.Core.Shake
|
|
|
|
import Development.IDE.Core.RuleTypes
|
2019-06-22 00:19:07 +03:00
|
|
|
import Development.IDE.LSP.Protocol
|
|
|
|
import Development.IDE.Types.Location
|
2019-05-20 18:36:08 +03:00
|
|
|
import Development.IDE.Types.Diagnostics
|
|
|
|
import Development.IDE.Types.Options
|
2019-06-22 11:21:59 +03:00
|
|
|
import Development.IDE.Types.Logger
|
2019-06-28 14:47:45 +03:00
|
|
|
import qualified Data.Text as T
|
2019-05-20 18:36:08 +03:00
|
|
|
import qualified Data.Text.IO as T
|
2019-06-11 17:03:44 +03:00
|
|
|
import Language.Haskell.LSP.Messages
|
2019-08-15 16:27:26 +03:00
|
|
|
import Linker
|
2019-09-07 17:23:14 +03:00
|
|
|
import System.Info
|
|
|
|
import Data.Version
|
2019-06-14 12:02:04 +03:00
|
|
|
import Development.IDE.LSP.LanguageServer
|
2019-06-26 19:07:08 +03:00
|
|
|
import System.Directory.Extra as IO
|
2019-05-20 18:36:08 +03:00
|
|
|
import System.Environment
|
2019-06-15 11:29:40 +03:00
|
|
|
import System.IO
|
2019-05-20 18:36:08 +03:00
|
|
|
import Development.Shake hiding (Env)
|
|
|
|
import qualified Data.Set as Set
|
|
|
|
|
2019-06-15 11:29:40 +03:00
|
|
|
-- import CmdLineParser
|
|
|
|
-- import DynFlags
|
|
|
|
-- import Panic
|
2019-09-07 17:23:14 +03:00
|
|
|
import GHC hiding (def)
|
2019-06-14 17:11:32 +03:00
|
|
|
import qualified GHC.Paths
|
2019-05-20 18:36:08 +03:00
|
|
|
|
2019-06-15 11:29:40 +03:00
|
|
|
import HIE.Bios
|
|
|
|
|
2019-06-14 17:11:32 +03:00
|
|
|
-- Set the GHC libdir to the nix libdir if it's present.
|
|
|
|
getLibdir :: IO FilePath
|
|
|
|
getLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"
|
2019-05-20 18:36:08 +03:00
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
main = do
|
2019-06-14 17:23:22 +03:00
|
|
|
-- WARNING: If you write to stdout before runLanguageServer
|
|
|
|
-- then the language server will not work
|
2019-09-09 16:55:16 +03:00
|
|
|
hPutStrLn stderr $ "Starting ghcide (GHC v" ++ showVersion compilerVersion ++ ")"
|
2019-06-26 19:07:08 +03:00
|
|
|
Arguments{..} <- getArguments
|
|
|
|
|
2019-05-20 18:36:08 +03:00
|
|
|
-- lock to avoid overlapping output on stdout
|
|
|
|
lock <- newLock
|
2019-06-28 14:47:45 +03:00
|
|
|
let logger = Logger $ \pri msg -> withLock lock $
|
|
|
|
T.putStrLn $ T.pack ("[" ++ upper (show pri) ++ "] ") <> msg
|
2019-05-20 18:36:08 +03:00
|
|
|
|
2019-06-26 19:07:08 +03:00
|
|
|
whenJust argsCwd setCurrentDirectory
|
|
|
|
|
2019-06-15 11:29:40 +03:00
|
|
|
dir <- getCurrentDirectory
|
|
|
|
hPutStrLn stderr dir
|
|
|
|
|
2019-06-26 19:07:08 +03:00
|
|
|
if argLSP then do
|
|
|
|
t <- offsetTime
|
|
|
|
hPutStrLn stderr "Starting LSP server..."
|
2019-08-13 21:00:21 +03:00
|
|
|
runLanguageServer def def $ \event vfs caps -> do
|
2019-06-26 19:07:08 +03:00
|
|
|
t <- t
|
|
|
|
hPutStrLn stderr $ "Started LSP server in " ++ showDuration t
|
2019-08-13 21:00:21 +03:00
|
|
|
let options = (defaultIdeOptions $ liftIO $ newSession' =<< findCradle (dir <> "/"))
|
|
|
|
{ optReportProgress = clientSupportsProgress caps }
|
2019-06-14 17:23:22 +03:00
|
|
|
initialise (mainRule >> action kick) event logger options vfs
|
2019-06-13 19:21:27 +03:00
|
|
|
else do
|
2019-06-26 19:07:08 +03:00
|
|
|
putStrLn "[1/6] Finding hie-bios cradle"
|
|
|
|
cradle <- findCradle (dir <> "/")
|
|
|
|
print cradle
|
|
|
|
|
|
|
|
putStrLn "\n[2/6] Converting Cradle to GHC session"
|
|
|
|
env <- newSession' cradle
|
|
|
|
|
|
|
|
putStrLn "\n[3/6] Initialising IDE session"
|
2019-06-13 19:21:27 +03:00
|
|
|
vfs <- makeVFSHandle
|
2019-06-26 19:07:08 +03:00
|
|
|
ide <- initialise mainRule (showEvent lock) logger (defaultIdeOptions $ return env) vfs
|
|
|
|
|
|
|
|
putStrLn "\n[4/6] Finding interesting files"
|
|
|
|
files <- nubOrd <$> expandFiles (argFiles ++ ["." | null argFiles])
|
|
|
|
putStrLn $ "Found " ++ show (length files) ++ " files"
|
|
|
|
|
|
|
|
putStrLn "\n[5/6] Setting interesting files"
|
|
|
|
setFilesOfInterest ide $ Set.fromList $ map toNormalizedFilePath files
|
|
|
|
|
|
|
|
putStrLn "\n[6/6] Loading interesting files"
|
|
|
|
results <- runActionSync ide $ uses TypeCheck $ map toNormalizedFilePath files
|
|
|
|
let (worked, failed) = partition fst $ zip (map isJust results) files
|
|
|
|
putStrLn $ "Files that worked: " ++ show (length worked)
|
|
|
|
putStrLn $ "Files that failed: " ++ show (length failed)
|
|
|
|
putStr $ unlines $ map ((++) " * " . snd) failed
|
|
|
|
|
2019-06-13 19:21:27 +03:00
|
|
|
putStrLn "Done"
|
|
|
|
|
|
|
|
|
2019-06-26 19:07:08 +03:00
|
|
|
expandFiles :: [FilePath] -> IO [FilePath]
|
|
|
|
expandFiles = concatMapM $ \x -> do
|
|
|
|
b <- IO.doesFileExist x
|
|
|
|
if b then return [x] else do
|
|
|
|
let recurse "." = True
|
|
|
|
recurse x | "." `isPrefixOf` takeFileName x = False -- skip .git etc
|
|
|
|
recurse x = takeFileName x `notElem` ["dist","dist-newstyle"] -- cabal directories
|
|
|
|
files <- filter (\x -> takeExtension x `elem` [".hs",".lhs"]) <$> listFilesInside (return . recurse) x
|
|
|
|
when (null files) $
|
|
|
|
fail $ "Couldn't find any .hs/.lhs files inside directory: " ++ x
|
|
|
|
return files
|
|
|
|
|
|
|
|
|
2019-06-14 17:23:22 +03:00
|
|
|
kick :: Action ()
|
|
|
|
kick = do
|
2019-06-24 14:46:51 +03:00
|
|
|
files <- getFilesOfInterest
|
2019-06-14 17:23:22 +03:00
|
|
|
void $ uses TypeCheck $ Set.toList files
|
|
|
|
|
2019-05-20 18:36:08 +03:00
|
|
|
-- | Print an LSP event.
|
2019-06-11 17:03:44 +03:00
|
|
|
showEvent :: Lock -> FromServerMessage -> IO ()
|
|
|
|
showEvent _ (EventFileDiagnostics _ []) = return ()
|
2019-06-13 16:11:47 +03:00
|
|
|
showEvent lock (EventFileDiagnostics (toNormalizedFilePath -> file) diags) =
|
2019-05-20 18:36:08 +03:00
|
|
|
withLock lock $ T.putStrLn $ showDiagnosticsColored $ map (file,) diags
|
|
|
|
showEvent lock e = withLock lock $ print e
|
|
|
|
|
2019-06-15 11:29:40 +03:00
|
|
|
newSession' :: Cradle -> IO HscEnv
|
2019-08-15 16:27:26 +03:00
|
|
|
newSession' cradle = getLibdir >>= \libdir -> do
|
|
|
|
env <- runGhc (Just libdir) $ do
|
|
|
|
initializeFlagsWithCradle "" cradle
|
|
|
|
getSession
|
|
|
|
initDynLinker env
|
|
|
|
pure env
|