-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multi-expression selection #275
Conversation
b9236fa
to
10932c2
Compare
The API is sufficient to expose work by @KaseQuark on recording.mp4 |
@@ -148,6 +148,8 @@ class RpcSessionForFile { | |||
try { | |||
const result = await this.sessions.iface.call({ method, params, sessionId, ... pos }); | |||
this.registerRefs(result); | |||
// HACK: most of our types are `T | undefined` so try to return something matching that interface | |||
if (result === null) return undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we can't just use T | null
in the interface types instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but this is the least invasive change which doesn't require all downstream code to check for !== null
(or use truthish checks). IMO this is justified because null
vs undefined
is one of the many bizarre parts of JS with unclear semantics and it is easier to stick to always using undefined
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One concrete case where this pops up is with getInteractiveGoals
.
{ goals: await getInteractiveGoals(...) }
-- where { goals?: InteractiveGoals }
If we keep null
, then the easy fix would be to add a ?? undefined
to the use site. But converting null
to undefined
seems convenient as well.
Note that we run into exactly the same issue with Option Foo
, where the ToJson
instance produces null
. For consistency it might be better to avoid any special case hacks here (since it gives the incorrect impression that T | undefined
is the correct RPC API for Option T
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahhh, you correctly point out that our entire RPC API is wrong. We serialize structure fields marked with the magic ?
as missing similarly to Serde's skip_serializing_if
. In JS accessing those fields gives undefined
. But we cannot do this for top-level values as there is only a null
but no undefined
in JSON. For example
structure Foo where
a? : Option String
b : Option String
deriving ToJson
/- {"b": null} -/
#eval toJson { a? := none, b := none : Foo }
so all the top-level Option SomeResponse
calls really return T | null
. In this case I guess we should go through the whole API and adjust it, and make a breaking release. Let's do this in another PR however, and temporarily keep the hack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me.
There are many cases where we want to tell Lean which parts of the goal state are relevant to a particular action. For example,
simp [h₁, h₂]
marks these two hypotheses as the rewrite rules to use. This PR adds a mechanism to select one or more locations within the goal state. Belowh₁, h₂
, and the RHS of the goal type are selected.Use cases
1. Tactic support and suggestions
This enables writing user widgets which use the current selection as a context/relevance filter for which parts of the goal to process. For example, the following widget (source code) becomes quite easily implementable:
recording.mp4
I believe that this also makes contextual suggestions (leanprover/lean4#1223) implementable in "user space", i.e. without touching core, as a user widget, and thus supersedes the locations part of that RFC.
2. Diagram contexts
In any production-sized local context it is difficult to algorithmically determine which hypotheses and values are relevant to drawing a diagram. Thus we defer the job of selecting what should be drawn, e.g. which relations between sets to include in a Venn diagram, to the user.
Implementation
This is based on the contextual suggestions prototype by @EdAyers but diverges from it in that locations are more strongly typed as follows.
Moreover we elect not to show extra information such as suggestions in popups because they are already too cramped by docstrings. Instead, extra info should be shown as an extra panel below the tactic state, i.e. as a user widget. The infoview popups will probably not become extensible.
We extend the data passed to user widgets by the current goal state as well as the selection.
We extend the
InteractiveGoal
type with a reference to the metavariable context. This eliminates the need discussed here for RPC handlers invoked by user widgets to search the server state forSnapshot
s and retrieve the goal state from those, effectively duplicating the work thatgetInteractiveGoals
had already done. This used to result in unnecessarily brutal-looking server-side code, and could lead to potential inconsistencies if the goal state retrieval is not exactly the same. This relies on the companion PR tolean4
.Other changes
case
blocks collapsible which helps read huge tactic states and moved the 'copy to comment' button down into<Goal>
so that term goals are also copyable. If these are controversial changes I can revert.@leanprover/infoview
/