@@ -30,7 +30,6 @@ import Development.IDE.GHC.ExactPrint (Annotated (annsA)
3030import Development.IDE.GHC.Util (prettyPrint )
3131import Development.IDE.Graph
3232import Development.IDE.Graph.Classes
33- import qualified Development.IDE.Types.KnownTargets as KT
3433import Development.IDE.Plugin.CodeAction (newImport ,
3534 newImportToEdit )
3635import Development.IDE.Plugin.CodeAction.ExactPrint
@@ -39,6 +38,7 @@ import Development.IDE.Plugin.Completions.Types
3938import Development.IDE.Types.Exports
4039import Development.IDE.Types.HscEnvEq (HscEnvEq (envPackageExports ),
4140 hscEnv )
41+ import qualified Development.IDE.Types.KnownTargets as KT
4242import Development.IDE.Types.Location
4343import GHC.Exts (fromList , toList )
4444import GHC.Generics
@@ -47,6 +47,7 @@ import Ide.Types
4747import qualified Language.LSP.Server as LSP
4848import Language.LSP.Types
4949import qualified Language.LSP.VFS as VFS
50+ import Text.Fuzzy.Parallel (Scored (.. ))
5051
5152descriptor :: PluginId -> PluginDescriptor IdeState
5253descriptor plId = (defaultPluginDescriptor plId)
@@ -156,17 +157,50 @@ getCompletionsLSP ide plId
156157 let clientCaps = clientCapabilities $ shakeExtras ide
157158 config <- getCompletionsConfig plId
158159 allCompletions <- liftIO $ getCompletions plId ideOpts cci' parsedMod bindMap pfix' clientCaps config moduleExports
159- pure $ InL (List allCompletions)
160+ pure $ InL (List $ orderedCompletions allCompletions)
160161 _ -> return (InL $ List [] )
161162 _ -> return (InL $ List [] )
162163 _ -> return (InL $ List [] )
163164
165+ {- COMPLETION SORTING
166+ We return an ordered set of completions (local -> nonlocal -> global).
167+ Ordering is important because local/nonlocal are import aware, whereas
168+ global are not and will always insert import statements, potentially redundant.
169+
170+ Moreover, the order prioritizes qualifiers, for instance, given:
171+
172+ import qualified MyModule
173+ foo = MyModule.<complete>
174+
175+ The identifiers defined in MyModule will be listed first, followed by other
176+ identifiers in importable modules.
177+
178+ According to the LSP specification, if no sortText is provided, the label is used
179+ to sort alphabetically. Alphabetical ordering is almost never what we want,
180+ so we force the LSP client to respect our ordering by using a numbered sequence.
181+ -}
182+
183+ orderedCompletions :: [Scored CompletionItem ] -> [CompletionItem ]
184+ orderedCompletions [] = []
185+ orderedCompletions xx = zipWith addOrder [0 .. ] xx
186+ where
187+ lxx = digits $ Prelude. length xx
188+ digits = Prelude. length . show
189+
190+ addOrder :: Int -> Scored CompletionItem -> CompletionItem
191+ addOrder n Scored {original = it@ CompletionItem {_label,_sortText}} =
192+ it{_sortText = Just $
193+ T. pack(pad lxx n)
194+ }
195+
196+ pad n x = let sx = show x in replicate (n - Prelude. length sx) ' 0' <> sx
197+
164198----------------------------------------------------------------------------------------------------
165199
166200toModueNameText :: KT. Target -> T. Text
167201toModueNameText target = case target of
168- KT. TargetModule m -> T. pack $ moduleNameString m
169- _ -> T. empty
202+ KT. TargetModule m -> T. pack $ moduleNameString m
203+ _ -> T. empty
170204
171205extendImportCommand :: PluginCommand IdeState
172206extendImportCommand =
0 commit comments