-
Notifications
You must be signed in to change notification settings - Fork 437
/
Completion.lean
96 lines (89 loc) · 3.41 KB
/
Completion.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Marc Huisinga
-/
prelude
import Lean.Server.Completion.CompletionCollectors
namespace Lean.Server.Completion
open Lsp
open Elab
private def filterDuplicateCompletionItems
(items : Array ScoredCompletionItem)
: Array ScoredCompletionItem :=
let duplicationGroups := items.groupByKey fun s => (
s.item.label,
s.item.textEdit?,
s.item.detail?,
s.item.kind?,
s.item.tags?,
s.item.documentation?,
)
duplicationGroups.map (fun _ duplicateItems => duplicateItems.getMax? (·.score < ·.score) |>.get!)
|>.valuesArray
/--
Sorts `items` descendingly according to their score and ascendingly according to their label
for equal scores.
-/
private def sortCompletionItems (items : Array ScoredCompletionItem) : Array CompletionItem :=
let items := items.qsort fun ⟨i1, s1⟩ ⟨i2, s2⟩ =>
if s1 != s2 then
s1 > s2
else
i1.label.map (·.toLower) < i2.label.map (·.toLower)
items.map (·.1)
/--
Assigns the `CompletionItem.sortText?` for all items in `completions` according to their order
in `completions`. This is necessary because clients will use their own sort order if the server
does not set it.
-/
private def assignSortTexts (completions : Array CompletionItem) : Array CompletionItem := Id.run do
if completions.isEmpty then
return #[]
let items := completions.mapIdx fun i item =>
{ item with sortText? := toString i }
let maxDigits := items[items.size - 1]!.sortText?.get!.length
let items := items.map fun item =>
let sortText := item.sortText?.get!
let pad := List.replicate (maxDigits - sortText.length) '0' |>.asString
{ item with sortText? := pad ++ sortText }
items
partial def find?
(params : CompletionParams)
(fileMap : FileMap)
(hoverPos : String.Pos)
(cmdStx : Syntax)
(infoTree : InfoTree)
(caps : ClientCapabilities)
: IO CompletionList := do
let prioritizedPartitions := findPrioritizedCompletionPartitionsAt fileMap hoverPos cmdStx infoTree
let mut allCompletions := #[]
for partition in prioritizedPartitions do
for (i, completionInfoPos) in partition do
let completions : Array ScoredCompletionItem ←
match i.info with
| .id stx id danglingDot lctx .. =>
idCompletion params completionInfoPos i.ctx lctx stx id i.hoverInfo danglingDot
| .dot info .. =>
dotCompletion params completionInfoPos i.ctx info
| .dotId _ id lctx expectedType? =>
dotIdCompletion params completionInfoPos i.ctx lctx id expectedType?
| .fieldId _ id lctx structName =>
fieldIdCompletion params completionInfoPos i.ctx lctx id structName
| .option stx =>
optionCompletion params completionInfoPos i.ctx stx caps
| .tactic .. =>
tacticCompletion params completionInfoPos i.ctx
| _ =>
pure #[]
allCompletions := allCompletions ++ completions
if ! allCompletions.isEmpty then
-- Stop accumulating completions with lower priority if we found completions for a higher
-- priority.
break
let finalCompletions := allCompletions
|> filterDuplicateCompletionItems
|> sortCompletionItems
|> assignSortTexts
return { items := finalCompletions, isIncomplete := true }
end Lean.Server.Completion