git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
2323: Sort IDE-generated explicit imports (#2413)
6675280bbqbaron
src/Language/PureScript/AST/Declarations.hs+25
@@ -261,6 +261,31 @@ instance Eq DeclarationRef where
261 r == (PositionedDeclarationRef _ _ r') = r == r'
261 r == (PositionedDeclarationRef _ _ r') = r == r'
262 _ == _ = False
262 _ == _ = False
263
263
264+-- enable sorting lists of explicitly imported refs when suggesting imports in linting, IDE, etc.
265+-- not an Ord because this implementation is not consistent with its Eq instance.
266+-- think of it as a notion of contextual, not inherent, ordering.
267+compDecRef :: DeclarationRef -> DeclarationRef -> Ordering
268+compDecRef (TypeRef name _) (TypeRef name' _) = compare name name'
269+compDecRef (TypeOpRef name) (TypeOpRef name') = compare name name'
270+compDecRef (ValueRef ident) (ValueRef ident') = compare ident ident'
271+compDecRef (ValueOpRef name) (ValueOpRef name') = compare name name'
272+compDecRef (TypeClassRef name) (TypeClassRef name') = compare name name'
273+compDecRef (TypeInstanceRef ident) (TypeInstanceRef ident') = compare ident ident'
274+compDecRef (ModuleRef name) (ModuleRef name') = compare name name'
275+compDecRef (ReExportRef name _) (ReExportRef name' _) = compare name name'
276+compDecRef (PositionedDeclarationRef _ _ ref) ref' = compDecRef ref ref'
277+compDecRef ref (PositionedDeclarationRef _ _ ref') = compDecRef ref ref'
278+compDecRef ref ref' = compare
279+ (orderOf ref) (orderOf ref')
280+ where
281+ orderOf :: DeclarationRef -> Int
282+ orderOf (TypeClassRef _) = 0
283+ orderOf (TypeOpRef _) = 1
284+ orderOf (TypeRef _ _) = 2
285+ orderOf (ValueRef _) = 3
286+ orderOf (ValueOpRef _) = 4
287+ orderOf _ = 5
288+
264getTypeRef :: DeclarationRef -> Maybe (ProperName 'TypeName, Maybe [ProperName 'ConstructorName])
289getTypeRef :: DeclarationRef -> Maybe (ProperName 'TypeName, Maybe [ProperName 'ConstructorName])
265getTypeRef (TypeRef name dctors) = Just (name, dctors)
290getTypeRef (TypeRef name dctors) = Just (name, dctors)
266getTypeRef (PositionedDeclarationRef _ _ r) = getTypeRef r
291getTypeRef (PositionedDeclarationRef _ _ r) = getTypeRef r
src/Language/PureScript/Ide/Imports.hs+3−8
@@ -202,7 +202,7 @@ addExplicitImport' decl moduleName imports =
202 refFromDeclaration (IdeDeclTypeClass n) =
202 refFromDeclaration (IdeDeclTypeClass n) =
203 P.TypeClassRef n
203 P.TypeClassRef n
204 refFromDeclaration (IdeDeclDataConstructor dtor) =
204 refFromDeclaration (IdeDeclDataConstructor dtor) =
205− P.TypeRef (dtor ^. ideDtorTypeName) (Just [dtor ^. ideDtorName])
205+ P.TypeRef (dtor ^. ideDtorTypeName) Nothing
206 refFromDeclaration (IdeDeclType t) =
206 refFromDeclaration (IdeDeclType t) =
207 P.TypeRef (t ^. ideTypeName) (Just [])
207 P.TypeRef (t ^. ideTypeName) (Just [])
208 refFromDeclaration (IdeDeclValueOperator op) =
208 refFromDeclaration (IdeDeclValueOperator op) =
@@ -216,7 +216,7 @@ addExplicitImport' decl moduleName imports =
216 -- TypeDeclaration "Maybe" + Data.Maybe (maybe) -> Data.Maybe(Maybe, maybe)
216 -- TypeDeclaration "Maybe" + Data.Maybe (maybe) -> Data.Maybe(Maybe, maybe)
217 insertDeclIntoImport :: IdeDeclaration -> Import -> Import
217 insertDeclIntoImport :: IdeDeclaration -> Import -> Import
218 insertDeclIntoImport decl' (Import mn (P.Explicit refs) Nothing) =
218 insertDeclIntoImport decl' (Import mn (P.Explicit refs) Nothing) =
219− Import mn (P.Explicit (insertDeclIntoRefs decl' refs)) Nothing
219+ Import mn (P.Explicit (sortBy P.compDecRef (insertDeclIntoRefs decl' refs))) Nothing
220 insertDeclIntoImport _ is = is
220 insertDeclIntoImport _ is = is
221
221
222 insertDeclIntoRefs :: IdeDeclaration -> [P.DeclarationRef] -> [P.DeclarationRef]
222 insertDeclIntoRefs :: IdeDeclaration -> [P.DeclarationRef] -> [P.DeclarationRef]
@@ -228,12 +228,7 @@ addExplicitImport' decl moduleName imports =
228 refs
228 refs
229 insertDeclIntoRefs dr refs = nubBy ((==) `on` P.prettyPrintRef) (refFromDeclaration dr : refs)
229 insertDeclIntoRefs dr refs = nubBy ((==) `on` P.prettyPrintRef) (refFromDeclaration dr : refs)
230
230
231− insertDtor dtor (P.TypeRef tn' dtors) =
231+ insertDtor _ (P.TypeRef tn' _) = P.TypeRef tn' Nothing
232− case dtors of
233− Just dtors' -> P.TypeRef tn' (Just (ordNub (dtor : dtors')))
234− -- This means the import was opened. We don't add anything in this case
235− -- import Data.Maybe (Maybe(..)) -> import Data.Maybe (Maybe(Just))
236− Nothing -> P.TypeRef tn' Nothing
237 insertDtor _ refs = refs
232 insertDtor _ refs = refs
238
233
239 matchType :: P.ProperName 'P.TypeName -> P.DeclarationRef -> Bool
234 matchType :: P.ProperName 'P.TypeName -> P.DeclarationRef -> Bool
src/Language/PureScript/Linter/Imports.hs+1−1
@@ -308,7 +308,7 @@ findUsedRefs env mni qn names =
308 typesRefs
308 typesRefs
309 = map (flip TypeRef (Just [])) typesWithoutDctors
309 = map (flip TypeRef (Just [])) typesWithoutDctors
310 ++ map (\(ty, ds) -> TypeRef ty (Just ds)) (M.toList typesWithDctors)
310 ++ map (\(ty, ds) -> TypeRef ty (Just ds)) (M.toList typesWithDctors)
311− in classRefs ++ typeOpRefs ++ typesRefs ++ valueRefs ++ valueOpRefs
311+ in sortBy compDecRef $ classRefs ++ typeOpRefs ++ typesRefs ++ valueRefs ++ valueOpRefs
312
312
313 where
313 where
314
314
tests/Language/PureScript/Ide/Imports/IntegrationSpec.hs+2−2
@@ -57,10 +57,10 @@ spec = beforeAll_ setup . describe "Adding imports" $ do
57 outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (class ATypeClass)"])
57 outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (class ATypeClass)"])
58 it "adds an explicit unqualified import (dataconstructor)" $ do
58 it "adds an explicit unqualified import (dataconstructor)" $ do
59 withSupportFiles (Integration.addImport "MyJust")
59 withSupportFiles (Integration.addImport "MyJust")
60− outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyMaybe(MyJust))"])
60+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyMaybe(..))"])
61 it "adds an explicit unqualified import (newtype)" $ do
61 it "adds an explicit unqualified import (newtype)" $ do
62 withSupportFiles (Integration.addImport "MyNewtype")
62 withSupportFiles (Integration.addImport "MyNewtype")
63− outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyNewtype(MyNewtype))"])
63+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyNewtype(..))"])
64 it "adds an explicit unqualified import (typeclass member function)" $ do
64 it "adds an explicit unqualified import (typeclass member function)" $ do
65 withSupportFiles (Integration.addImport "typeClassFun")
65 withSupportFiles (Integration.addImport "typeClassFun")
66 outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (typeClassFun)"])
66 outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (typeClassFun)"])
tests/Language/PureScript/Ide/ImportsSpec.hs+46−3
@@ -73,6 +73,8 @@ spec = do
73 prettyPrintImportSection (addExplicitImport' (IdeDeclValueOperator (IdeValueOperator op (P.Qualified Nothing (Left (P.Ident ""))) 2 P.Infix Nothing)) mn is)
73 prettyPrintImportSection (addExplicitImport' (IdeDeclValueOperator (IdeValueOperator op (P.Qualified Nothing (Left (P.Ident ""))) 2 P.Infix Nothing)) mn is)
74 addDtorImport i t mn is =
74 addDtorImport i t mn is =
75 prettyPrintImportSection (addExplicitImport' (IdeDeclDataConstructor (IdeDataConstructor (P.ProperName i) t wildcard)) mn is)
75 prettyPrintImportSection (addExplicitImport' (IdeDeclDataConstructor (IdeDataConstructor (P.ProperName i) t wildcard)) mn is)
76+ addTypeImport i mn is =
77+ prettyPrintImportSection (addExplicitImport' (IdeDeclType (IdeType (P.ProperName i) P.Star)) mn is)
76 it "adds an implicit unqualified import" $
78 it "adds an implicit unqualified import" $
77 shouldBe
79 shouldBe
78 (addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map"))
80 (addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map"))
@@ -100,20 +102,26 @@ spec = do
100 shouldBe
102 shouldBe
101 (addOpImport (P.OpName "<~>") (P.moduleNameFromString "Data.Array") explicitImports)
103 (addOpImport (P.OpName "<~>") (P.moduleNameFromString "Data.Array") explicitImports)
102 [ "import Prelude"
104 [ "import Prelude"
103− , "import Data.Array ((<~>), tail)"
105+ , "import Data.Array (tail, (<~>))"
104 ]
106 ]
107+ it "adds a type with constructors without automatically adding an open import of said constructors " $
108+ shouldBe
109+ (addTypeImport "Maybe" (P.moduleNameFromString "Data.Maybe") simpleFileImports)
110+ [ "import Prelude"
111+ , "import Data.Maybe (Maybe)"
112+ ]
105 it "adds the type for a given DataConstructor" $
113 it "adds the type for a given DataConstructor" $
106 shouldBe
114 shouldBe
107 (addDtorImport "Just" (P.ProperName "Maybe") (P.moduleNameFromString "Data.Maybe") simpleFileImports)
115 (addDtorImport "Just" (P.ProperName "Maybe") (P.moduleNameFromString "Data.Maybe") simpleFileImports)
108 [ "import Prelude"
116 [ "import Prelude"
109− , "import Data.Maybe (Maybe(Just))"
117+ , "import Data.Maybe (Maybe(..))"
110 ]
118 ]
111 it "adds a dataconstructor to an existing type import" $ do
119 it "adds a dataconstructor to an existing type import" $ do
112 let Right (_, _, typeImports, _) = sliceImportSection (withImports ["import Data.Maybe (Maybe)"])
120 let Right (_, _, typeImports, _) = sliceImportSection (withImports ["import Data.Maybe (Maybe)"])
113 shouldBe
121 shouldBe
114 (addDtorImport "Just" (P.ProperName "Maybe") (P.moduleNameFromString "Data.Maybe") typeImports)
122 (addDtorImport "Just" (P.ProperName "Maybe") (P.moduleNameFromString "Data.Maybe") typeImports)
115 [ "import Prelude"
123 [ "import Prelude"
116− , "import Data.Maybe (Maybe(Just))"
124+ , "import Data.Maybe (Maybe(..))"
117 ]
125 ]
118 it "doesn't add a dataconstructor to an existing type import with open dtors" $ do
126 it "doesn't add a dataconstructor to an existing type import with open dtors" $ do
119 let Right (_, _, typeImports, _) = sliceImportSection (withImports ["import Data.Maybe (Maybe(..))"])
127 let Right (_, _, typeImports, _) = sliceImportSection (withImports ["import Data.Maybe (Maybe(..))"])
@@ -128,3 +136,38 @@ spec = do
128 [ "import Prelude"
136 [ "import Prelude"
129 , "import Data.Array (tail)"
137 , "import Data.Array (tail)"
130 ]
138 ]
139+
140+ describe "explicit import sorting" $ do
141+ -- given some basic import skeleton
142+ let Right (_, _, baseImports, _) = sliceImportSection $ withImports ["import Control.Monad (ap)"]
143+ moduleName = (P.moduleNameFromString "Control.Monad")
144+ addImport imports import' = addExplicitImport' import' moduleName imports
145+ valueImport ident = (IdeDeclValue (IdeValue (P.Ident ident) wildcard))
146+ typeImport name = (IdeDeclType (IdeType (P.ProperName name) P.Star))
147+ classImport name = (IdeDeclTypeClass (P.ProperName name))
148+ dtorImport name typeName = (IdeDeclDataConstructor (IdeDataConstructor (P.ProperName name) (P.ProperName typeName) wildcard))
149+ -- expect any list of provided identifiers, when imported, to come out as specified
150+ expectSorted imports expected = shouldBe
151+ (ordNub $ map
152+ (prettyPrintImportSection . foldl addImport baseImports)
153+ (permutations imports))
154+ [expected]
155+ it "sorts class" $
156+ expectSorted (map classImport ["Applicative", "Bind"])
157+ ["import Prelude", "import Control.Monad (class Applicative, class Bind, ap)"]
158+ it "sorts value" $
159+ expectSorted (map valueImport ["unless", "where"])
160+ ["import Prelude", "import Control.Monad (ap, unless, where)"]
161+ it "sorts type, value" $
162+ expectSorted
163+ ((map valueImport ["unless", "where"]) ++ (map typeImport ["Foo", "Bar"]))
164+ ["import Prelude", "import Control.Monad (Bar, Foo, ap, unless, where)"]
165+ it "sorts class, type, value" $
166+ expectSorted
167+ ((map valueImport ["unless", "where"]) ++ (map typeImport ["Foo", "Bar"]) ++ (map classImport ["Applicative", "Bind"]))
168+ ["import Prelude", "import Control.Monad (class Applicative, class Bind, Bar, Foo, ap, unless, where)"]
169+ it "sorts types with constructors, using open imports for the constructors" $
170+ expectSorted
171+ -- the imported names don't actually have to exist!
172+ (map (uncurry dtorImport) [("Just", "Maybe"), ("Nothing", "Maybe"), ("SomeOtherConstructor", "SomeDataType")])
173+ ["import Prelude", "import Control.Monad (Maybe(..), SomeDataType(..), ap)"]