feat: make go-to-definition on a typeclass projection application go to the instance(s) (#1767)
This commit is contained in:
parent
600758ba49
commit
561e404fe4
9 changed files with 281 additions and 45 deletions
|
|
@ -66,11 +66,11 @@ def handleHover (p : HoverParams)
|
|||
| none => pure none
|
||||
|
||||
-- now try info tree
|
||||
if let some (ci, i) := snap.infoTree.hoverableInfoAt? hoverPos then
|
||||
if let some range := i.range? then
|
||||
if let some ictx := snap.infoTree.hoverableInfoAt? hoverPos then
|
||||
if let some range := ictx.info.range? then
|
||||
-- prefer info tree if at least as specific as parser docstring
|
||||
if stxDoc?.all fun (_, stxRange) => stxRange.includes range then
|
||||
if let some hoverFmt ← i.fmtHover? ci then
|
||||
if let some hoverFmt ← ictx.info.fmtHover? ictx.ctx then
|
||||
return mkHover (toString hoverFmt.fmt) range
|
||||
|
||||
if let some (doc, range) := stxDoc? then
|
||||
|
|
@ -79,7 +79,7 @@ def handleHover (p : HoverParams)
|
|||
return none
|
||||
|
||||
open Elab GoToKind in
|
||||
def locationLinksOfInfo (kind : GoToKind) (ci : Elab.ContextInfo) (i : Elab.Info)
|
||||
def locationLinksOfInfo (kind : GoToKind) (ictx : InfoWithCtx)
|
||||
(infoTree? : Option InfoTree := none) : RequestM (Array LocationLink) := do
|
||||
let rc ← read
|
||||
let doc ← readDoc
|
||||
|
|
@ -116,6 +116,9 @@ def locationLinksOfInfo (kind : GoToKind) (ci : Elab.ContextInfo) (i : Elab.Info
|
|||
return #[ll]
|
||||
return #[]
|
||||
|
||||
let i := ictx.info
|
||||
let ci := ictx.ctx
|
||||
let children := ictx.children
|
||||
match i with
|
||||
| .ofTermInfo ti =>
|
||||
let mut expr := ti.expr
|
||||
|
|
@ -126,6 +129,43 @@ def locationLinksOfInfo (kind : GoToKind) (ci : Elab.ContextInfo) (i : Elab.Info
|
|||
| Expr.const n .. => return ← ci.runMetaM i.lctx <| locationLinksFromDecl i n
|
||||
| Expr.fvar id .. => return ← ci.runMetaM i.lctx <| locationLinksFromBinder i id
|
||||
| _ => pure ()
|
||||
|
||||
-- Check whether this `TermInfo` node is directly responsible for its `.expr`.
|
||||
-- This is the case iff all of its children represent strictly smaller subexpressions;
|
||||
-- it is sufficient to check this of all direct children of this node (and that its elaborator didn't expand it as a macro)
|
||||
let isExprGenerator := children.all fun
|
||||
| .node (Info.ofTermInfo info) _ => info.expr != expr
|
||||
| .node (Info.ofMacroExpansionInfo _) _ => false
|
||||
| _ => true
|
||||
|
||||
-- don't go-to-instance if this `TermInfo` didn't directly generate its `.expr`
|
||||
if kind != declaration && isExprGenerator then
|
||||
-- go-to-definition on a projection application of a typeclass
|
||||
-- should return all instances generated by TC
|
||||
expr ← ci.runMetaM i.lctx do instantiateMVars expr
|
||||
if let .const n _ := expr.getAppFn then
|
||||
-- also include constant along with instance results
|
||||
let mut results ← ci.runMetaM i.lctx <| locationLinksFromDecl i n
|
||||
if let some info := ci.env.getProjectionFnInfo? n then
|
||||
let mut elaborators := default
|
||||
if let some ei := i.toElabInfo? then do
|
||||
-- also include elaborator along with instance results, as this wouldn't be accessible otherwise
|
||||
if ei.elaborator != `Delab -- prevent an error if this `TermInfo` came from the infoview
|
||||
&& ei.elaborator != `Lean.Elab.Term.elabApp && ei.elaborator != `Lean.Elab.Term.elabIdent -- don't include trivial elaborators
|
||||
then do
|
||||
elaborators ← ci.runMetaM i.lctx <| locationLinksFromDecl i ei.elaborator
|
||||
let instIdx := info.numParams
|
||||
let appArgs := expr.getAppArgs
|
||||
let rec extractInstances : Expr → RequestM (Array Name)
|
||||
| .const declName _ => do
|
||||
if ← ci.runMetaM i.lctx do Lean.Meta.isInstance declName then pure #[declName] else pure #[]
|
||||
| .app fn arg => do pure $ (← extractInstances fn).append (← extractInstances arg)
|
||||
| _ => pure #[]
|
||||
if let some instArg := appArgs.get? instIdx then
|
||||
for inst in (← extractInstances instArg) do
|
||||
results := results.append (← ci.runMetaM i.lctx <| locationLinksFromDecl i inst)
|
||||
results := results.append elaborators -- put elaborators at the end of the results
|
||||
return results
|
||||
| .ofFieldInfo fi =>
|
||||
if kind == type then
|
||||
let expr ← ci.runMetaM i.lctx do
|
||||
|
|
@ -157,8 +197,8 @@ def handleDefinition (kind : GoToKind) (p : TextDocumentPositionParams)
|
|||
|
||||
withWaitFindSnap doc (fun s => s.endPos > hoverPos)
|
||||
(notFoundX := pure #[]) fun snap => do
|
||||
if let some (ci, i) := snap.infoTree.hoverableInfoAt? (includeStop := true /- #767 -/) hoverPos then
|
||||
locationLinksOfInfo kind ci i snap.infoTree
|
||||
if let some infoWithCtx := snap.infoTree.hoverableInfoAt? (omitIdentApps := true) (includeStop := true /- #767 -/) hoverPos then
|
||||
locationLinksOfInfo kind infoWithCtx snap.infoTree
|
||||
else return #[]
|
||||
|
||||
open RequestM in
|
||||
|
|
@ -214,7 +254,7 @@ def getInteractiveTermGoal (p : Lsp.PlainTermGoalParams)
|
|||
let hoverPos := text.lspPosToUtf8Pos p.position
|
||||
withWaitFindSnap doc (fun s => s.endPos > hoverPos)
|
||||
(notFoundX := pure none) fun snap => do
|
||||
if let some (ci, i@(Elab.Info.ofTermInfo ti)) := snap.infoTree.termGoalAt? hoverPos then
|
||||
if let some {ctx := ci, info := i@(Elab.Info.ofTermInfo ti), ..} := snap.infoTree.termGoalAt? hoverPos then
|
||||
let ty ← ci.runMetaM i.lctx do
|
||||
instantiateMVars <| ti.expectedType?.getD (← Meta.inferType ti.expr)
|
||||
-- for binders, hide the last hypothesis (the binder itself)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import Lean.Server.FileWorker.RequestHandling
|
|||
/-! Registers all widget-related RPC procedures. -/
|
||||
|
||||
namespace Lean.Widget
|
||||
open Server
|
||||
open Server Lean.Elab
|
||||
|
||||
structure MsgToInteractive where
|
||||
msg : WithRpcRef MessageData
|
||||
|
|
@ -127,7 +127,7 @@ builtin_initialize
|
|||
(Array Lsp.LocationLink)
|
||||
fun ⟨kind, ⟨i⟩⟩ => RequestM.asTask do
|
||||
let rc ← read
|
||||
let ls ← FileWorker.locationLinksOfInfo kind i.ctx i.info
|
||||
let ls ← FileWorker.locationLinksOfInfo kind i
|
||||
if !ls.isEmpty then return ls
|
||||
-- TODO(WN): unify handling of delab'd (infoview) and elab'd (editor) applications
|
||||
let .ofTermInfo ti := i.info | return #[]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,33 @@ import Lean.PrettyPrinter
|
|||
|
||||
namespace Lean.Elab
|
||||
|
||||
/-- Elaborator information with elaborator context.
|
||||
|
||||
It can be thought of as a "thunked" elaboration computation that allows us
|
||||
to retroactively extract type information, symbol locations, etc.
|
||||
through arbitrary invocations of `runMetaM` (where the necessary context and state
|
||||
can be reconstructed from `ctx` and `info.lctx`).
|
||||
|
||||
W.r.t. widgets, this is used to tag different parts of expressions in `ppExprTagged`.
|
||||
This is the input to the RPC call `Lean.Widget.InteractiveDiagnostics.infoToInteractive`.
|
||||
It carries over information about delaborated
|
||||
`Info` nodes in a `CodeWithInfos`, and the associated pretty-printing
|
||||
functionality is purpose-specific to showing the contents of infoview popups.
|
||||
|
||||
For use in standard LSP go-to-definition (see `Lean.Server.FileWorker.locationLinksOfInfo`),
|
||||
all the elaborator information we need for similar tasks is already fully recoverable via
|
||||
the `InfoTree` structure (see `Lean.Elab.InfoTree.visitM`).
|
||||
There we use this as a convienience wrapper for queried nodes (e.g. the return value of
|
||||
`Lean.Elab.InfoTree.hoverableInfoAt?`). It also includes the children info nodes
|
||||
as additional context (this is unused in the RPC case, as delaboration has no notion of child nodes).
|
||||
|
||||
NOTE: This type is for internal use in the infoview/LSP. It should not be used in user widgets.
|
||||
-/
|
||||
structure InfoWithCtx where
|
||||
ctx : Elab.ContextInfo
|
||||
info : Elab.Info
|
||||
children : PersistentArray InfoTree
|
||||
|
||||
/-- Visit nodes, passing in a surrounding context (the innermost one) and accumulating results on the way back up. -/
|
||||
partial def InfoTree.visitM [Monad m]
|
||||
(preNode : ContextInfo → Info → (children : PersistentArray InfoTree) → m Unit := fun _ _ _ => pure ())
|
||||
|
|
@ -135,11 +162,16 @@ def InfoTree.smallestInfo? (p : Info → Bool) (t : InfoTree) : Option (ContextI
|
|||
infos.toArray.getMax? (fun a b => a.1 > b.1) |>.map fun (_, ci, i) => (ci, i)
|
||||
|
||||
/-- Find an info node, if any, which should be shown on hover/cursor at position `hoverPos`. -/
|
||||
partial def InfoTree.hoverableInfoAt? (t : InfoTree) (hoverPos : String.Pos) (includeStop := false) (omitAppFns := false) : Option (ContextInfo × Info) := Id.run do
|
||||
let results := t.visitM (m := Id) (postNode := fun ctx info _ results => do
|
||||
partial def InfoTree.hoverableInfoAt? (t : InfoTree) (hoverPos : String.Pos) (includeStop := false) (omitAppFns := false) (omitIdentApps := false) : Option InfoWithCtx := Id.run do
|
||||
let results := t.visitM (m := Id) (postNode := fun ctx info children results => do
|
||||
let mut results := results.bind (·.getD [])
|
||||
if omitAppFns && info.stx.isOfKind ``Parser.Term.app && info.stx[0].isIdent then
|
||||
results := results.filter (·.2.2.stx != info.stx[0])
|
||||
results := results.filter (·.2.info.stx != info.stx[0])
|
||||
if omitIdentApps && info.stx.isIdent then
|
||||
-- if an identifier stands for an application (e.g. in the case of a typeclass projection), prefer the application
|
||||
if let .ofTermInfo ti := info then
|
||||
if ti.expr.isApp then
|
||||
results := results.filter (·.2.info.stx != info.stx)
|
||||
unless results.isEmpty do
|
||||
return results -- prefer innermost results
|
||||
/-
|
||||
|
|
@ -161,7 +193,7 @@ partial def InfoTree.hoverableInfoAt? (t : InfoTree) (hoverPos : String.Pos) (in
|
|||
Int.negOfNat (r.stop - r.start).byteIdx,
|
||||
-- prefer results for constants over variables (which overlap at declaration names)
|
||||
if info matches .ofTermInfo { expr := .fvar .., .. } then 0 else 1)
|
||||
[(priority, ctx, info)]) |>.getD []
|
||||
[(priority, {ctx, info, children})]) |>.getD []
|
||||
-- sort results by lexicographical priority
|
||||
let maxPrio? :=
|
||||
let _ := @lexOrd
|
||||
|
|
@ -169,8 +201,8 @@ partial def InfoTree.hoverableInfoAt? (t : InfoTree) (hoverPos : String.Pos) (in
|
|||
let _ := @maxOfLe
|
||||
results.map (·.1) |>.maximum?
|
||||
let res? := results.find? (·.1 == maxPrio?) |>.map (·.2)
|
||||
if let some (_, i) := res? then
|
||||
if let .ofTermInfo ti := i then
|
||||
if let some i := res? then
|
||||
if let .ofTermInfo ti := i.info then
|
||||
if ti.expr.isSyntheticSorry then
|
||||
return none
|
||||
return res?
|
||||
|
|
@ -328,7 +360,7 @@ where
|
|||
stx.getNumArgs == 2 && stx[0].isToken "by" && stx[1].getNumArgs == 1 && stx[1][0].isMissing
|
||||
|
||||
|
||||
partial def InfoTree.termGoalAt? (t : InfoTree) (hoverPos : String.Pos) : Option (ContextInfo × Info) :=
|
||||
partial def InfoTree.termGoalAt? (t : InfoTree) (hoverPos : String.Pos) : Option InfoWithCtx :=
|
||||
-- In the case `f a b`, where `f` is an identifier, the term goal at `f` should be the goal for the full application `f a b`.
|
||||
hoverableInfoAt? t hoverPos (includeStop := true) (omitAppFns := true)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,13 @@
|
|||
import Lean.Elab.InfoTree
|
||||
import Lean.Message
|
||||
import Lean.Server.Rpc.Basic
|
||||
import Lean.Server.InfoUtils
|
||||
|
||||
namespace Lean.Widget
|
||||
|
||||
open Elab Server
|
||||
|
||||
/-- Elaborator information with elaborator context.
|
||||
|
||||
This is used to tag different parts of expressions in `ppExprTagged`.
|
||||
This is the input to the RPC call `Lean.Widget.InteractiveDiagnostics.infoToInteractive`.
|
||||
|
||||
The purpose of `InfoWithCtx` is to carry over information about delaborated
|
||||
`Info` nodes in a `CodeWithInfos`, and the associated pretty-printing
|
||||
functionality is purpose-specific to showing the contents of infoview popups.
|
||||
|
||||
NOTE: This type is for internal use in the infoview. It should not be used in user widgets. -/
|
||||
structure InfoWithCtx where
|
||||
ctx : Elab.ContextInfo
|
||||
info : Elab.Info
|
||||
deriving TypeName
|
||||
|
||||
deriving instance TypeName for InfoWithCtx
|
||||
deriving instance TypeName for MessageData
|
||||
deriving instance TypeName for LocalContext
|
||||
deriving instance TypeName for Elab.ContextInfo
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ Authors: Wojciech Nawrocki
|
|||
-/
|
||||
import Lean.PrettyPrinter
|
||||
import Lean.Server.Rpc.Basic
|
||||
import Lean.Server.InfoUtils
|
||||
import Lean.Widget.TaggedText
|
||||
import Lean.Widget.Basic
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ inductive DiffTag where
|
|||
/-- Information about a subexpression within delaborated code. -/
|
||||
structure SubexprInfo where
|
||||
/-- The `Elab.Info` node with the semantics of this part of the output. -/
|
||||
info : WithRpcRef InfoWithCtx
|
||||
info : WithRpcRef Lean.Elab.InfoWithCtx
|
||||
/-- The position of this subexpression within the top-level expression. See `Lean.SubExpr`. -/
|
||||
subexprPos : Lean.SubExpr.Pos
|
||||
-- TODO(WN): add fields for semantic highlighting
|
||||
|
|
@ -67,7 +68,7 @@ where
|
|||
| none => go subTt
|
||||
| some i =>
|
||||
let t : SubexprInfo := {
|
||||
info := WithRpcRef.mk { ctx, info := i }
|
||||
info := WithRpcRef.mk { ctx, info := i, children := .empty }
|
||||
subexprPos := n
|
||||
}
|
||||
TaggedText.tag t (go subTt)
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ def mkFoo₂ := mkFoo₁
|
|||
|
||||
syntax (name := elabTest) "test" : term
|
||||
|
||||
@[term_elab elabTest] def elabElabTest : Lean.Elab.Term.TermElab := fun _ _ => do
|
||||
@[term_elab elabTest] def elabElabTest : Lean.Elab.Term.TermElab := fun orig _ => do
|
||||
let stx ← `(2)
|
||||
Lean.Elab.Term.elabTerm stx none
|
||||
Lean.Elab.withMacroExpansionInfo orig stx $ Lean.Elab.Term.elabTerm stx none
|
||||
|
||||
--v textDocument/declaration
|
||||
#check test
|
||||
|
|
@ -61,6 +61,54 @@ macro_rules | `(test) => `(3)
|
|||
#check test
|
||||
--^ textDocument/definition
|
||||
|
||||
class Foo2 where
|
||||
foo : Nat → Nat
|
||||
foo' : Nat
|
||||
|
||||
class Foo3 [Foo2] where
|
||||
foo : [Foo2] → Nat
|
||||
|
||||
class inductive Foo4 : Nat → Type where
|
||||
| mk : Nat → Foo4 0
|
||||
|
||||
def Foo4.foo : [Foo4 n] → Nat
|
||||
| .mk n => n
|
||||
|
||||
class Foo5 where
|
||||
foo : Foo2
|
||||
|
||||
|
||||
instance : Foo2 := .mk id 0
|
||||
instance : Foo3 := .mk 0
|
||||
instance : Foo4 0 := .mk 0
|
||||
instance [foo2 : Foo2] : Foo5 := .mk foo2
|
||||
|
||||
-- should go-to instance
|
||||
--v textDocument/definition
|
||||
#check Foo2.foo 2
|
||||
--^ textDocument/definition
|
||||
#check (Foo2.foo)
|
||||
--^ textDocument/definition
|
||||
#check (Foo2.foo')
|
||||
--^ textDocument/definition
|
||||
|
||||
-- should go-to projection
|
||||
#check @Foo2.foo
|
||||
--^ textDocument/definition
|
||||
|
||||
-- test that the correct instance index is extracted
|
||||
#check (Foo3.foo)
|
||||
--^ textDocument/definition
|
||||
|
||||
-- non-projections should not go-to instance
|
||||
#check (Foo4.foo)
|
||||
--^ textDocument/definition
|
||||
|
||||
set_option pp.all true in
|
||||
-- test that multiple instances can be extracted
|
||||
#check (Foo5.foo)
|
||||
--^ textDocument/definition
|
||||
|
||||
-- duplicate definitions link to the original
|
||||
def mkFoo₁ := 1
|
||||
--^ textDocument/definition
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@
|
|||
"end": {"line": 38, "character": 38}},
|
||||
"targetRange":
|
||||
{"start": {"line": 38, "character": 22},
|
||||
"end": {"line": 40, "character": 34}},
|
||||
"end": {"line": 40, "character": 78}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 43, "character": 7},
|
||||
"end": {"line": 43, "character": 11}}}]
|
||||
|
|
@ -136,12 +136,140 @@
|
|||
{"start": {"line": 60, "character": 7},
|
||||
"end": {"line": 60, "character": 11}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 64, "character": 7}}
|
||||
"position": {"line": 87, "character": 16}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 64, "character": 2}, "end": {"line": 64, "character": 5}},
|
||||
"targetRange":
|
||||
{"start": {"line": 64, "character": 2}, "end": {"line": 64, "character": 5}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 87, "character": 7},
|
||||
"end": {"line": 87, "character": 18}}},
|
||||
{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 80, "character": 0}, "end": {"line": 80, "character": 8}},
|
||||
"targetRange":
|
||||
{"start": {"line": 80, "character": 0}, "end": {"line": 80, "character": 27}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 87, "character": 7},
|
||||
"end": {"line": 87, "character": 18}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 87, "character": 12}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 64, "character": 2}, "end": {"line": 64, "character": 5}},
|
||||
"targetRange":
|
||||
{"start": {"line": 64, "character": 2}, "end": {"line": 64, "character": 5}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 87, "character": 7},
|
||||
"end": {"line": 87, "character": 15}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 89, "character": 13}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 64, "character": 2}, "end": {"line": 64, "character": 5}},
|
||||
"targetRange":
|
||||
{"start": {"line": 64, "character": 2}, "end": {"line": 64, "character": 5}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 89, "character": 8},
|
||||
"end": {"line": 89, "character": 16}}},
|
||||
{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 80, "character": 0}, "end": {"line": 80, "character": 8}},
|
||||
"targetRange":
|
||||
{"start": {"line": 80, "character": 0}, "end": {"line": 80, "character": 27}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 89, "character": 8},
|
||||
"end": {"line": 89, "character": 16}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 91, "character": 13}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 65, "character": 2}, "end": {"line": 65, "character": 6}},
|
||||
"targetRange":
|
||||
{"start": {"line": 65, "character": 2}, "end": {"line": 65, "character": 6}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 91, "character": 8},
|
||||
"end": {"line": 91, "character": 17}}},
|
||||
{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 80, "character": 0}, "end": {"line": 80, "character": 8}},
|
||||
"targetRange":
|
||||
{"start": {"line": 80, "character": 0}, "end": {"line": 80, "character": 27}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 91, "character": 8},
|
||||
"end": {"line": 91, "character": 17}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 95, "character": 13}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 64, "character": 2}, "end": {"line": 64, "character": 5}},
|
||||
"targetRange":
|
||||
{"start": {"line": 64, "character": 2}, "end": {"line": 64, "character": 5}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 95, "character": 8},
|
||||
"end": {"line": 95, "character": 16}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 99, "character": 13}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 68, "character": 2}, "end": {"line": 68, "character": 5}},
|
||||
"targetRange":
|
||||
{"start": {"line": 68, "character": 2}, "end": {"line": 68, "character": 5}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 99, "character": 8},
|
||||
"end": {"line": 99, "character": 16}}},
|
||||
{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 81, "character": 0}, "end": {"line": 81, "character": 8}},
|
||||
"targetRange":
|
||||
{"start": {"line": 81, "character": 0}, "end": {"line": 81, "character": 24}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 99, "character": 8},
|
||||
"end": {"line": 99, "character": 16}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 103, "character": 13}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 73, "character": 4}, "end": {"line": 73, "character": 12}},
|
||||
"targetRange":
|
||||
{"start": {"line": 73, "character": 0}, "end": {"line": 74, "character": 12}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 103, "character": 8},
|
||||
"end": {"line": 103, "character": 16}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 108, "character": 13}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 77, "character": 2}, "end": {"line": 77, "character": 5}},
|
||||
"targetRange":
|
||||
{"start": {"line": 77, "character": 2}, "end": {"line": 77, "character": 5}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 108, "character": 8},
|
||||
"end": {"line": 108, "character": 16}}},
|
||||
{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 83, "character": 0}, "end": {"line": 83, "character": 8}},
|
||||
"targetRange":
|
||||
{"start": {"line": 83, "character": 0}, "end": {"line": 83, "character": 41}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 108, "character": 8},
|
||||
"end": {"line": 108, "character": 16}}},
|
||||
{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 80, "character": 0}, "end": {"line": 80, "character": 8}},
|
||||
"targetRange":
|
||||
{"start": {"line": 80, "character": 0}, "end": {"line": 80, "character": 27}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 108, "character": 8},
|
||||
"end": {"line": 108, "character": 16}}}]
|
||||
{"textDocument": {"uri": "file://goTo.lean"},
|
||||
"position": {"line": 112, "character": 7}}
|
||||
[{"targetUri": "file://goTo.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 9, "character": 4}, "end": {"line": 9, "character": 10}},
|
||||
"targetRange":
|
||||
{"start": {"line": 9, "character": 0}, "end": {"line": 17, "character": 1}},
|
||||
"originSelectionRange":
|
||||
{"start": {"line": 64, "character": 4},
|
||||
"end": {"line": 64, "character": 10}}}]
|
||||
{"start": {"line": 112, "character": 4},
|
||||
"end": {"line": 112, "character": 10}}}]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{"textDocument": {"uri": "file://goto2.lean"},
|
||||
{"textDocument": {"uri": "file://goTo2.lean"},
|
||||
"position": {"line": 10, "character": 15}}
|
||||
[{"targetUri": "file://goto2.lean",
|
||||
[{"targetUri": "file://goTo2.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 55}},
|
||||
"targetRange":
|
||||
|
|
@ -8,9 +8,9 @@
|
|||
"originSelectionRange":
|
||||
{"start": {"line": 10, "character": 11},
|
||||
"end": {"line": 10, "character": 20}}}]
|
||||
{"textDocument": {"uri": "file://goto2.lean"},
|
||||
{"textDocument": {"uri": "file://goTo2.lean"},
|
||||
"position": {"line": 10, "character": 27}}
|
||||
[{"targetUri": "file://goto2.lean",
|
||||
[{"targetUri": "file://goTo2.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 55}},
|
||||
"targetRange":
|
||||
|
|
@ -18,9 +18,9 @@
|
|||
"originSelectionRange":
|
||||
{"start": {"line": 10, "character": 23},
|
||||
"end": {"line": 10, "character": 30}}}]
|
||||
{"textDocument": {"uri": "file://goto2.lean"},
|
||||
{"textDocument": {"uri": "file://goTo2.lean"},
|
||||
"position": {"line": 10, "character": 11}}
|
||||
[{"targetUri": "file://goto2.lean",
|
||||
[{"targetUri": "file://goTo2.lean",
|
||||
"targetSelectionRange":
|
||||
{"start": {"line": 14, "character": 4}, "end": {"line": 14, "character": 5}},
|
||||
"targetRange":
|
||||
Loading…
Add table
Reference in a new issue