rename message to hint
This commit is contained in:
@@ -123,7 +123,7 @@ elab "Path" s:Parser.path : command => do
|
||||
|
||||
end metadata
|
||||
|
||||
/-! ## Messages -/
|
||||
/-! ## Hints -/
|
||||
|
||||
open Lean Meta Elab Command Term
|
||||
|
||||
@@ -144,38 +144,37 @@ def mkGoalSyntax (s : Term) : List (Ident × Term) → MacroM Term
|
||||
| (n, t)::tail => do return (← `(∀ $n : $t, $(← mkGoalSyntax s tail)))
|
||||
| [] => return s
|
||||
|
||||
/-- Declare a message. This version doesn't prevent the unused linter variable from running. -/
|
||||
local elab "Message'" decls:mydecl* ":" goal:term "=>" msg:str : command => do
|
||||
let g ← liftMacroM $ mkGoalSyntax goal (decls.map (λ decl => (getIdent decl, getType decl))).toList
|
||||
let g ← liftTermElabM do (return ← elabTermAndSynthesize g none)
|
||||
modifyCurLevel fun level => pure {level with messages := level.messages.push {
|
||||
goal := g,
|
||||
intros := decls.size,
|
||||
message := msg.getString }}
|
||||
|
||||
/--
|
||||
Declare a hint. This version doesn't prevent the unused linter variable from running.
|
||||
The difference between hints/messages is that hints should be hidden by default, while
|
||||
messages are visible.
|
||||
-/
|
||||
/-- Declare a hint. This version doesn't prevent the unused linter variable from running. -/
|
||||
local elab "Hint'" decls:mydecl* ":" goal:term "=>" msg:str : command => do
|
||||
let g ← liftMacroM $ mkGoalSyntax goal (decls.map (λ decl => (getIdent decl, getType decl))).toList
|
||||
let g ← liftTermElabM do (return ← elabTermAndSynthesize g none)
|
||||
modifyCurLevel fun level => pure {level with messages := level.messages.push {
|
||||
modifyCurLevel fun level => pure {level with hints := level.hints.push {
|
||||
goal := g,
|
||||
intros := decls.size,
|
||||
spoiler := true,
|
||||
message := msg.getString }}
|
||||
text := msg.getString }}
|
||||
|
||||
/--
|
||||
Declare a hint. This version doesn't prevent the unused linter variable from running.
|
||||
A hidden hint is only displayed if explicitly requested by the user.
|
||||
-/
|
||||
local elab "HiddenHint'" decls:mydecl* ":" goal:term "=>" msg:str : command => do
|
||||
let g ← liftMacroM $ mkGoalSyntax goal (decls.map (λ decl => (getIdent decl, getType decl))).toList
|
||||
let g ← liftTermElabM do (return ← elabTermAndSynthesize g none)
|
||||
modifyCurLevel fun level => pure {level with hints := level.hints.push {
|
||||
goal := g,
|
||||
intros := decls.size,
|
||||
hidden := true,
|
||||
text := msg.getString }}
|
||||
|
||||
/-- Declare a message in reaction to a given tactic state in the current level. -/
|
||||
macro "Message" decls:mydecl* ":" goal:term "=>" msg:str : command => do
|
||||
`(set_option linter.unusedVariables false in Message' $decls* : $goal => $msg)
|
||||
|
||||
/-- Declare a hint in reaction to a given tactic state in the current level. -/
|
||||
macro "Hint" decls:mydecl* ":" goal:term "=>" msg:str : command => do
|
||||
`(set_option linter.unusedVariables false in Hint' $decls* : $goal => $msg)
|
||||
|
||||
/-- Declare a hidden hint in reaction to a given tactic state in the current level. -/
|
||||
macro "HiddenHint" decls:mydecl* ":" goal:term "=>" msg:str : command => do
|
||||
`(set_option linter.unusedVariables false in HiddenHint' $decls* : $goal => $msg)
|
||||
|
||||
/-! ## Tactics -/
|
||||
|
||||
/-- Declare a documentation entry for some tactic.
|
||||
|
||||
@@ -8,20 +8,20 @@ defined in this file.
|
||||
|
||||
open Lean
|
||||
|
||||
/-! ## Messages -/
|
||||
/-! ## Hints -/
|
||||
|
||||
/--
|
||||
A message to be displayed to the user as instruction/hint.
|
||||
A hint to help the user with a specific goal state
|
||||
|
||||
Fields
|
||||
(TODO)
|
||||
spoiler: If true, then message should be hidden by default
|
||||
hidden: If true, then hint should be hidden by default
|
||||
-/
|
||||
structure GoalMessageEntry where
|
||||
structure GoalHintEntry where
|
||||
goal : Expr
|
||||
intros : Nat
|
||||
message : String
|
||||
spoiler : Bool := false
|
||||
text : String
|
||||
hidden : Bool := false
|
||||
deriving Repr
|
||||
|
||||
/-! ## Tactic documentation -/
|
||||
@@ -200,7 +200,7 @@ structure GameLevel where
|
||||
conclusion: String := default
|
||||
tactics: Array TacticDocEntry := default
|
||||
lemmas: Array LemmaDocEntry := default
|
||||
messages: Array GoalMessageEntry := default
|
||||
hints: Array GoalHintEntry := default
|
||||
goal : TSyntax `Lean.Parser.Command.declSig := default
|
||||
descrText: String := default
|
||||
descrFormat : String := default
|
||||
|
||||
@@ -10,57 +10,13 @@ open Meta
|
||||
|
||||
/-! ## GameGoal -/
|
||||
|
||||
structure GameLocalDecl where
|
||||
userName : Name
|
||||
type : String
|
||||
structure GameHint where
|
||||
text : String
|
||||
hidden : Bool
|
||||
deriving FromJson, ToJson
|
||||
|
||||
structure GameMessage where
|
||||
message : String
|
||||
spoiler : Bool
|
||||
deriving FromJson, ToJson
|
||||
|
||||
structure GameGoal where
|
||||
objects : List GameLocalDecl
|
||||
assumptions : List GameLocalDecl
|
||||
goal : String
|
||||
messages : Array GameMessage
|
||||
deriving FromJson, ToJson
|
||||
|
||||
|
||||
def Lean.MVarId.toGameGoal (goal : MVarId) (messages : Array GameMessage) : MetaM GameGoal := do
|
||||
match (← getMCtx).findDecl? goal with
|
||||
| none => throwError "unknown goal"
|
||||
| some mvarDecl => do
|
||||
-- toGameGoalAux below will sort local declarations from the context of goal into data and assumptions,
|
||||
-- discarding auxilliary declarations
|
||||
let rec toGameGoalAux : List (Option LocalDecl) → MetaM (List LocalDecl × List LocalDecl)
|
||||
| (some decl)::t => withLCtx mvarDecl.lctx mvarDecl.localInstances do
|
||||
let (o, a) ← toGameGoalAux t
|
||||
if decl.isAuxDecl then
|
||||
return (o, a)
|
||||
if (← inferType decl.type).isProp then
|
||||
return (o, decl::a)
|
||||
else
|
||||
return (decl::o, a)
|
||||
| none:: t => toGameGoalAux t
|
||||
| [] => return ([], [])
|
||||
withLCtx mvarDecl.lctx mvarDecl.localInstances do
|
||||
let (objects, assumptions) ← toGameGoalAux mvarDecl.lctx.decls.toList
|
||||
let objects ← objects.mapM fun decl => do
|
||||
return { userName := decl.userName, type := toString (← Meta.ppExpr decl.type) }
|
||||
let assumptions ← assumptions.mapM fun decl => do
|
||||
return { userName := decl.userName, type := toString (← Meta.ppExpr decl.type) }
|
||||
return {objects := objects, assumptions := assumptions, goal := toString (← Meta.ppExpr mvarDecl.type), messages }
|
||||
|
||||
namespace GameServer
|
||||
|
||||
/-- `Game.getGoals` client<-server reply. -/
|
||||
structure PlainGoal where
|
||||
/-- The pretty-printed goals, empty if all accomplished. -/
|
||||
goals : Array GameGoal
|
||||
deriving FromJson, ToJson
|
||||
|
||||
-- TODO: Find a better way to pass on the file name?
|
||||
def levelIdFromFileName [Monad m] [MonadError m] [MonadEnv m] (fileName : String) : m LevelId := do
|
||||
let fileParts := fileName.splitOn "/"
|
||||
@@ -99,26 +55,26 @@ def matchDecls (declMvars : Array Expr) (declFvars : Array Expr) : MetaM Bool :=
|
||||
return true
|
||||
|
||||
open Meta in
|
||||
/-- Find all messages whose trigger matches the current goal -/
|
||||
def findMessages (goal : MVarId) (doc : FileWorker.EditableDocument) : MetaM (Array GameMessage) := do
|
||||
/-- Find all hints whose trigger matches the current goal -/
|
||||
def findHints (goal : MVarId) (doc : FileWorker.EditableDocument) : MetaM (Array GameHint) := do
|
||||
goal.withContext do
|
||||
let level ← getLevelByFileName doc.meta.mkInputContext.fileName
|
||||
let messages ← level.messages.filterMapM fun message => do
|
||||
let (declMvars, binderInfo, messageGoal) ← forallMetaBoundedTelescope message.goal message.intros
|
||||
let hints ← level.hints.filterMapM fun hint => do
|
||||
let (declMvars, binderInfo, hintGoal) ← forallMetaBoundedTelescope hint.goal hint.intros
|
||||
-- TODO: Protext mvars in the type of `goal` to be instantiated?
|
||||
if ← isDefEq messageGoal (← inferType $ mkMVar goal) -- TODO: also check assumptions
|
||||
if ← isDefEq hintGoal (← inferType $ mkMVar goal) -- TODO: also check assumptions
|
||||
then
|
||||
let lctx ← getLCtx -- Local context of the `goal`
|
||||
if ← matchDecls declMvars lctx.getFVars
|
||||
then
|
||||
return some { message := message.message, spoiler := message.spoiler }
|
||||
return some { text := hint.text, hidden := hint.hidden }
|
||||
else return none
|
||||
else return none
|
||||
return messages
|
||||
return hints
|
||||
|
||||
structure GameInteractiveGoal where
|
||||
goal : InteractiveGoal
|
||||
messages: Array GameMessage
|
||||
hints: Array GameHint
|
||||
deriving RpcEncodable
|
||||
|
||||
structure GameInteractiveGoals where
|
||||
@@ -148,8 +104,8 @@ def getInteractiveGoals (p : Lsp.PlainGoalParams) : RequestM (RequestTask (Optio
|
||||
return List.toArray <| if useAfter then ti.goalsAfter else ti.goalsBefore
|
||||
let goals ← ci.runMetaM {} do
|
||||
goals.mapM fun goal => do
|
||||
let messages ← findMessages goal doc
|
||||
return {goal := ← Widget.goalToInteractive goal, messages}
|
||||
let hints ← findHints goal doc
|
||||
return {goal := ← Widget.goalToInteractive goal, hints}
|
||||
-- compute the goal diff
|
||||
-- let goals ← ciAfter.runMetaM {} (do
|
||||
-- try
|
||||
|
||||
Reference in New Issue
Block a user