reorganisational draft
This commit is contained in:
+125
-97
@@ -78,33 +78,40 @@ in the first level and get enabled during the game.
|
||||
|
||||
/-! ## Doc entries -/
|
||||
|
||||
/-- Throw a warning if inventory doc does not exist. If `(default := _)` is provided,
|
||||
it will create a new inverntory entry with the specified default description. -/
|
||||
def checkInventoryDoc (type : InventoryType) (name : Syntax)
|
||||
(default : Option (String) := none) : CommandElabM Unit := do
|
||||
let some _ := (inventoryDocExt.getState (← getEnv)).find?
|
||||
(fun x => x.name == name.getId && x.type == type)
|
||||
| match default with
|
||||
| some _ =>
|
||||
logInfoAt name (m!"Missing {type} Documentation: {name}, used provided default (e.g. " ++
|
||||
m!"statement description) instead. If you want to write your own description, add " ++
|
||||
m!"`{type}Doc {name}` somewhere above this statement.")
|
||||
| none =>
|
||||
logWarningAt name (m!"Missing {type} Documentation: {name}\nAdd `{type}Doc {name}` " ++
|
||||
m!"somewhere above this statement.")
|
||||
|
||||
let default₀ := match default with
|
||||
| some d => d
|
||||
| none => "missing"
|
||||
|
||||
-- Create a default inventory entry
|
||||
let n := name.getId
|
||||
modifyEnv (inventoryDocExt.addEntry · {
|
||||
name := n
|
||||
/-- Checks if `inventoryKeyExt` contains an entry with `(type, name)` and yields
|
||||
a warning otherwise. If `template` is provided, it will add such an entry instead of yielding a
|
||||
warning. -/
|
||||
def checkInventoryDoc (type : InventoryType) (name : Ident)
|
||||
(template : Option String := none) : CommandElabM Unit := do
|
||||
-- note: `name` is an `Ident` (instead of `Name`) for the log messages.
|
||||
let env ← getEnv
|
||||
let n := name.getId
|
||||
-- Find a key with matching `(type, name)`.
|
||||
match (inventoryKeyExt.getState env).findIdx?
|
||||
(fun x => x.name == n && x.type == type) with
|
||||
-- Nothing to do if the entry exists
|
||||
| some _ => pure ()
|
||||
| none =>
|
||||
match template with
|
||||
-- Warn about missing documentation
|
||||
| none =>
|
||||
-- We just add a dummy entry
|
||||
modifyEnv (inventoryKeyExt.addEntry · {
|
||||
type := type
|
||||
displayName := s!"{n}" -- TODO: for lemmas, only take the last part of the name
|
||||
name := name.getId
|
||||
category := if type == .Lemma then s!"{n.getPrefix}" else "" })
|
||||
logWarningAt name (m!"Missing {type} Documentation: {name}\nAdd `{type}Doc {name}` " ++
|
||||
m!"somewhere above this statement.")
|
||||
-- Add the default documentation
|
||||
| some s =>
|
||||
modifyEnv (inventoryKeyExt.addEntry · {
|
||||
type := type
|
||||
name := name.getId
|
||||
category := if type == .Lemma then s!"{n.getPrefix}" else ""
|
||||
content := default₀ })
|
||||
content := s })
|
||||
logInfoAt name (m!"Missing {type} Documentation: {name}, used provided default (e.g. " ++
|
||||
m!"statement description) instead. If you want to write your own description, add " ++
|
||||
m!"`{type}Doc {name}` somewhere above this statement.")
|
||||
|
||||
/-- Documentation entry of a tactic. Example:
|
||||
|
||||
@@ -116,8 +123,7 @@ TacticDoc rw "`rw` stands for rewrite, etc. "
|
||||
* The description is a string supporting Markdown.
|
||||
-/
|
||||
elab "TacticDoc" name:ident content:str : command =>
|
||||
modifyEnv (inventoryDocExt.addEntry · {
|
||||
category := default
|
||||
modifyEnv (inventoryKeyExt.addEntry · {
|
||||
type := .Tactic
|
||||
name := name.getId
|
||||
displayName := name.getId.toString
|
||||
@@ -136,12 +142,18 @@ LemmaDoc Nat.succ_pos as "succ_pos" in "Nat" "says `0 < n.succ`, etc."
|
||||
* The description is a string supporting Markdown.
|
||||
-/
|
||||
elab "LemmaDoc" name:ident "as" displayName:str "in" category:str content:str : command =>
|
||||
modifyEnv (inventoryDocExt.addEntry · {
|
||||
name := name.getId,
|
||||
modifyEnv (inventoryKeyExt.addEntry · {
|
||||
type := .Lemma
|
||||
displayName := displayName.getString,
|
||||
category := category.getString,
|
||||
name := name.getId
|
||||
category := category.getString
|
||||
displayName := displayName.getString
|
||||
content := content.getString })
|
||||
-- TODO: Catch the following behaviour.
|
||||
-- 1. if `LemmaDoc` appears in the same file as `Statement`, it will silently use
|
||||
-- it but display the info that it wasn't found in `Statement`
|
||||
-- 2. if it appears in a later file, however, it will silently not do anything and keep
|
||||
-- the first one.
|
||||
|
||||
|
||||
/-- Documentation entry of a definition. Example:
|
||||
|
||||
@@ -154,31 +166,63 @@ DefinitionDoc Function.Bijective as "Bijective" "defined as `Injective f ∧ Sur
|
||||
* The string following `as` is the displayed name (in the Inventory).
|
||||
* The description is a string supporting Markdown.
|
||||
-/
|
||||
elab "DefinitionDoc" name:ident "as" displayName:str content:str : command =>
|
||||
modifyEnv (inventoryDocExt.addEntry · {
|
||||
category := default
|
||||
elab "DefinitionDoc" name:ident "as" displayName:str template:str : command =>
|
||||
modifyEnv (inventoryKeyExt.addEntry · {
|
||||
type := .Definition
|
||||
name := name.getId,
|
||||
displayName := displayName.getString,
|
||||
content := content.getString })
|
||||
content := template.getString })
|
||||
|
||||
/-! ## Add inventory items -/
|
||||
|
||||
-- namespace Lean.PrettyPrinter
|
||||
-- def ppSignature' (c : Name) : MetaM String := do
|
||||
-- let decl ← getConstInfo c
|
||||
-- let e := .const c (decl.levelParams.map mkLevelParam)
|
||||
-- let (stx, _) ← delabCore e (delab := Delaborator.delabConstWithSignature)
|
||||
-- let f ← ppTerm stx
|
||||
-- return toString f
|
||||
-- end Lean.PrettyPrinter
|
||||
|
||||
def getStatement (name : Name) : CommandElabM MessageData := do
|
||||
-- let c := name.getId
|
||||
|
||||
let decl ← getConstInfo name
|
||||
-- -- TODO: How to go between CommandElabM and MetaM
|
||||
|
||||
-- addCompletionInfo <| .id name c (danglingDot := false) {} none
|
||||
return ← addMessageContextPartial (.ofPPFormat { pp := fun
|
||||
| some ctx => ctx.runMetaM <| ppExpr decl.type
|
||||
-- PrettyPrinter.ppSignature' c
|
||||
-- PrettyPrinter.ppSignature c
|
||||
| none => return "that's a bug." })
|
||||
|
||||
-- Note: We use `String` because we can't send `MessageData` as json, but
|
||||
-- `MessageData` might be better for interactive highlighting.
|
||||
/-- Get a string of the form `my_lemma (n : ℕ) : n + n = 2 * n`. -/
|
||||
def getStatementString (name : Name) : CommandElabM String := do
|
||||
try
|
||||
return ← (← getStatement name).toString
|
||||
catch
|
||||
| _ => throwError m!"Could not find {name} in context."
|
||||
-- TODO: I think it would be nicer to unresolve Namespaces as much as possible.
|
||||
|
||||
/-- Declare tactics that are introduced by this level. -/
|
||||
elab "NewTactic" args:ident* : command => do
|
||||
for name in ↑args do checkInventoryDoc .Tactic name
|
||||
for name in ↑args do checkInventoryDoc .Tactic name -- TODO: Add (template := "[docstring]")
|
||||
modifyCurLevel fun level => pure {level with
|
||||
tactics := {level.tactics with new := args.map (·.getId)}}
|
||||
|
||||
/-- Declare lemmas that are introduced by this level. -/
|
||||
elab "NewLemma" args:ident* : command => do
|
||||
for name in ↑args do checkInventoryDoc .Lemma name
|
||||
for name in ↑args do
|
||||
checkInventoryDoc .Lemma name -- TODO: Add (template := "[mathlib]")
|
||||
modifyCurLevel fun level => pure {level with
|
||||
lemmas := {level.lemmas with new := args.map (·.getId)}}
|
||||
|
||||
/-- Declare definitions that are introduced by this level. -/
|
||||
elab "NewDefinition" args:ident* : command => do
|
||||
for name in ↑args do checkInventoryDoc .Definition name
|
||||
for name in ↑args do checkInventoryDoc .Definition name -- TODO: Add (template := "[mathlib]")
|
||||
modifyCurLevel fun level => pure {level with
|
||||
definitions := {level.definitions with new := args.map (·.getId)}}
|
||||
|
||||
@@ -228,22 +272,6 @@ elab "LemmaTab" category:str : command =>
|
||||
|
||||
/-! # Exercise Statement -/
|
||||
|
||||
-- TODO: Instead of this, it would be nice to have a proper syntax parser that enables
|
||||
-- us highlighting on the client side.
|
||||
partial def reprintCore : Syntax → Option Format
|
||||
| Syntax.missing => none
|
||||
| Syntax.atom _ val => val.trim
|
||||
| Syntax.ident _ rawVal _ _ => rawVal.toString
|
||||
| Syntax.node _ _ args =>
|
||||
match args.toList.filterMap reprintCore with
|
||||
| [] => none
|
||||
| [arg] => arg
|
||||
| args => Format.group <| Format.nest 2 <| Format.joinSep args " "
|
||||
|
||||
/-- `reprint` is used to display the Lean-statement to the user-/
|
||||
def reprint (stx : Syntax) : Format :=
|
||||
reprintCore stx |>.getD ""
|
||||
|
||||
/-- A `attr := ...` option for `Statement`. Add attributes to the defined theorem. -/
|
||||
syntax statementAttr := "(" &"attr" ":=" Parser.Term.attrInstance,* ")"
|
||||
-- TODO
|
||||
@@ -259,14 +287,9 @@ elab "Statement" statementName:ident ? descr:str ? sig:declSig val:declVal : com
|
||||
-- Save the messages before evaluation of the proof.
|
||||
let initMsgs ← modifyGet fun st => (st.messages, { st with messages := {} })
|
||||
|
||||
-- Check that statement has a docs entry.
|
||||
match statementName with
|
||||
| some name => checkInventoryDoc .Lemma name (default := descr)
|
||||
| none => pure ()
|
||||
|
||||
-- The default name of the statement is `[Game].[World].level[no.]`, e.g. `NNG.Addition.level1`
|
||||
-- However, this should not be used when designing the game.
|
||||
let defaultDeclName : Name := (← getCurGame).name ++ (← getCurWorld).name ++
|
||||
let defaultDeclName : Ident := mkIdent <| (← getCurGame).name ++ (← getCurWorld).name ++
|
||||
("level" ++ toString lvlIdx : String)
|
||||
|
||||
-- Add theorem to context.
|
||||
@@ -277,35 +300,21 @@ elab "Statement" statementName:ident ? descr:str ? sig:declSig val:declVal : com
|
||||
let origType := (env.constants.map₁.find! name.getId).type
|
||||
-- TODO: Check if `origType` agrees with `sig` and output `logInfo` instead of `logWarning`
|
||||
-- in that case.
|
||||
logWarningAt name m!"Environment already contains {name.getId}!
|
||||
Only the existing statement will be available in later levels:
|
||||
|
||||
{origType}"
|
||||
-- let (binders, typeStx) := expandDeclSig sig
|
||||
-- --let type ← Term.elabType typeStx
|
||||
-- runTermElabM (fun vars =>
|
||||
-- Term.elabBinders binders.getArgs (fun xs => do
|
||||
-- let type ← Term.elabType typeStx
|
||||
-- --Term.synthesizeSyntheticMVarsNoPostponing
|
||||
-- --let type ← instantiateMVars type
|
||||
-- --let type ← mkForallFVars xs type
|
||||
-- ))
|
||||
--let newType := Term.elabTerm sig.raw
|
||||
--dbg_trace newType
|
||||
--logInfo origType
|
||||
-- dbg_trace sig
|
||||
-- dbg_trace origType
|
||||
--dbg_trace (env.constants.map₁.find! name.getId).value! -- that's the proof
|
||||
--let newType := Lean.Elab.Term.elabTerm sig none
|
||||
|
||||
let thmStatement ← `(theorem $(mkIdent defaultDeclName) $sig $val)
|
||||
logWarningAt name (m!"Environment already contains {name.getId}! Only the existing " ++
|
||||
m!"statement will be available in later levels:\n\n{origType}")
|
||||
let thmStatement ← `(theorem $defaultDeclName $sig $val)
|
||||
elabCommand thmStatement
|
||||
-- Check that statement has a docs entry.
|
||||
checkInventoryDoc .Lemma name (template := descr)
|
||||
|
||||
else
|
||||
-- logInfo attr
|
||||
let thmStatement ← `( theorem $(mkIdent name.getId) $sig $val)
|
||||
let thmStatement ← `( theorem $name $sig $val)
|
||||
elabCommand thmStatement
|
||||
-- Check that statement has a docs entry.
|
||||
checkInventoryDoc .Lemma name (template := descr)
|
||||
|
||||
| none =>
|
||||
let thmStatement ← `(theorem $(mkIdent defaultDeclName) $sig $val)
|
||||
let thmStatement ← `(theorem $defaultDeclName $sig $val)
|
||||
elabCommand thmStatement
|
||||
|
||||
let msgs := (← get).messages
|
||||
@@ -339,7 +348,15 @@ Only the existing statement will be available in later levels:
|
||||
let scope ← getScope
|
||||
let env ← getEnv
|
||||
|
||||
modifyCurLevel fun level => pure {level with
|
||||
let st ← match statementName with
|
||||
| some name => getStatementString name.getId
|
||||
| none => getStatementString defaultDeclName.getId -- TODO: We dont want the internal lemma name here
|
||||
|
||||
let head := match statementName with
|
||||
| some name => Format.join ["theorem ", name.getId.toString]
|
||||
| none => "example"
|
||||
|
||||
modifyCurLevel fun level => pure { level with
|
||||
module := env.header.mainModule
|
||||
goal := sig,
|
||||
scope := scope,
|
||||
@@ -347,13 +364,8 @@ Only the existing statement will be available in later levels:
|
||||
statementName := match statementName with
|
||||
| none => default
|
||||
| some name => name.getId
|
||||
descrFormat := match statementName with
|
||||
| none => "example " ++ (toString <| reprint sig.raw) ++ " := by"
|
||||
| some name => (Format.join ["theorem ", reprint name.raw, " ", reprint sig.raw, " := by"]).pretty 10 -- "lemma " ++ (toString <| reprint name.raw) ++ " " ++ (Format.pretty (reprint sig.raw) 40) ++ " := by"
|
||||
hints := hints
|
||||
} -- Format.pretty <| format thmStatement.raw }
|
||||
|
||||
|
||||
descrFormat := (Format.join [head, " ", st, " := by"]).pretty 10
|
||||
hints := hints }
|
||||
|
||||
/-! # Hints -/
|
||||
|
||||
@@ -500,6 +512,21 @@ elab "MakeGame" : command => do
|
||||
if game.worlds.hasLoops then
|
||||
throwError "World graph must not contain loops! Check your `Path` declarations."
|
||||
|
||||
-- Now create The doc entries from the templates
|
||||
for item in inventoryKeyExt.getState (← getEnv) do
|
||||
-- TODO: Add information about inventory items
|
||||
let name := item.name
|
||||
match item.type with
|
||||
| .Lemma =>
|
||||
modifyEnv (inventoryExt.addEntry · { item with
|
||||
-- Add the lemma statement to the doc.
|
||||
statement := (← getStatementString name)
|
||||
})
|
||||
| _ =>
|
||||
modifyEnv (inventoryExt.addEntry · {
|
||||
item with
|
||||
})
|
||||
|
||||
-- Compute which inventory items are available in which level:
|
||||
for inventoryType in #[.Tactic, .Definition, .Lemma] do
|
||||
let mut newItemsInWorld : HashMap Name (HashSet Name) := {}
|
||||
@@ -543,7 +570,8 @@ elab "MakeGame" : command => do
|
||||
let Availability₀ : HashMap Name ComputedInventoryItem :=
|
||||
HashMap.ofList $
|
||||
← allItems.toList.mapM fun item => do
|
||||
let data := (← getInventoryDoc? item inventoryType).get!
|
||||
let data := (← getInventoryItem? item inventoryType).get!
|
||||
-- TODO: BUG, panic at `get!` in vscode
|
||||
return (item, {
|
||||
name := item
|
||||
displayName := data.displayName
|
||||
@@ -557,7 +585,7 @@ elab "MakeGame" : command => do
|
||||
let predecessors := game.worlds.predecessors worldId
|
||||
for predWorldId in predecessors do
|
||||
for item in newItemsInWorld.find! predWorldId do
|
||||
let data := (← getInventoryDoc? item inventoryType).get!
|
||||
let data := (← getInventoryItem? item inventoryType).get!
|
||||
items := items.insert item {
|
||||
name := item
|
||||
displayName := data.displayName
|
||||
@@ -575,7 +603,7 @@ elab "MakeGame" : command => do
|
||||
|
||||
-- unlock items that are unlocked in this level
|
||||
for item in levelInfo.new do
|
||||
let data := (← getInventoryDoc? item inventoryType).get!
|
||||
let data := (← getInventoryItem? item inventoryType).get!
|
||||
items := items.insert item {
|
||||
name := item
|
||||
displayName := data.displayName
|
||||
@@ -588,7 +616,7 @@ elab "MakeGame" : command => do
|
||||
match lemmaStatements.find? (worldId, levelId) with
|
||||
| none => pure ()
|
||||
| some name =>
|
||||
let data := (← getInventoryDoc? name inventoryType).get!
|
||||
let data := (← getInventoryItem? name inventoryType).get!
|
||||
items := items.insert name {
|
||||
name := name
|
||||
displayName := data.displayName
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import GameServer.AbstractCtx
|
||||
import GameServer.Graph
|
||||
|
||||
|
||||
|
||||
/-- The default game name if `Game "MyGame"` is not used. -/
|
||||
def defaultGameName: String := "MyGame"
|
||||
-- Note: When changing any of these default names, one also needs to change them in `index.mjs`
|
||||
|
||||
/-- The default game module name. -/
|
||||
def defaultGameModule: String := "Game"
|
||||
|
||||
/-! # Environment extensions
|
||||
|
||||
The game framework stores almost all its game building data in environment extensions
|
||||
@@ -9,14 +18,6 @@ defined in this file.
|
||||
|
||||
open Lean
|
||||
|
||||
-- Note: When changing these, one also needs to change them in `index.mjs`
|
||||
|
||||
/-- The default game name if `Game "MyGame"` is not used. -/
|
||||
def defaultGameName: String := "MyGame"
|
||||
|
||||
/-- The default game module name. -/
|
||||
def defaultGameModule: String := "Game"
|
||||
|
||||
/-! ## Hints -/
|
||||
|
||||
/-- A hint to help the user with a specific goal state -/
|
||||
@@ -33,17 +34,88 @@ instance : Repr GoalHintEntry := {
|
||||
reprPrec := fun a n => reprPrec a.text n
|
||||
}
|
||||
|
||||
/-! ## Tactic/Definition/Lemma documentation -/
|
||||
/-! ## Tactic/Definition/Lemma documentation
|
||||
|
||||
There are three inventory types: Lemma, Tactic, Definition. They vary about in the information
|
||||
they carry.
|
||||
|
||||
The commands `LemmaDoc`, `TacticDoc`, and `DefinitionDoc` add keys and templates to an
|
||||
env. extension called `InventoryKeyExt`. Commands like `NewLemma`, etc. as well as
|
||||
`Statement` check if there is a key registered in this extension and might add a default or
|
||||
print a warning if not.
|
||||
|
||||
Then, `MakeGame` takes the templates from `InventoryKeyExt` and creates the documentation entries
|
||||
that are sent to the client. This allows us to modify them like adding information from
|
||||
mathlib or from parsing the lemma in question.
|
||||
-/
|
||||
|
||||
/-- The game knows three different inventory types that contain slightly different information -/
|
||||
inductive InventoryType := | Tactic | Lemma | Definition
|
||||
deriving ToJson, FromJson, Repr, BEq, Hashable, Inhabited
|
||||
|
||||
-- TODO: golf this?
|
||||
instance : ToString InventoryType := ⟨fun t => match t with
|
||||
| .Tactic => "Tactic"
|
||||
| .Lemma => "Lemma"
|
||||
| .Definition => "Definition"
|
||||
⟩
|
||||
| .Definition => "Definition"⟩
|
||||
|
||||
/-- The keys/templates of the inventory items, stored in `InventoryKeyExt`. -/
|
||||
structure InventoryKey where
|
||||
/-- Lemma, Tactic, or Definition -/
|
||||
type: InventoryType
|
||||
/-- Depends on the type:
|
||||
* Tactic: the tactic's name
|
||||
* Lemma: fully qualified lemma name
|
||||
* Definition: no restrictions (preferrably the definions fully qualified name)
|
||||
-/
|
||||
name: Name
|
||||
/-- Only for Lemmas. To sort them into tabs -/
|
||||
category: String := default
|
||||
/-- Free-text short name -/
|
||||
displayName: String := name.toString
|
||||
/-- Template documentation. Allows for special tags to insert mathlib info [TODO!] -/
|
||||
content: String := "(missing)"
|
||||
deriving ToJson, Repr, Inhabited
|
||||
|
||||
/-- A inventory item as it gets sent to the client. The command `MakeGame` creates these
|
||||
from the `InventoryKey`s and modifies them. -/
|
||||
structure InventoryItem extends InventoryKey where -- TODO: can I remove the field `template`? Probably not...
|
||||
statement: String := ""
|
||||
deriving ToJson, Repr, Inhabited
|
||||
|
||||
/-- The extension that stores the doc templates. Note that you can only add, but never modify
|
||||
entries! -/
|
||||
initialize inventoryKeyExt : SimplePersistentEnvExtension InventoryKey (Array InventoryKey) ←
|
||||
registerSimplePersistentEnvExtension {
|
||||
name := `inventory_keys
|
||||
addEntryFn := Array.push
|
||||
addImportedFn := Array.concatMap id }
|
||||
|
||||
def getInventoryKey? [Monad m] [MonadEnv m] (n : Name) (type : InventoryType) :
|
||||
m (Option InventoryKey) := do
|
||||
return (inventoryKeyExt.getState (← getEnv)).find? (fun x => x.name == n && x.type == type)
|
||||
|
||||
/-- The extension that contains the inventory content after it has been processed.
|
||||
`MakeGame` is the only command adding items here. -/
|
||||
initialize inventoryExt : SimplePersistentEnvExtension InventoryItem (Array InventoryItem) ←
|
||||
registerSimplePersistentEnvExtension {
|
||||
name := `inventory_doc
|
||||
addEntryFn := Array.push
|
||||
addImportedFn := Array.concatMap id }
|
||||
|
||||
def getInventoryItem? [Monad m] [MonadEnv m] (n : Name) (type : InventoryType) :
|
||||
m (Option InventoryItem) := do
|
||||
return (inventoryExt.getState (← getEnv)).find? (fun x => x.name == n && x.type == type)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/-- An inventory item represents the documentation of a tactic/lemma/definitions. -/
|
||||
structure InventoryDocEntry where
|
||||
@@ -63,14 +135,20 @@ structure InventoryDocEntry where
|
||||
category : String
|
||||
/-- The description (doc) of the item. (free-text) -/
|
||||
content : String
|
||||
/-- For definitions and statements this is the statement -/
|
||||
statement : String := ""
|
||||
/-- The docstring if one exists -/
|
||||
docstring : String := ""
|
||||
deriving ToJson, Repr, Inhabited
|
||||
|
||||
/-- The reduced version of `InventoryDocEntry` which is sent to the client -/
|
||||
structure Doc where
|
||||
name: String
|
||||
displayName: String
|
||||
text: String -- TODO: rename to `content`
|
||||
deriving ToJson
|
||||
-- /-- The reduced version of `InventoryDocEntry` which is sent to the client -/
|
||||
-- structure Doc where
|
||||
-- name: String
|
||||
-- displayName: String
|
||||
-- content: String
|
||||
-- statement : String
|
||||
-- docstring : String
|
||||
-- deriving ToJson
|
||||
|
||||
/-- Another reduced version of `InventoryDocEntry` which is used for the tiles in the doc -/
|
||||
structure ComputedInventoryItem where
|
||||
@@ -94,23 +172,23 @@ structure ComputedInventoryItem where
|
||||
new := false
|
||||
deriving ToJson, FromJson, Repr, Inhabited
|
||||
|
||||
/-- Environment extension for inventory documentation. -/
|
||||
initialize inventoryDocExt : SimplePersistentEnvExtension InventoryDocEntry (Array InventoryDocEntry) ←
|
||||
registerSimplePersistentEnvExtension {
|
||||
name := `inventory_doc
|
||||
addEntryFn := Array.push
|
||||
addImportedFn := Array.concatMap id
|
||||
}
|
||||
-- /-- This extension only keeps track of all doc entries that will need to be gener. -/
|
||||
-- initialize inventoryDocExt : SimplePersistentEnvExtension InventoryDocEntry (Array InventoryDocEntry) ←
|
||||
-- registerSimplePersistentEnvExtension {
|
||||
-- name := `inventory_doc_old
|
||||
-- addEntryFn := Array.push
|
||||
-- addImportedFn := Array.concatMap id
|
||||
-- }
|
||||
|
||||
def getInventoryDoc? {m : Type → Type} [Monad m] [MonadEnv m] (n : Name) (type : InventoryType) :
|
||||
m (Option InventoryDocEntry) := do
|
||||
return (inventoryDocExt.getState (← getEnv)).find? (fun x => x.name == n && x.type == type)
|
||||
-- def getInventoryDoc? {m : Type → Type} [Monad m] [MonadEnv m] (n : Name) (type : InventoryType) :
|
||||
-- m (Option InventoryDocEntry) := do
|
||||
-- return (inventoryDocExt.getState (← getEnv)).find? (fun x => x.name == n && x.type == type)
|
||||
|
||||
open Elab Command in
|
||||
/-- Print a registered tactic doc for debugging purposes. -/
|
||||
elab "#print_doc" : command => do
|
||||
for entry in inventoryDocExt.getState (← getEnv) do
|
||||
dbg_trace "[{entry.type}] {entry.name} : {entry.content}"
|
||||
-- open Elab Command in
|
||||
-- /-- Print a registered tactic doc for debugging purposes. -/
|
||||
-- elab "#print_doc" : command => do
|
||||
-- for entry in inventoryDocExt.getState (← getEnv) do
|
||||
-- dbg_trace "[{entry.type}] {entry.name} : {entry.content}"
|
||||
|
||||
|
||||
/-! ## Environment extensions for game specification-/
|
||||
@@ -134,23 +212,25 @@ variable {m: Type → Type} [Monad m] [MonadEnv m]
|
||||
|
||||
/-- Set the current game -/
|
||||
def setCurGameId (game : Name) : m Unit :=
|
||||
modifyEnv (curGameExt.setState · (some game))
|
||||
modifyEnv (curGameExt.setState · game)
|
||||
|
||||
/-- Set the current world -/
|
||||
def setCurWorldId (world : Name) : m Unit :=
|
||||
modifyEnv (curWorldExt.setState · (some world))
|
||||
modifyEnv (curWorldExt.setState · world)
|
||||
|
||||
/-- Set the current level -/
|
||||
def setCurLevelIdx (level : Nat) : m Unit :=
|
||||
modifyEnv (curLevelExt.setState · (some level))
|
||||
modifyEnv (curLevelExt.setState · level)
|
||||
|
||||
/-- Get the current layer. -/
|
||||
def getCurLayer [MonadError m] : m Layer := do
|
||||
match curGameExt.getState (← getEnv), curWorldExt.getState (← getEnv), curLevelExt.getState (← getEnv) with
|
||||
| _, some _, some _ => return Layer.Level
|
||||
| _, some _, none => return Layer.World
|
||||
| _, none, none => return Layer.Game
|
||||
| _, _, _ => throwError "Invalid Layer"
|
||||
-- previously, we also had `curGameExt.getState (← getEnv), ` in here, which got removed
|
||||
-- when we made the `Game` command optional
|
||||
match curWorldExt.getState (← getEnv), curLevelExt.getState (← getEnv) with
|
||||
| some _, some _ => return Layer.Level
|
||||
| some _, none => return Layer.World
|
||||
| none, none => return Layer.Game
|
||||
| _, _ => throwError "Invalid Layer"
|
||||
|
||||
/-- Get the current game, or default if none is specified -/
|
||||
def getCurGameId [Monad m] : m Name := do
|
||||
|
||||
@@ -130,7 +130,7 @@ partial def handleServerEvent (ev : ServerEvent) : GameServerM Bool := do
|
||||
lemmaTab := lvl.lemmaTab
|
||||
statementName := match lvl.statementName with
|
||||
| .anonymous => none
|
||||
| name => match (inventoryDocExt.getState env).find?
|
||||
| name => match (inventoryExt.getState env).find?
|
||||
(fun x => x.name == name && x.type == .Lemma) with
|
||||
| some n => n.displayName
|
||||
| none => name.toString
|
||||
@@ -143,14 +143,15 @@ partial def handleServerEvent (ev : ServerEvent) : GameServerM Bool := do
|
||||
let p ← parseParams LoadDocParams (toJson params)
|
||||
-- let s ← get
|
||||
let c ← read
|
||||
let some doc ← getInventoryDoc? p.name p.type
|
||||
let some doc ← getInventoryItem? p.name p.type
|
||||
| do
|
||||
c.hOut.writeLspResponseError ⟨id, .invalidParams, s!"Documentation not found: {p.name}", none⟩
|
||||
c.hOut.writeLspResponseError ⟨id, .invalidParams,
|
||||
s!"Documentation not found: {p.name}", none⟩
|
||||
return true
|
||||
let doc : Doc :=
|
||||
{ name := doc.name.toString
|
||||
displayName := doc.displayName
|
||||
text := doc.content }
|
||||
-- TODO: not necessary at all?
|
||||
-- Here we only need to convert the fields that were not `String` in the `InventoryDocEntry`
|
||||
-- let doc : InventoryItem := { doc with
|
||||
-- name := doc.name.toString }
|
||||
c.hOut.writeLspResponse ⟨id, ToJson.toJson doc⟩
|
||||
return true
|
||||
| _ => return false
|
||||
|
||||
Reference in New Issue
Block a user