git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge pull request #2305 from kRITZCREEK/psc-ide-ast-information-completion
c993ec2Phil Freeman
psc-ide-server/PROTOCOL.md+13−22
@@ -51,27 +51,7 @@ definition position, if it can be found in the passed source files.
51```
51```
52
52
53**Result:**
53**Result:**
54−The possible types are returned in the same format as completions + eventual position information
54+The possible types are returned in the same format as completions
55−```json
56−[
57− {
58− "module": "Data.Array",
59− "identifier": "filter",
60− "type": "forall a. (a -> Boolean) -> Array a -> Array a"
61− },
62− {
63− "module": "Data.Array",
64− "identifier": "filter",
65− "type": "forall a. (a -> Boolean) -> Array a -> Array a",
66− "definedAt":
67− {
68− "name": "/path/to/file",
69− "start": [1, 3],
70− "end": [3, 1]
71− }
72− }
73−]
74−```
75
55
76### Complete
56### Complete
77The `complete` command looks up possible completions/corrections.
57The `complete` command looks up possible completions/corrections.
@@ -104,12 +84,23 @@ The `complete` command looks up possible completions/corrections.
104
84
105The following format is returned as the Result:
85The following format is returned as the Result:
106
86
87+Both the `definedAt` aswell as the `documentation` field might be `null` if they
88+couldn't be extracted from a source file.
89+
107```json
90```json
108[
91[
109 {
92 {
110 "module": "Data.Array",
93 "module": "Data.Array",
111 "identifier": "filter",
94 "identifier": "filter",
112− "type": "forall a. (a -> Boolean) -> Array a -> Array a"
95+ "type": "forall a. (a -> Boolean) -> Array a -> Array a",
96+ "expandedType": "forall a. (a -> Boolean) -> Array a -> Array a",
97+ "definedAt":
98+ {
99+ "name": "/path/to/file",
100+ "start": [1, 3],
101+ "end": [3, 1]
102+ },
103+ "documentation": "A filtering function"
113 }
104 }
114]
105]
115```
106```
src/Language/PureScript/Ide.hs+6−6
@@ -38,9 +38,9 @@ import Language.PureScript.Ide.SourceFile
38import Language.PureScript.Ide.State
38import Language.PureScript.Ide.State
39import Language.PureScript.Ide.Types
39import Language.PureScript.Ide.Types
40import Language.PureScript.Ide.Util
40import Language.PureScript.Ide.Util
41−import System.Directory
41+import System.Directory (getCurrentDirectory, getDirectoryContents, doesDirectoryExist, doesFileExist)
42−import System.FilePath
42+import System.FilePath ((</>))
43−import System.FilePath.Glob
43+import System.FilePath.Glob (glob)
44
44
45-- | Accepts a Commmand and runs it against psc-ide's State. This is the main
45-- | Accepts a Commmand and runs it against psc-ide's State. This is the main
46-- entry point for the server.
46-- entry point for the server.
@@ -77,7 +77,7 @@ handleCommand c = case c of
77 case rs of
77 case rs of
78 Right rs' -> answerRequest outfp rs'
78 Right rs' -> answerRequest outfp rs'
79 Left question ->
79 Left question ->
80− pure (CompletionResult (map completionFromMatch question))
80+ pure (CompletionResult (map (completionFromMatch . map withEmptyAnn) question))
81 Rebuild file ->
81 Rebuild file ->
82 rebuildFile file
82 rebuildFile file
83 Cwd ->
83 Cwd ->
@@ -88,7 +88,7 @@ handleCommand c = case c of
88 liftIO exitSuccess
88 liftIO exitSuccess
89
89
90findCompletions :: Ide m =>
90findCompletions :: Ide m =>
91− [Filter] -> Matcher IdeDeclaration -> Maybe P.ModuleName -> m Success
91+ [Filter] -> Matcher IdeDeclarationAnn -> Maybe P.ModuleName -> m Success
92findCompletions filters matcher currentModule = do
92findCompletions filters matcher currentModule = do
93 modules <- getAllModules currentModule
93 modules <- getAllModules currentModule
94 pure . CompletionResult . map completionFromMatch . getCompletions filters matcher $ modules
94 pure . CompletionResult . map completionFromMatch . getCompletions filters matcher $ modules
@@ -97,7 +97,7 @@ findType :: Ide m =>
97 Text -> [Filter] -> Maybe P.ModuleName -> m Success
97 Text -> [Filter] -> Maybe P.ModuleName -> m Success
98findType search filters currentModule = do
98findType search filters currentModule = do
99 modules <- getAllModules currentModule
99 modules <- getAllModules currentModule
100− pure . InfoResult . map infoFromMatch . getExactMatches search filters $ modules
100+ pure . CompletionResult . map completionFromMatch . getExactMatches search filters $ modules
101
101
102findPursuitCompletions :: MonadIO m =>
102findPursuitCompletions :: MonadIO m =>
103 PursuitQuery -> m Success
103 PursuitQuery -> m Success
src/Language/PureScript/Ide/Command.hs+1−1
@@ -34,7 +34,7 @@ data Command
34 }
34 }
35 | Complete
35 | Complete
36 { completeFilters :: [Filter]
36 { completeFilters :: [Filter]
37− , completeMatcher :: Matcher IdeDeclaration
37+ , completeMatcher :: Matcher IdeDeclarationAnn
38 , completeCurrentModule :: Maybe P.ModuleName
38 , completeCurrentModule :: Maybe P.ModuleName
39 }
39 }
40 | Pursuit
40 | Pursuit
src/Language/PureScript/Ide/Completion.hs+7−8
@@ -9,24 +9,23 @@ import Protolude
9import Language.PureScript.Ide.Filter
9import Language.PureScript.Ide.Filter
10import Language.PureScript.Ide.Matcher
10import Language.PureScript.Ide.Matcher
11import Language.PureScript.Ide.Types
11import Language.PureScript.Ide.Types
12−import Language.PureScript.Ide.Util
13
12
14-- | Applies the CompletionFilters and the Matcher to the given Modules
13-- | Applies the CompletionFilters and the Matcher to the given Modules
15-- and sorts the found Completions according to the Matching Score
14-- and sorts the found Completions according to the Matching Score
16getCompletions
15getCompletions
17 :: [Filter]
16 :: [Filter]
18− -> Matcher IdeDeclaration
17+ -> Matcher IdeDeclarationAnn
19 -> [Module]
18 -> [Module]
20− -> [Match IdeDeclaration]
19+ -> [Match IdeDeclarationAnn]
21getCompletions filters matcher modules =
20getCompletions filters matcher modules =
22− runMatcher matcher (completionsFromModules discardAnn (applyFilters filters modules))
21+ runMatcher matcher (completionsFromModules (applyFilters filters modules))
23
22
24getExactMatches :: Text -> [Filter] -> [Module] -> [Match IdeDeclarationAnn]
23getExactMatches :: Text -> [Filter] -> [Module] -> [Match IdeDeclarationAnn]
25getExactMatches search filters modules =
24getExactMatches search filters modules =
26− completionsFromModules identity (applyFilters (equalityFilter search : filters) modules)
25+ completionsFromModules (applyFilters (equalityFilter search : filters) modules)
27
26
28−completionsFromModules :: (IdeDeclarationAnn -> a) -> [Module] -> [Match a]
27+completionsFromModules :: [Module] -> [Match IdeDeclarationAnn]
29−completionsFromModules f = foldMap completionFromModule
28+completionsFromModules = foldMap completionFromModule
30 where
29 where
31 completionFromModule (moduleName, decls) =
30 completionFromModule (moduleName, decls) =
32− map (\x -> Match (moduleName, f x)) decls
31+ map (\x -> Match (moduleName, x)) decls
src/Language/PureScript/Ide/Matcher.hs+8−8
@@ -38,7 +38,7 @@ type ScoredMatch a = (Match a, Double)
38
38
39newtype Matcher a = Matcher (Endo [Match a]) deriving (Monoid)
39newtype Matcher a = Matcher (Endo [Match a]) deriving (Monoid)
40
40
41−instance FromJSON (Matcher IdeDeclaration) where
41+instance FromJSON (Matcher IdeDeclarationAnn) where
42 parseJSON = withObject "matcher" $ \o -> do
42 parseJSON = withObject "matcher" $ \o -> do
43 (matcher :: Maybe Text) <- o .:? "matcher"
43 (matcher :: Maybe Text) <- o .:? "matcher"
44 case matcher of
44 case matcher of
@@ -60,17 +60,17 @@ instance FromJSON (Matcher IdeDeclaration) where
60-- Examples:
60-- Examples:
61-- flMa matches flexMatcher. Score: 14.28
61-- flMa matches flexMatcher. Score: 14.28
62-- sons matches sortCompletions. Score: 6.25
62-- sons matches sortCompletions. Score: 6.25
63−flexMatcher :: Text -> Matcher IdeDeclaration
63+flexMatcher :: Text -> Matcher IdeDeclarationAnn
64flexMatcher p = mkMatcher (flexMatch p)
64flexMatcher p = mkMatcher (flexMatch p)
65
65
66−distanceMatcher :: Text -> Int -> Matcher IdeDeclaration
66+distanceMatcher :: Text -> Int -> Matcher IdeDeclarationAnn
67distanceMatcher q maxDist = mkMatcher (distanceMatcher' q maxDist)
67distanceMatcher q maxDist = mkMatcher (distanceMatcher' q maxDist)
68
68
69−distanceMatcher' :: Text -> Int -> [Match IdeDeclaration] -> [ScoredMatch IdeDeclaration]
69+distanceMatcher' :: Text -> Int -> [Match IdeDeclarationAnn] -> [ScoredMatch IdeDeclarationAnn]
70distanceMatcher' q maxDist = mapMaybe go
70distanceMatcher' q maxDist = mapMaybe go
71 where
71 where
72 go m = let d = dist (T.unpack y)
72 go m = let d = dist (T.unpack y)
73− y = identifierFromIdeDeclaration (unwrapMatch m)
73+ y = identifierFromIdeDeclaration (discardAnn (unwrapMatch m))
74 in if d <= maxDist
74 in if d <= maxDist
75 then Just (m, 1 / fromIntegral d)
75 then Just (m, 1 / fromIntegral d)
76 else Nothing
76 else Nothing
@@ -85,12 +85,12 @@ runMatcher (Matcher m)= appEndo m
85sortCompletions :: [ScoredMatch a] -> [ScoredMatch a]
85sortCompletions :: [ScoredMatch a] -> [ScoredMatch a]
86sortCompletions = sortBy (flip compare `on` snd)
86sortCompletions = sortBy (flip compare `on` snd)
87
87
88−flexMatch :: Text -> [Match IdeDeclaration] -> [ScoredMatch IdeDeclaration]
88+flexMatch :: Text -> [Match IdeDeclarationAnn] -> [ScoredMatch IdeDeclarationAnn]
89flexMatch = mapMaybe . flexRate
89flexMatch = mapMaybe . flexRate
90
90
91−flexRate :: Text -> Match IdeDeclaration -> Maybe (ScoredMatch IdeDeclaration)
91+flexRate :: Text -> Match IdeDeclarationAnn -> Maybe (ScoredMatch IdeDeclarationAnn)
92flexRate p c = do
92flexRate p c = do
93− score <- flexScore p (identifierFromIdeDeclaration (unwrapMatch c))
93+ score <- flexScore p (identifierFromIdeDeclaration (discardAnn (unwrapMatch c)))
94 return (c, score)
94 return (c, score)
95
95
96-- FlexMatching ala Sublime.
96-- FlexMatching ala Sublime.
src/Language/PureScript/Ide/SourceFile.hs+12
@@ -17,12 +17,15 @@
17module Language.PureScript.Ide.SourceFile
17module Language.PureScript.Ide.SourceFile
18 ( parseModule
18 ( parseModule
19 , getImportsForFile
19 , getImportsForFile
20+ , extractAstInformation
21+ -- for tests
20 , extractSpans
22 , extractSpans
21 , extractTypeAnnotations
23 , extractTypeAnnotations
22 ) where
24 ) where
23
25
24import Protolude
26import Protolude
25
27
28+import qualified Data.Map as Map
26import qualified Language.PureScript as P
29import qualified Language.PureScript as P
27import Language.PureScript.Ide.Error
30import Language.PureScript.Ide.Error
28import Language.PureScript.Ide.Util
31import Language.PureScript.Ide.Util
@@ -65,6 +68,15 @@ getImportsForFile fp = do
65 unwrapImportType (P.Hiding decls) = P.Hiding (map unwrapPositionedRef decls)
68 unwrapImportType (P.Hiding decls) = P.Hiding (map unwrapPositionedRef decls)
66 unwrapImportType P.Implicit = P.Implicit
69 unwrapImportType P.Implicit = P.Implicit
67
70
71+-- | Extracts AST information from a parsed module
72+extractAstInformation
73+ :: P.Module
74+ -> (DefinitionSites P.SourceSpan, TypeAnnotations)
75+extractAstInformation (P.Module ss _ _ decls _) =
76+ let definitions = Map.fromList (concatMap (extractSpans ss) decls)
77+ typeAnnotations = Map.fromList (extractTypeAnnotations decls)
78+ in (definitions, typeAnnotations)
79+
68-- | Extracts type annotations for functions from a given Module
80-- | Extracts type annotations for functions from a given Module
69extractTypeAnnotations
81extractTypeAnnotations
70 :: [P.Declaration]
82 :: [P.Declaration]
src/Language/PureScript/Ide/State.hs+1−4
@@ -180,10 +180,7 @@ populateStage2 = do
180populateStage2STM :: TVar IdeState -> STM ()
180populateStage2STM :: TVar IdeState -> STM ()
181populateStage2STM ref = do
181populateStage2STM ref = do
182 modules <- s1Modules <$> getStage1STM ref
182 modules <- s1Modules <$> getStage1STM ref
183− let astData = map (\(P.Module ss _ _ decls _, _) ->
183+ let astData = map (extractAstInformation . fst) modules
184− let definitions = M.fromList (concatMap (extractSpans ss) decls)
185− typeAnnotations = M.fromList (extractTypeAnnotations decls)
186− in (definitions, typeAnnotations)) modules
187 setStage2STM ref (Stage2 (AstData astData))
184 setStage2STM ref (Stage2 (AstData astData))
188
185
189-- | Resolves reexports and populates Stage3 with data to be used in queries.
186-- | Resolves reexports and populates Stage3 with data to be used in queries.
src/Language/PureScript/Ide/Types.hs+18−16
@@ -112,21 +112,25 @@ data Stage3 = Stage3
112newtype Match a = Match (P.ModuleName, a)
112newtype Match a = Match (P.ModuleName, a)
113 deriving (Show, Eq, Functor)
113 deriving (Show, Eq, Functor)
114
114
115+-- | A completion as it gets sent to the editors
115−newtype Completion =
116+data Completion = Completion
116− Completion (Text, Text, Text)
117+ { complModule :: Text
117− deriving (Show,Eq)
118+ , complIdentifier :: Text
118−
119+ , complType :: Text
119−newtype Info =
120+ , complExpandedType :: Text
120− Info (Text, Text, Text, Maybe P.SourceSpan)
121+ , complLocation :: Maybe P.SourceSpan
121− deriving (Show,Eq)
122+ , complDocumentation :: Maybe Text
122−
123+ } deriving (Show, Eq)
123−instance ToJSON Info where
124− toJSON (Info (m, d, t, sourceSpan)) =
125− object ["module" .= m, "identifier" .= d, "type" .= t, "definedAt" .= sourceSpan]
126
124
127instance ToJSON Completion where
125instance ToJSON Completion where
128− toJSON (Completion (m, d, t)) =
126+ toJSON (Completion {..}) =
129− object ["module" .= m, "identifier" .= d, "type" .= t]
127+ object [ "module" .= complModule
128+ , "identifier" .= complIdentifier
129+ , "type" .= complType
130+ , "expandedType" .= complExpandedType
131+ , "definedAt" .= complLocation
132+ , "documentation" .= complDocumentation
133+ ]
130
134
131data ModuleImport =
135data ModuleImport =
132 ModuleImport
136 ModuleImport
@@ -164,14 +168,13 @@ identifierFromDeclarationRef _ = ""
164
168
165data Success =
169data Success =
166 CompletionResult [Completion]
170 CompletionResult [Completion]
167− | InfoResult [Info]
168 | TextResult Text
171 | TextResult Text
169 | MultilineTextResult [Text]
172 | MultilineTextResult [Text]
170 | PursuitResult [PursuitResponse]
173 | PursuitResult [PursuitResponse]
171 | ImportList [ModuleImport]
174 | ImportList [ModuleImport]
172 | ModuleList [ModuleIdent]
175 | ModuleList [ModuleIdent]
173 | RebuildSuccess [P.JSONError]
176 | RebuildSuccess [P.JSONError]
174− deriving(Show, Eq)
177+ deriving (Show, Eq)
175
178
176encodeSuccess :: (ToJSON a) => a -> Value
179encodeSuccess :: (ToJSON a) => a -> Value
177encodeSuccess res =
180encodeSuccess res =
@@ -179,7 +182,6 @@ encodeSuccess res =
179
182
180instance ToJSON Success where
183instance ToJSON Success where
181 toJSON (CompletionResult cs) = encodeSuccess cs
184 toJSON (CompletionResult cs) = encodeSuccess cs
182− toJSON (InfoResult i) = encodeSuccess i
183 toJSON (TextResult t) = encodeSuccess t
185 toJSON (TextResult t) = encodeSuccess t
184 toJSON (MultilineTextResult ts) = encodeSuccess ts
186 toJSON (MultilineTextResult ts) = encodeSuccess ts
185 toJSON (PursuitResult resp) = encodeSuccess resp
187 toJSON (PursuitResult resp) = encodeSuccess resp
src/Language/PureScript/Ide/Util.hs+28−24
@@ -20,10 +20,10 @@ module Language.PureScript.Ide.Util
20 , unwrapPositioned
20 , unwrapPositioned
21 , unwrapPositionedRef
21 , unwrapPositionedRef
22 , completionFromMatch
22 , completionFromMatch
23− , infoFromMatch
24 , encodeT
23 , encodeT
25 , decodeT
24 , decodeT
26 , discardAnn
25 , discardAnn
26+ , withEmptyAnn
27 , module Language.PureScript.Ide.Conversions
27 , module Language.PureScript.Ide.Conversions
28 ) where
28 ) where
29
29
@@ -48,25 +48,35 @@ identifierFromIdeDeclaration d = case d of
48discardAnn :: IdeDeclarationAnn -> IdeDeclaration
48discardAnn :: IdeDeclarationAnn -> IdeDeclaration
49discardAnn (IdeDeclarationAnn _ d) = d
49discardAnn (IdeDeclarationAnn _ d) = d
50
50
51+withEmptyAnn :: IdeDeclaration -> IdeDeclarationAnn
52+withEmptyAnn = IdeDeclarationAnn emptyAnn
53+
51unwrapMatch :: Match a -> a
54unwrapMatch :: Match a -> a
52unwrapMatch (Match (_, ed)) = ed
55unwrapMatch (Match (_, ed)) = ed
53
56
54−completionFromMatch :: Match IdeDeclaration -> Completion
57+completionFromMatch :: Match IdeDeclarationAnn -> Completion
55−completionFromMatch = Completion . completionFromMatch'
58+completionFromMatch (Match (m, IdeDeclarationAnn ann decl)) =
56−
59+ Completion {..}
57−completionFromMatch' :: Match IdeDeclaration -> (Text, Text, Text)
58−completionFromMatch' (Match (m', d)) = case d of
59− IdeValue name type' -> (m, runIdentT name, prettyTypeT type')
60− IdeType name kind -> (m, runProperNameT name, toS (P.prettyPrintKind kind))
61− IdeTypeSynonym name kind -> (m, runProperNameT name, prettyTypeT kind)
62− IdeDataConstructor name _ type' -> (m, runProperNameT name, prettyTypeT type')
63− IdeTypeClass name -> (m, runProperNameT name, "class")
64− IdeValueOperator op ref precedence associativity ->
65− (m, runOpNameT op, showFixity precedence associativity ref op)
66− IdeTypeOperator op ref precedence associativity ->
67− (m, runOpNameT op, showFixity precedence associativity ref op)
68 where
60 where
61+ (complIdentifier, complExpandedType) = case decl of
62+ IdeValue name type' -> (runIdentT name, prettyTypeT type')
63+ IdeType name kind -> (runProperNameT name, toS (P.prettyPrintKind kind))
64+ IdeTypeSynonym name kind -> (runProperNameT name, prettyTypeT kind)
65+ IdeDataConstructor name _ type' -> (runProperNameT name, prettyTypeT type')
66+ IdeTypeClass name -> (runProperNameT name, "class")
67+ IdeValueOperator op ref precedence associativity ->
68+ (runOpNameT op, showFixity precedence associativity ref op)
69+ IdeTypeOperator op ref precedence associativity ->
70+ (runOpNameT op, showFixity precedence associativity ref op)
71+
69− m = runModuleNameT m'
72+ complModule = runModuleNameT m
73+
74+ complType = maybe complExpandedType prettyTypeT (annTypeAnnotation ann)
75+
76+ complLocation = annLocation ann
77+
78+ complDocumentation = Nothing
79+
70 showFixity p a r o =
80 showFixity p a r o =
71 let asso = case a of
81 let asso = case a of
72 P.Infix -> "infix"
82 P.Infix -> "infix"
@@ -74,12 +84,6 @@ completionFromMatch' (Match (m', d)) = case d of
74 P.Infixr -> "infixr"
84 P.Infixr -> "infixr"
75 in T.unwords [asso, show p, r, "as", runOpNameT o]
85 in T.unwords [asso, show p, r, "as", runOpNameT o]
76
86
77−infoFromMatch :: Match IdeDeclarationAnn -> Info
78−infoFromMatch (Match (m, IdeDeclarationAnn ann d)) =
79− Info (a, b, maybe c prettyTypeT (annTypeAnnotation ann), annLocation ann)
80− where
81− (a, b, c) = completionFromMatch' (Match (m, d))
82−
83encodeT :: (ToJSON a) => a -> Text
87encodeT :: (ToJSON a) => a -> Text
84encodeT = toS . decodeUtf8 . encode
88encodeT = toS . decodeUtf8 . encode
85
89
@@ -87,9 +91,9 @@ decodeT :: (FromJSON a) => Text -> Maybe a
87decodeT = decode . encodeUtf8 . toS
91decodeT = decode . encodeUtf8 . toS
88
92
89unwrapPositioned :: P.Declaration -> P.Declaration
93unwrapPositioned :: P.Declaration -> P.Declaration
90−unwrapPositioned (P.PositionedDeclaration _ _ x) = x
94+unwrapPositioned (P.PositionedDeclaration _ _ x) = unwrapPositioned x
91unwrapPositioned x = x
95unwrapPositioned x = x
92
96
93unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
97unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
94−unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = x
98+unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = unwrapPositionedRef x
95unwrapPositionedRef x = x
99unwrapPositionedRef x = x
tests/Language/PureScript/Ide/Integration.hs+7−19
@@ -37,13 +37,11 @@ module Language.PureScript.Ide.Integration
37 , getFlexCompletions
37 , getFlexCompletions
38 , getFlexCompletionsInModule
38 , getFlexCompletionsInModule
39 , getType
39 , getType
40− , getInfo
41 , rebuildModule
40 , rebuildModule
42 , reset
41 , reset
43 -- checking results
42 -- checking results
44 , resultIsSuccess
43 , resultIsSuccess
45 , parseCompletions
44 , parseCompletions
46− , parseInfo
47 , parseTextResult
45 , parseTextResult
48 ) where
46 ) where
49
47
@@ -158,18 +156,15 @@ loadModules = sendCommand . load
158loadAll :: IO Text
156loadAll :: IO Text
159loadAll = sendCommand (load [])
157loadAll = sendCommand (load [])
160
158
161−getFlexCompletions :: Text -> IO [(Text, Text, Text)]
159+getFlexCompletions :: Text -> IO [(Text, Text, Text, Maybe P.SourceSpan)]
162getFlexCompletions q = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) Nothing)
160getFlexCompletions q = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) Nothing)
163
161
164−getFlexCompletionsInModule :: Text -> Text -> IO [(Text, Text, Text)]
162+getFlexCompletionsInModule :: Text -> Text -> IO [(Text, Text, Text, Maybe P.SourceSpan)]
165getFlexCompletionsInModule q m = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) (Just m))
163getFlexCompletionsInModule q m = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) (Just m))
166
164
167−getType :: Text -> IO [(Text, Text, Text)]
165+getType :: Text -> IO [(Text, Text, Text, Maybe P.SourceSpan)]
168getType q = parseCompletions <$> sendCommand (typeC q [])
166getType q = parseCompletions <$> sendCommand (typeC q [])
169
167
170−getInfo :: Text -> IO [P.SourceSpan]
171−getInfo q = parseInfo <$> sendCommand (typeC q [])
172−
173addImport :: Text -> FilePath -> FilePath -> IO Text
168addImport :: Text -> FilePath -> FilePath -> IO Text
174addImport identifier fp outfp = sendCommand (addImportC identifier fp outfp)
169addImport identifier fp outfp = sendCommand (addImportC identifier fp outfp)
175
170
@@ -254,17 +249,14 @@ withResult p v = do
254 Left err -> pure (Left err)
249 Left err -> pure (Left err)
255 Right res -> Right <$> p res
250 Right res -> Right <$> p res
256
251
257−completionParser :: Value -> Parser [(Text, Text, Text)]
252+completionParser :: Value -> Parser [(Text, Text, Text, Maybe P.SourceSpan)]
258completionParser = withArray "res" $ \cs ->
253completionParser = withArray "res" $ \cs ->
259 mapM (withObject "completion" $ \o -> do
254 mapM (withObject "completion" $ \o -> do
260 ident <- o .: "identifier"
255 ident <- o .: "identifier"
261 module' <- o .: "module"
256 module' <- o .: "module"
262 ty <- o .: "type"
257 ty <- o .: "type"
258+ ss <- o .: "definedAt"
263− pure (module', ident, ty)) (V.toList cs)
259+ pure (module', ident, ty, ss)) (V.toList cs)
264−
265−infoParser :: Value -> Parser [P.SourceSpan]
266−infoParser = withArray "res" $ \cs ->
267− mapM (withObject "info" $ \o -> o .: "definedAt") (V.toList cs)
268
260
269valueFromText :: Text -> Value
261valueFromText :: Text -> Value
270valueFromText = fromJust . decode . toS
262valueFromText = fromJust . decode . toS
@@ -272,14 +264,10 @@ valueFromText = fromJust . decode . toS
272resultIsSuccess :: Text -> Bool
264resultIsSuccess :: Text -> Bool
273resultIsSuccess = isRight . join . first toS . parseEither unwrapResult . valueFromText
265resultIsSuccess = isRight . join . first toS . parseEither unwrapResult . valueFromText
274
266
275−parseCompletions :: Text -> [(Text, Text, Text)]
267+parseCompletions :: Text -> [(Text, Text, Text, Maybe P.SourceSpan)]
276parseCompletions s =
268parseCompletions s =
277 fromJust $ join (rightToMaybe <$> parseMaybe (withResult completionParser) (valueFromText s))
269 fromJust $ join (rightToMaybe <$> parseMaybe (withResult completionParser) (valueFromText s))
278
270
279−parseInfo :: Text -> [P.SourceSpan]
280−parseInfo s =
281− fromJust $ join (rightToMaybe <$> parseMaybe (withResult infoParser) (valueFromText s))
282−
283parseTextResult :: Text -> Text
271parseTextResult :: Text -> Text
284parseTextResult s =
272parseTextResult s =
285 fromJust $ join (rightToMaybe <$> parseMaybe (withResult (withText "tr" pure)) (valueFromText s))
273 fromJust $ join (rightToMaybe <$> parseMaybe (withResult (withText "tr" pure)) (valueFromText s))
tests/Language/PureScript/Ide/MatcherSpec.hs+9−7
@@ -9,20 +9,21 @@ import qualified Language.PureScript as P
9import Language.PureScript.Ide.Integration
9import Language.PureScript.Ide.Integration
10import Language.PureScript.Ide.Matcher
10import Language.PureScript.Ide.Matcher
11import Language.PureScript.Ide.Types
11import Language.PureScript.Ide.Types
12+import Language.PureScript.Ide.Util
12import Test.Hspec
13import Test.Hspec
13
14
14−value :: Text -> IdeDeclaration
15+value :: Text -> IdeDeclarationAnn
15−value s = IdeValue (P.Ident (toS s)) P.REmpty
16+value s = withEmptyAnn (IdeValue (P.Ident (toS s)) P.REmpty)
16
17
17−firstResult, secondResult, fiult :: Match IdeDeclaration
18+firstResult, secondResult, fiult :: Match IdeDeclarationAnn
18firstResult = Match (P.moduleNameFromString "Match", value "firstResult")
19firstResult = Match (P.moduleNameFromString "Match", value "firstResult")
19secondResult = Match (P.moduleNameFromString "Match", value "secondResult")
20secondResult = Match (P.moduleNameFromString "Match", value "secondResult")
20fiult = Match (P.moduleNameFromString "Match", value "fiult")
21fiult = Match (P.moduleNameFromString "Match", value "fiult")
21
22
22−completions :: [Match IdeDeclaration]
23+completions :: [Match IdeDeclarationAnn]
23completions = [firstResult, secondResult, fiult]
24completions = [firstResult, secondResult, fiult]
24
25
25−runFlex :: Text -> [Match IdeDeclaration]
26+runFlex :: Text -> [Match IdeDeclarationAnn]
26runFlex s = runMatcher (flexMatcher s) completions
27runFlex s = runMatcher (flexMatcher s) completions
27
28
28setup :: IO ()
29setup :: IO ()
@@ -43,5 +44,6 @@ spec = do
43 cs <- getFlexCompletions ""
44 cs <- getFlexCompletions ""
44 cs `shouldBe` []
45 cs `shouldBe` []
45 it "matches on equality" $ do
46 it "matches on equality" $ do
47+ -- ignore any position information
46− cs <- getFlexCompletions "const"
48+ (m, i, t, _) : _ <- getFlexCompletions "const"
47− cs `shouldBe` [("MatcherSpec", "const", "forall a b. a -> b -> a")]
49+ (m, i, t) `shouldBe` ("MatcherSpec", "const", "forall a b. a -> b -> a")
tests/Language/PureScript/Ide/SourceFile/IntegrationSpec.hs+6−1
@@ -31,6 +31,11 @@ spec = beforeAll_ setup $
31
31
32testCase :: Text -> (Int, Int) -> IO ()
32testCase :: Text -> (Int, Int) -> IO ()
33testCase s (x, y) = do
33testCase s (x, y) = do
34− P.SourceSpan f (P.SourcePos l c) _ : _ <- Integration.getInfo s
34+ P.SourceSpan f (P.SourcePos l c) _ <- getLocation s
35 toS f `shouldSatisfy` T.isSuffixOf "SourceFileSpec.purs"
35 toS f `shouldSatisfy` T.isSuffixOf "SourceFileSpec.purs"
36 (l, c) `shouldBe` (x, y)
36 (l, c) `shouldBe` (x, y)
37+
38+getLocation :: Text -> IO P.SourceSpan
39+getLocation s = do
40+ (_, _, _, Just location) : _ <- Integration.getType s
41+ pure location
tests/Language/PureScript/Ide/SourceFileSpec.hs+6−2
@@ -13,7 +13,8 @@ span0 = P.SourceSpan "ModuleLevel" (P.SourcePos 0 0) (P.SourcePos 1 1)
13span1 = P.SourceSpan "" (P.SourcePos 1 1) (P.SourcePos 2 2)
13span1 = P.SourceSpan "" (P.SourcePos 1 1) (P.SourcePos 2 2)
14span2 = P.SourceSpan "" (P.SourcePos 2 2) (P.SourcePos 3 3)
14span2 = P.SourceSpan "" (P.SourcePos 2 2) (P.SourcePos 3 3)
15
15
16−value1, synonym1, class1, class2, data1, data2, foreign1, foreign2, member1 :: P.Declaration
16+typeAnnotation1, value1, synonym1, class1, class2, data1, data2, foreign1, foreign2, member1 :: P.Declaration
17+typeAnnotation1 = P.TypeDeclaration (P.Ident "value1") P.REmpty
17value1 = P.ValueDeclaration (P.Ident "value1") P.Public [] (Left [])
18value1 = P.ValueDeclaration (P.Ident "value1") P.Public [] (Left [])
18synonym1 = P.TypeSynonymDeclaration (P.ProperName "Synonym1") [] P.REmpty
19synonym1 = P.TypeSynonymDeclaration (P.ProperName "Synonym1") [] P.REmpty
19class1 = P.TypeClassDeclaration (P.ProperName "Class1") [] [] []
20class1 = P.TypeClassDeclaration (P.ProperName "Class1") [] [] []
@@ -26,7 +27,7 @@ foreign2 = P.ExternDataDeclaration (P.ProperName "Foreign2") P.Star
26member1 = P.TypeDeclaration (P.Ident "member1") P.REmpty
27member1 = P.TypeDeclaration (P.Ident "member1") P.REmpty
27
28
28spec :: Spec
29spec :: Spec
29−spec =
30+spec = do
30 describe "Extracting Spans" $ do
31 describe "Extracting Spans" $ do
31 it "extracts a span for a value declaration" $
32 it "extracts a span for a value declaration" $
32 extractSpans span0 (P.PositionedDeclaration span1 [] value1) `shouldBe` [(Left "value1", span1)]
33 extractSpans span0 (P.PositionedDeclaration span1 [] value1) `shouldBe` [(Left "value1", span1)]
@@ -44,3 +45,6 @@ spec =
44 extractSpans span0 (P.PositionedDeclaration span1 [] foreign1) `shouldBe` [(Left "foreign1", span1)]
45 extractSpans span0 (P.PositionedDeclaration span1 [] foreign1) `shouldBe` [(Left "foreign1", span1)]
45 it "extracts a span for a data foreign declaration" $
46 it "extracts a span for a data foreign declaration" $
46 extractSpans span0 (P.PositionedDeclaration span1 [] foreign2) `shouldBe` [(Right "Foreign2", span1)]
47 extractSpans span0 (P.PositionedDeclaration span1 [] foreign2) `shouldBe` [(Right "Foreign2", span1)]
48+ describe "Type annotations" $ do
49+ it "extracts a type annotation" $
50+ extractTypeAnnotations [typeAnnotation1] `shouldBe` [(P.Ident "value1", P.REmpty)]