Zulip Chat Archive
Stream: lean4
Topic: code action behaviour?
Siddhartha Gadgil (Nov 18 2022 at 09:26):
I was experimenting with the (low level) code actions. This is very nice, especially that lazy actions are supported.
But there was one piece of unexpected behaviour and a related question regarding the examples in the codeaction.lean
test file.
- I would have guessed that the code actions would replace the selected token with "Hello!!!" or the directory, as it seemed the range should be for the syntax object and this should be replaced by the new text. Instead they are inserted.
- And the question: in a real case, the inserted text will depend on the text in the range. How do I access this?
@Edward Ayers @Gabriel Ebner are there some examples I should look at?
Edward Ayers (Nov 18 2022 at 09:31):
Hello! There is an example of usage in the tests which it sounds like you found. You can get it to replace text by setting the range
field in the TextEdit
object. To determine the range of text that needs to be replaced you need to get the Syntax node of the text.
Edward Ayers (Nov 18 2022 at 09:32):
With Lean.Syntax.getRange?
Edward Ayers (Nov 18 2022 at 09:39):
Recovering an expression or piece of syntax from a document position can be a little involved, but the way to do it is to find a snapshot for a given position and then search the InfoTree to find what you are looking for. There are lots of examples of this in RequestHandling.lean
Edward Ayers (Nov 18 2022 at 09:42):
Also Lean.Syntax.getRange?
will give you a Lean range, but this needs to be converted to an LSP range using leanPosToLspPos
Siddhartha Gadgil (Nov 18 2022 at 09:52):
I take it that the starting point should be to use params.range
to get an LSP range and convert this to a Lean range. Is that correct?
Edward Ayers (Nov 18 2022 at 09:54):
yes
Siddhartha Gadgil (Nov 18 2022 at 09:56):
Thanks. Will experiment and ask again for any questions.
Siddhartha Gadgil (Nov 18 2022 at 14:34):
Been digging through the source code but am asking as there may be an easy answer: how do I get the contents of the current file?
Siddhartha Gadgil (Nov 18 2022 at 14:35):
With position as above which can be converted.
Siddhartha Gadgil (Nov 18 2022 at 14:37):
I do see a function readDoc
. However this involves a request context. Can I call it when defining a code-action?
Sebastian Ullrich (Nov 18 2022 at 14:43):
I think you can retrieve the request context in the eager part
Siddhartha Gadgil (Nov 18 2022 at 14:49):
I see many ways to get a DocumentUri. Is there a function that gets the actual document from this?
Edward Ayers (Nov 18 2022 at 14:51):
let doc ← readDoc
doc.meta.uri
Edward Ayers (Nov 18 2022 at 14:53):
doc.meta.text
has the actual sourcetext somewhere
Siddhartha Gadgil (Nov 18 2022 at 14:55):
I mean the other way. CodeActionParams
has the uri and the identifiers. I need the new text as a function of the current file.
Siddhartha Gadgil (Nov 18 2022 at 14:55):
In an IO context readDoc
does not work.
Joachim Breitner (Nov 18 2022 at 15:10):
I’d also like to use readDoc
, but in the Elaborator monad (maybe with a piece of Syntax
to locate the doc), so a suggestion here is welcome :-)
Edward Ayers (Nov 18 2022 at 15:11):
You can pass in the RequestContext as a closure
Siddhartha Gadgil (Nov 18 2022 at 15:12):
Edward Ayers said:
You can pass in the RequestContext as a closure
Can you give an example, say within the lazy part of the codeactions.lean
file.
Siddhartha Gadgil (Nov 18 2022 at 15:13):
I want the inserted text to depend on the current text.
Siddhartha Gadgil (Nov 18 2022 at 15:15):
I don't know how to get the RequestContext
from the CodeActionParams
Siddhartha Gadgil (Nov 18 2022 at 15:20):
It seems to me that it should be common for code-actions to depend on the current text. If I follow the code in the definitions I end up with TextEdit
which asks for the new text, but not as a function of the current text.
Edward Ayers (Nov 18 2022 at 15:22):
@[codeActionProvider]
def xyz : CodeActionProvider := fun params snap => do
let rc : RequestContext ← read
let ca : CodeAction := {
title := "xyz"
}
let lazy : RequestM CodeAction := do
-- this is a requestM
let doc ← RequestM.readDoc
return ca
return #[{
eager := ca
lazy? := some <| (EIO.toIO (fun x => x.message)) <| ReaderT.run lazy rc
}]
Edward Ayers (Nov 18 2022 at 15:24):
I admit this is quite clunky
Siddhartha Gadgil (Nov 18 2022 at 15:24):
Thanks a lot.
Sebastian Ullrich (Nov 18 2022 at 15:44):
Joachim Breitner said:
I’d also like to use
readDoc
, but in the Elaborator monad (maybe with a piece ofSyntax
to locate the doc), so a suggestion here is welcome :-)
@Edward Ayers This makes me wonder whether elaborators really should be in charge of adding widgets. I'm imagining an alternative design where widgets are created by server handlers triggered by nodes in the info tree (perhaps containing data added by elaborators specifically for widget visualization). This would have the advantage that not only does the widget creation code have access to server data, you can also add widgets for existing elaborators, e.g. +/- buttons for any elabNumLit
node.
Anand Rao (Nov 18 2022 at 17:16):
Edward Ayers said:
Also
Lean.Syntax.getRange?
will give you a Lean range, but this needs to be converted to an LSP range usingleanPosToLspPos
Is there a similar function from LspPos
to String.Pos
? I am trying to get the user's cursor position as a String.Pos
. So far I have been using _snap.beginPos
as a reasonable approximation, but in my use case it would be better to have the actual position. I believe params.range
starts and ends at the same position when nothing is selected, so I was wondering if I could just use that position (which is an LspPos
) to get a String.Pos
.
Edward Ayers (Nov 18 2022 at 17:25):
I think lspPosToUtf8Pos
and toPosition
should do it
Last updated: Dec 20 2023 at 11:08 UTC