on master help sign in
Add a haskell-ide-core demo project (#1251)

* Demo program for haskell-ide-core as a library * Fix all warnings in the Demo file * Build the IDE demo * Give a better error message than undefined * HLint * Fix copyright header * Sort the dependencies * Improve the comment * Bazel formatting * Disable building on Windows until ghc-paths is fixed * Bazel formatting * Specify the main function

commita290aab6945aaf85dc3bebd47c864722c720d282 authorNeil Mitchell <35463327+neil-da@users.noreply.github.com> dateMon 20 May 2019, 16:36 (7 years ago) parent60f0177
5 files changed+265−1
.ghci+16 BUILD.bazel+24−1 haskell-ide-core.cabal+118 stack.yaml+3 test/Demo.hs+104
.ghcinew file+16
@@ -0,0 +1,16 @@
1+:set -ignore-package=ghc-lib -ignore-package=ghc-parser -package=ghc
2+:set -fwarn-unused-binds -fwarn-unused-imports -fwarn-orphans
3+:set -isrc -i../../libs-haskell/prettyprinter-syntax/src
4+:set -DGHC_STABLE
5+:set -XLambdaCase
6+:set -XBangPatterns
7+:set -XDeriveGeneric
8+:set -XRecordWildCards
9+:set -XScopedTypeVariables
10+:set -XNamedFieldPuns
11+:set -XTupleSections
12+:set -XTypeApplications
13+:set -XViewPatterns
14+:set -XGeneralizedNewtypeDeriving
15+:set -XStandaloneDeriving
16+:load test/Demo.hs
BUILD.bazel+24−1
@@ -1,7 +1,8 @@
11# Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22# SPDX-License-Identifier: Apache-2.0
33
4−load("//bazel_tools:haskell.bzl", "da_haskell_library")
4+load("//bazel_tools:haskell.bzl", "da_haskell_binary", "da_haskell_library")
5+load("@os_info//:os_info.bzl", "is_windows")
56
67depends = [
78 "aeson",
@@ -60,3 +61,25 @@ da_haskell_library(
6061 "//libs-haskell/prettyprinter-syntax",
6162 ],
6263)
64+
65+da_haskell_binary(
66+ name = "haskell-ide-core-demo",
67+ srcs = glob(["test/**/*.hs"]),
68+ hazel_deps = [
69+ "base",
70+ "containers",
71+ "extra",
72+ "filepath",
73+ "ghc-paths",
74+ "ghc",
75+ "shake",
76+ "text",
77+ ],
78+ main_function = "Demo.main",
79+ src_strip_prefix = "test",
80+ visibility = ["//visibility:public"],
81+ deps = [
82+ "haskell-ide-core-public",
83+ "//libs-haskell/prettyprinter-syntax",
84+ ],
85+) if not is_windows else None # Disable on Windows until ghc-paths is fixed upstream
haskell-ide-core.cabalnew file+118
@@ -0,0 +1,118 @@
1+cabal-version: >= 1.18
2+build-type: Simple
3+name: haskell-ide-core
4+version: 0
5+license: BSD3
6+x-license: BSD3 OR Apache2
7+author: Digital Asset
8+maintainer: Digital Asset
9+copyright: Digital Asset 2018-2019
10+synopsis: The core of an IDE
11+description:
12+ A library for building Haskell IDE's on top of the GHC API.
13+homepage: https://github.com/digital-asset/daml#readme
14+bug-reports: https://github.com/digital-asset/daml/issues
15+tested-with: GHC==8.6.5
16+
17+source-repository head
18+ type: git
19+ location: https://github.com/digital-asset/daml.git
20+
21+library
22+ default-language: Haskell2010
23+ build-depends:
24+ aeson,
25+ base == 4.*,
26+ binary,
27+ bytestring,
28+ containers,
29+ deepseq,
30+ directory,
31+ either,
32+ extra,
33+ filepath,
34+ ghc,
35+ ghc-boot-th,
36+ ghc-boot,
37+ hashable,
38+ haskell-lsp,
39+ haskell-lsp-types,
40+ mtl,
41+ pretty,
42+ safe-exceptions,
43+ shake,
44+ stm,
45+ syb,
46+ text,
47+ time,
48+ prettyprinter,
49+ prettyprinter-ansi-terminal,
50+ transformers,
51+ uniplate,
52+ unordered-containers,
53+ uri-encode
54+
55+ cpp-options: -DGHC_STABLE
56+ default-extensions:
57+ LambdaCase
58+ BangPatterns
59+ DeriveGeneric
60+ RecordWildCards
61+ ScopedTypeVariables
62+ NamedFieldPuns
63+ TupleSections
64+ TypeApplications
65+ ViewPatterns
66+ GeneralizedNewtypeDeriving
67+ StandaloneDeriving
68+
69+ hs-source-dirs:
70+ src
71+ ../../libs-haskell/prettyprinter-syntax/src
72+ exposed-modules:
73+ Development.IDE.Logger
74+ Development.IDE.UtilGHC
75+ Development.IDE.Functions.AtPoint
76+ Development.IDE.Functions.Compile
77+ Development.IDE.Functions.CPP
78+ Development.IDE.Orphans
79+ Development.IDE.Functions.DependencyInformation
80+ Development.IDE.Functions.Documentation
81+ Development.IDE.Functions.FindImports
82+ Development.IDE.Functions.GHCError
83+ Development.IDE.Functions.SpanInfo
84+ Development.IDE.Functions.Warnings
85+ Development.IDE.State.FileStore
86+ Development.IDE.State.Rules
87+ Development.IDE.Compat
88+ Development.IDE.Types.Options
89+ Development.IDE.State.RuleTypes
90+ Development.IDE.State.Service
91+ Development.IDE.State.Shake
92+ Development.IDE.Types.Diagnostics
93+ Development.IDE.Types.Location
94+ Development.IDE.Types.LSP
95+ Development.IDE.Types.SpanInfo
96+ other-modules:
97+ Data.Text.Prettyprint.Doc.Syntax
98+
99+executable ide-demo
100+ default-language: Haskell2010
101+ main-is: Demo.hs
102+ ghc-options: -main-is Demo.main
103+ build-depends:
104+ base == 4.*,
105+ filepath,
106+ containers,
107+ shake,
108+ ghc-paths,
109+ ghc,
110+ extra,
111+ text,
112+ haskell-ide-core
113+
114+ default-extensions:
115+ TupleSections
116+ RecordWildCards
117+
118+ hs-source-dirs: test
stack.yamlnew file+3
@@ -0,0 +1,3 @@
1+resolver: nightly-2019-05-20
2+packages:
3+- .
test/Demo.hsnew file+104
@@ -0,0 +1,104 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+module Demo(main) where
5+
6+import Control.Concurrent.Extra
7+import Control.Monad
8+import System.Time.Extra
9+import Development.IDE.State.Service
10+import Development.IDE.State.Rules
11+import Development.IDE.State.Shake
12+import Development.IDE.State.RuleTypes
13+import Development.IDE.Types.Diagnostics
14+import Development.IDE.Types.Options
15+import Development.IDE.Logger
16+import qualified Data.Text.IO as T
17+import System.Environment
18+import Data.List
19+import Data.Maybe
20+import System.FilePath
21+import Data.Tuple.Extra
22+import System.IO.Extra
23+import Development.IDE.Types.LSP
24+import Development.Shake hiding (Env)
25+import qualified Data.Set as Set
26+
27+import CmdLineParser
28+import DynFlags
29+import Panic
30+import GHC
31+import GHC.Paths
32+
33+
34+main :: IO ()
35+main = do
36+ (ghcOptions, files) <- getCmdLine
37+
38+ -- lock to avoid overlapping output on stdout
39+ lock <- newLock
40+
41+ ide <- initialise
42+ mainRule
43+ (Just $ showEvent lock)
44+ (makeOneHandle $ withLock lock . T.putStrLn)
45+ IdeOptions
46+ {optPreprocessor = (,) []
47+ ,optWriteIface = False
48+ ,optGhcSession = liftIO $ newSession ghcOptions
49+ ,optExtensions = ["hs"]
50+ ,optPkgLocationOpts = error "optPkgLocationOpts not implemented yet"
51+ ,optThreads = 0
52+ ,optShakeProfiling = Nothing -- Just "output.html"
53+ }
54+ setFilesOfInterest ide $ Set.fromList files
55+ _ <- runAction ide $ uses_ TypeCheck files
56+ -- shake now writes an async message that it is completed with timing info,
57+ -- so we sleep briefly to wait for it to have been written
58+ sleep 0.01
59+ putStrLn "Done"
60+
61+
62+-- | Print an LSP event.
63+showEvent :: Lock -> Event -> IO ()
64+showEvent _ (EventFileDiagnostics (_, [])) = return ()
65+showEvent lock (EventFileDiagnostics (file, diags)) =
66+ withLock lock $ T.putStrLn $ showDiagnosticsColored $ map (file,) diags
67+showEvent lock e = withLock lock $ print e
68+
69+
70+-- | Create a GHC session that will be subsequently reused.
71+newSession :: [String] -> IO HscEnv
72+newSession flags = runGhc (Just libdir) $ do
73+ damlDFlags <- getSessionDynFlags
74+ (dflags', leftover, warns) <- parseDynamicFlagsCmdLine damlDFlags $ map noLoc flags
75+
76+ let leftoverError = CmdLineError $
77+ (unlines . ("Unable to parse custom flags:":) . map unLoc) leftover
78+ unless (null leftover) $ liftIO $ throwGhcExceptionIO leftoverError
79+
80+ unless (null warns) $
81+ liftIO $ putStrLn $ unlines $ "Warnings:" : map (unLoc . warnMsg) warns
82+
83+ _ <- setSessionDynFlags dflags'
84+ getSession
85+
86+
87+-- | Convert the command line into GHC options and files to load.
88+getCmdLine :: IO ([String], [FilePath])
89+getCmdLine = do
90+ args <- getArgs
91+ args <- return $ if null args then [".ghci"] else args
92+ let (flags, files) = partition ("-" `isPrefixOf`) args
93+ let (ghci, hs) = partition ((==) ".ghci" . takeExtension) files
94+ (flags, files) <- both concat . unzip . ((flags,hs):) <$> mapM readGhci ghci
95+ when (null files) $
96+ fail "Expected some files to load, but didn't find any"
97+ return (flags, files)
98+
99+readGhci :: FilePath -> IO ([String], [FilePath])
100+readGhci file = do
101+ xs <- lines <$> readFileUTF8' file
102+ let flags = concatMap words $ mapMaybe (stripPrefix ":set ") xs
103+ let files = concatMap words $ mapMaybe (stripPrefix ":load ") xs
104+ return (flags, files)