mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-27 08:39:30 +00:00
Compare commits
2 commits
ed7fe34853
...
77c6ac6ba2
| Author | SHA1 | Date | |
|---|---|---|---|
| 77c6ac6ba2 | |||
| 876135401c |
11 changed files with 425 additions and 70 deletions
|
|
@ -5,8 +5,56 @@ local Event = ast.abstract.Event
|
||||||
|
|
||||||
local operator_priority = require("anselme.common").operator_priority
|
local operator_priority = require("anselme.common").operator_priority
|
||||||
|
|
||||||
|
--- ChoiceEventData represent the data returned by an event with the type `"choice"`.
|
||||||
|
-- See the [language documentation](language.md#choices) for more details on how to create a choice event.
|
||||||
|
--
|
||||||
|
-- A ChoiceEventData contains a list of [LuaText](#luatext), each LuaText representing a separate choice of the choice event.
|
||||||
|
--
|
||||||
|
-- For example, the following Anselme script:
|
||||||
|
--
|
||||||
|
-- ```
|
||||||
|
-- *| Yes!
|
||||||
|
-- *| No.
|
||||||
|
-- ```
|
||||||
|
-- will return a choice event containing two LuaTexts, the first containing the text "Yes!" and the second "No.".
|
||||||
|
--
|
||||||
|
-- Usage:
|
||||||
|
-- ```lua
|
||||||
|
-- current_choice = nil
|
||||||
|
-- waiting_for_choice = false
|
||||||
|
--
|
||||||
|
-- -- in your anselem event handling loop:
|
||||||
|
-- if not waiting_for_choice then
|
||||||
|
-- local event_type, event_data = run_state:step()
|
||||||
|
-- if event_type == "choice" then
|
||||||
|
-- -- event_data is a ChoiceEventData, i.e. a list of LuaText
|
||||||
|
-- for i, luatext in ipairs(event_data) do
|
||||||
|
-- write(("Choice number %s:"):format(i))
|
||||||
|
-- -- luatext is a list of text parts { text = "text string", tags = { ... } }
|
||||||
|
-- for _, textpart in ipairs(luatext) do
|
||||||
|
-- write_choice_part_with_color(textpart.text, textpart.tags.color)
|
||||||
|
-- end
|
||||||
|
-- else
|
||||||
|
-- -- handle other event types...
|
||||||
|
-- end
|
||||||
|
-- current_choice = event_data
|
||||||
|
-- waiting_for_choice = true
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- -- somewhere in your code where choices are selected
|
||||||
|
-- current_choice:select(choice_number)
|
||||||
|
-- waiting_for_choice = false
|
||||||
|
-- ```
|
||||||
|
-- @title ChoiceEventData
|
||||||
local ChoiceEventData = class {
|
local ChoiceEventData = class {
|
||||||
|
-- [1] = LuaText, ...
|
||||||
|
|
||||||
_selected = nil,
|
_selected = nil,
|
||||||
|
|
||||||
|
--- Choose the choice at position `choice` (number).
|
||||||
|
--
|
||||||
|
-- A choice must be selected after receiving a choice event and before calling `:step` again.
|
||||||
choose = function(self, choice)
|
choose = function(self, choice)
|
||||||
self._selected = choice
|
self._selected = choice
|
||||||
end
|
end
|
||||||
|
|
@ -36,7 +84,7 @@ Choice = ast.abstract.Runtime(Event) {
|
||||||
build_event_data = function(self, state, event_buffer)
|
build_event_data = function(self, state, event_buffer)
|
||||||
local l = ChoiceEventData:new()
|
local l = ChoiceEventData:new()
|
||||||
for _, c in event_buffer:iter(state) do
|
for _, c in event_buffer:iter(state) do
|
||||||
table.insert(l, c.text)
|
table.insert(l, c.text:to_lua(state))
|
||||||
end
|
end
|
||||||
return l
|
return l
|
||||||
end,
|
end,
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ Struct = ast.abstract.Runtime {
|
||||||
|
|
||||||
to_lua = function(self, state)
|
to_lua = function(self, state)
|
||||||
local l = {}
|
local l = {}
|
||||||
for _, e in ipairs(self.table) do
|
for _, e in pairs(self.table) do
|
||||||
l[e[1]:to_lua(state)] = e[2]:to_lua(state)
|
l[e[1]:to_lua(state)] = e[2]:to_lua(state)
|
||||||
end
|
end
|
||||||
return l
|
return l
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,101 @@ local ArgumentTuple, Struct
|
||||||
|
|
||||||
local to_anselme = require("anselme.common.to_anselme")
|
local to_anselme = require("anselme.common.to_anselme")
|
||||||
|
|
||||||
|
--- A Lua-friendly representation of an Anselme Text value.
|
||||||
|
-- They appear in both TextEventData and ChoiceEventData to represent the text that has to be shown.
|
||||||
|
--
|
||||||
|
-- It contains a list of _text parts_, which are parts of a single text, each part potentially having differrent tags attached.
|
||||||
|
-- A text will typically only consist of a single part unless it was built using text interpolation.
|
||||||
|
--
|
||||||
|
-- Each text part is a table containing `text` (string) and `tags` (table) properties, for example: `{ text = "text part string", tags = { color = "red" } }`.
|
||||||
|
-- @title LuaText
|
||||||
|
-- @defer lua text
|
||||||
|
local LuaText
|
||||||
|
LuaText = class {
|
||||||
|
-- [1] = { text = "string", tags = { tag_name = value, ... } }, ...
|
||||||
|
|
||||||
|
_state = nil,
|
||||||
|
|
||||||
|
--- Anselme Text value this was created from. For advanced usage only. See the source file [Text.lua](anselme/ast/Text.lua) for more information.
|
||||||
|
-- @defer lua text
|
||||||
|
raw = nil,
|
||||||
|
|
||||||
|
init = function(self, text, state)
|
||||||
|
self._state = state
|
||||||
|
self.raw = text
|
||||||
|
for _, e in ipairs(text.list) do
|
||||||
|
table.insert(self, { text = e[1]:to_lua(state), tags = e[2]:to_lua(state) })
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
--- Returns a text representation of the LuaText, using Anselme's default formatting. Useful for debugging.
|
||||||
|
--
|
||||||
|
-- Usage: `print(luatext)`
|
||||||
|
-- @defer lua text
|
||||||
|
__tostring = function(self)
|
||||||
|
return self.raw:format(self._state)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
--- TextEventData represent the data returned by an event with the type `"text"`.
|
||||||
|
-- See the [language documentation](language.md#texts) for more details on how to create a text event.
|
||||||
|
--
|
||||||
|
-- A TextEventData contains a list of [LuaText](#luatext), each LuaText representing a separate line of the text event.
|
||||||
|
--
|
||||||
|
-- For example, the following Anselme script:
|
||||||
|
--
|
||||||
|
-- ```
|
||||||
|
-- | Hi!
|
||||||
|
-- | My name's John.
|
||||||
|
-- ```
|
||||||
|
-- will return a text event containing two LuaTexts, the first containing the text "Hi!" and the second "My name's John.".
|
||||||
|
--
|
||||||
|
-- Usage:
|
||||||
|
-- ```lua
|
||||||
|
-- local event_type, event_data = run_state:step()
|
||||||
|
-- if event_type == "text" then
|
||||||
|
-- -- event_data is a TextEventData, i.e. a list of LuaText
|
||||||
|
-- for _, luatext in ipairs(event_data) do
|
||||||
|
-- -- luatext is a list of text parts { text = "text string", tags = { ... } }
|
||||||
|
-- for _, textpart in ipairs(luatext) do
|
||||||
|
-- write_text_part_with_color(textpart.text, textpart.tags.color)
|
||||||
|
-- end
|
||||||
|
-- write_text("\n") -- for example, if we want a newline between each text line
|
||||||
|
-- end
|
||||||
|
-- else
|
||||||
|
-- -- handle other event types...
|
||||||
|
-- end
|
||||||
|
-- ```
|
||||||
|
-- @title TextEventData
|
||||||
local TextEventData
|
local TextEventData
|
||||||
TextEventData = class {
|
TextEventData = class {
|
||||||
-- returns a list of TextEventData where the first element of each text of each TextEventData has the same value for the tag tag_name
|
-- [1] = LuaText, ...
|
||||||
|
|
||||||
|
--- Returns a list of TextEventData where the first part of each LuaText of each TextEventData has the same value for the tag `tag_name`.
|
||||||
|
--
|
||||||
|
-- In other words, this groups all the LuaTexts contained in this TextEventData using the `tag_name` tag and returns a list containing these groups.
|
||||||
|
--
|
||||||
|
-- For example, with the following Anselme script:
|
||||||
|
-- ```
|
||||||
|
-- speaker: "John" #
|
||||||
|
-- | A
|
||||||
|
-- | B
|
||||||
|
-- speaker: "Lana" #
|
||||||
|
-- | C
|
||||||
|
-- speaker: "John" #
|
||||||
|
-- | D
|
||||||
|
-- ```
|
||||||
|
-- calling `text_event_data:group_by("speaker")` will return a list of three TextEventData:
|
||||||
|
-- * the first with the texts "A" and "B"; both with the tag `speaker="John"`
|
||||||
|
-- * the second with the text "C"; with the tag `speaker="Lana"`
|
||||||
|
-- * the last with the text "D"; wiith the tag `speaker="John"`
|
||||||
group_by = function(self, tag_name)
|
group_by = function(self, tag_name)
|
||||||
local l = {}
|
local l = {}
|
||||||
local current_group
|
local current_group
|
||||||
local tag_key = to_anselme(tag_name)
|
local tag_key = to_anselme(tag_name)
|
||||||
local last_value
|
local last_value
|
||||||
for _, event in ipairs(self) do
|
for _, luatext in ipairs(self) do
|
||||||
local list = event.list
|
local list = luatext.raw.list
|
||||||
if #list > 0 then
|
if #list > 0 then
|
||||||
local value = list[1][2]:get_strict(tag_key)
|
local value = list[1][2]:get_strict(tag_key)
|
||||||
if (not current_group) or (last_value == nil and value) or (last_value and value == nil) or (last_value and value and last_value:hash() ~= value:hash()) then -- new group
|
if (not current_group) or (last_value == nil and value) or (last_value and value == nil) or (last_value and value and last_value:hash() ~= value:hash()) then -- new group
|
||||||
|
|
@ -22,11 +107,11 @@ TextEventData = class {
|
||||||
table.insert(l, current_group)
|
table.insert(l, current_group)
|
||||||
last_value = value
|
last_value = value
|
||||||
end
|
end
|
||||||
table.insert(current_group, event) -- add to current group
|
table.insert(current_group, luatext) -- add to current group
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return l
|
return l
|
||||||
end,
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
local Text
|
local Text
|
||||||
|
|
@ -68,6 +153,10 @@ Text = Runtime(Event) {
|
||||||
return ("| %s |"):format(table.concat(t, " "))
|
return ("| %s |"):format(table.concat(t, " "))
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
to_lua = function(self, state)
|
||||||
|
return LuaText:new(self, state)
|
||||||
|
end,
|
||||||
|
|
||||||
-- autocall when used directly as a statement
|
-- autocall when used directly as a statement
|
||||||
eval_statement = function(self, state)
|
eval_statement = function(self, state)
|
||||||
return self:call(state, ArgumentTuple:new())
|
return self:call(state, ArgumentTuple:new())
|
||||||
|
|
@ -77,8 +166,8 @@ Text = Runtime(Event) {
|
||||||
|
|
||||||
build_event_data = function(self, state, event_buffer)
|
build_event_data = function(self, state, event_buffer)
|
||||||
local l = TextEventData:new()
|
local l = TextEventData:new()
|
||||||
for _, event in event_buffer:iter(state) do
|
for _, text in event_buffer:iter(state) do
|
||||||
table.insert(l, event)
|
table.insert(l, text:to_lua(state))
|
||||||
end
|
end
|
||||||
return l
|
return l
|
||||||
end,
|
end,
|
||||||
|
|
|
||||||
|
|
@ -13,25 +13,20 @@
|
||||||
-- local state = anselme.new()
|
-- local state = anselme.new()
|
||||||
-- state:load_stdlib()
|
-- state:load_stdlib()
|
||||||
--
|
--
|
||||||
-- -- read an anselme script file
|
-- -- load an anselme script file in a new branch
|
||||||
-- local f = assert(io.open("script.ans"))
|
|
||||||
-- local script = anselme.parse(f:read("a"), "script.ans")
|
|
||||||
-- f:close()
|
|
||||||
--
|
|
||||||
-- -- load the script in a new branch
|
|
||||||
-- local run_state = state:branch()
|
-- local run_state = state:branch()
|
||||||
-- run_state:run(script)
|
-- run_state:run_file("script.ans")
|
||||||
--
|
--
|
||||||
-- -- run the script
|
-- -- run the script
|
||||||
-- while run_state:active() do
|
-- while run_state:active() do
|
||||||
-- local e, data = run_state:step()
|
-- local e, data = run_state:step()
|
||||||
-- if e == "text" then
|
-- if e == "text" then
|
||||||
-- for _, l in ipairs(data) do
|
-- for _, l in ipairs(data) do
|
||||||
-- print(l:format(run_state))
|
-- print(l)
|
||||||
-- end
|
-- end
|
||||||
-- elseif e == "choice" then
|
-- elseif e == "choice" then
|
||||||
-- for i, l in ipairs(data) do
|
-- for i, l in ipairs(data) do
|
||||||
-- print(("%s> %s"):format(i, l:format(run_state)))
|
-- print(("%s> %s"):format(i, l))
|
||||||
-- end
|
-- end
|
||||||
-- local choice = tonumber(io.read("l"))
|
-- local choice = tonumber(io.read("l"))
|
||||||
-- data:choose(choice)
|
-- data:choose(choice)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
local expression_to_ast = require("anselme.parser.expression.to_ast")
|
local expression_to_ast = require("anselme.parser.expression.to_ast")
|
||||||
|
|
||||||
|
local utf8 = utf8 or require("lua-utf8")
|
||||||
local ast = require("anselme.ast")
|
local ast = require("anselme.ast")
|
||||||
local PartialScope, Block, Call, Identifier = ast.PartialScope, ast.Block, ast.Call, ast.Identifier
|
local PartialScope, Block, Call, Identifier = ast.PartialScope, ast.Block, ast.Call, ast.Identifier
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ local tag_manager = require("anselme.state.tag_manager")
|
||||||
local event_manager = require("anselme.state.event_manager")
|
local event_manager = require("anselme.state.event_manager")
|
||||||
local translation_manager = require("anselme.state.translation_manager")
|
local translation_manager = require("anselme.state.translation_manager")
|
||||||
local persistent_manager = require("anselme.state.persistent_manager")
|
local persistent_manager = require("anselme.state.persistent_manager")
|
||||||
local uuid = require("anselme.common").uuid
|
|
||||||
local parser = require("anselme.parser")
|
local parser = require("anselme.parser")
|
||||||
local binser = require("anselme.lib.binser")
|
local binser = require("anselme.lib.binser")
|
||||||
local assert0 = require("anselme.common").assert0
|
local common = require("anselme.common")
|
||||||
local operator_priority = require("anselme.common").operator_priority
|
local uuid, assert0, operator_priority = common.uuid, common.assert0, common.operator_priority
|
||||||
|
local to_anselme = require("anselme.common.to_anselme")
|
||||||
local anselme
|
local anselme
|
||||||
local Identifier, Return, Node
|
local Identifier, Return, Node
|
||||||
|
|
||||||
|
|
@ -178,12 +178,13 @@ State = class {
|
||||||
--- Load a script in this branch. It will become the active script.
|
--- Load a script in this branch. It will become the active script.
|
||||||
--
|
--
|
||||||
-- `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
|
-- `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
|
||||||
|
-- `tags` is an optional Lua table; its content will be added to the tags for the duration of the script.
|
||||||
--
|
--
|
||||||
-- Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State.
|
-- Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State.
|
||||||
run = function(self, code, source)
|
run = function(self, code, source, tags)
|
||||||
assert(not self:active(), "a script is already active")
|
assert(not self:active(), "a script is already active")
|
||||||
self._coroutine = coroutine.create(function()
|
self._coroutine = coroutine.create(function()
|
||||||
local r = assert0(self:eval_local(code, source))
|
local r = assert0(self:eval_local(code, source, tags))
|
||||||
event_manager:complete_flush(self)
|
event_manager:complete_flush(self)
|
||||||
if Return:is(r) then r = r.expression end
|
if Return:is(r) then r = r.expression end
|
||||||
return "return", r
|
return "return", r
|
||||||
|
|
@ -191,17 +192,19 @@ State = class {
|
||||||
end,
|
end,
|
||||||
--- Same as `:run`, but read the code from a file.
|
--- Same as `:run`, but read the code from a file.
|
||||||
-- `source` will be set as the file path.
|
-- `source` will be set as the file path.
|
||||||
run_file = function(self, path)
|
run_file = function(self, path, tags)
|
||||||
local f = assert(io.open(path, "r"))
|
local f = assert(io.open(path, "r"))
|
||||||
local block = parser(f:read("a"), path)
|
local block = parser(f:read("a"), path)
|
||||||
f:close()
|
f:close()
|
||||||
return self:run(block)
|
return self:run(block, nil, tags)
|
||||||
end,
|
end,
|
||||||
--- When a script is active, will resume running it until the next event.
|
--- When a script is active, will resume running it until the next event.
|
||||||
--
|
--
|
||||||
-- Will error if no script is active.
|
-- Will error if no script is active.
|
||||||
--
|
--
|
||||||
-- Returns `event type string, event data`.
|
-- Returns `event type string, event data`.
|
||||||
|
--
|
||||||
|
-- See the [events](#events) section for details on event data types for built-in events.
|
||||||
step = function(self)
|
step = function(self)
|
||||||
assert(self:active(), "trying to step but no script is currently active")
|
assert(self:active(), "trying to step but no script is currently active")
|
||||||
local success, type, data = coroutine.resume(self._coroutine)
|
local success, type, data = coroutine.resume(self._coroutine)
|
||||||
|
|
@ -218,16 +221,17 @@ State = class {
|
||||||
--
|
--
|
||||||
-- Will error if no script is active.
|
-- Will error if no script is active.
|
||||||
--
|
--
|
||||||
-- If `code` is given, the script will not be disabled but instead will be immediately replaced with this new script.
|
-- `code`, `source` and `tags` are all optional and have the same behaviour as in `:run`.
|
||||||
|
-- If they are given, the script will not be disabled but instead will be immediately replaced with this new script.
|
||||||
-- The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script.
|
-- The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script.
|
||||||
--
|
--
|
||||||
-- If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution.
|
-- If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution.
|
||||||
interrupt = function(self, code, source)
|
interrupt = function(self, code, source, tags)
|
||||||
assert(self:active(), "trying to interrupt but no script is currently active")
|
assert(self:active(), "trying to interrupt but no script is currently active")
|
||||||
local called_from_script = self:state() == "running"
|
local called_from_script = self:state() == "running"
|
||||||
if code then
|
if code then
|
||||||
self._coroutine = coroutine.create(function()
|
self._coroutine = coroutine.create(function()
|
||||||
local r = assert0(self:eval_local(code, source))
|
local r = assert0(self:eval_local(code, source, tags))
|
||||||
event_manager:complete_flush(self)
|
event_manager:complete_flush(self)
|
||||||
self.scope:reset() -- scope stack is probably messed up after the switch
|
self.scope:reset() -- scope stack is probably messed up after the switch
|
||||||
if Return:is(r) then r = r.expression end
|
if Return:is(r) then r = r.expression end
|
||||||
|
|
@ -244,19 +248,24 @@ State = class {
|
||||||
--
|
--
|
||||||
-- This can be called from outside a running script, but an error will be triggered the expression raise any event other than return.
|
-- This can be called from outside a running script, but an error will be triggered the expression raise any event other than return.
|
||||||
--
|
--
|
||||||
|
-- `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
|
||||||
|
-- `tags` is an optional Lua table; its content will be added to the tags for the duration of the expression.
|
||||||
|
--
|
||||||
-- * returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value.
|
-- * returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value.
|
||||||
-- * returns `nil, error message` in case of error.
|
-- * returns `nil, error message` in case of error.
|
||||||
eval = function(self, code, source)
|
eval = function(self, code, source, tags)
|
||||||
self.scope:push_global()
|
self.scope:push_global()
|
||||||
local r, e = self:eval_local(code, source)
|
local r, e = self:eval_local(code, source, tags)
|
||||||
self.scope:pop()
|
self.scope:pop()
|
||||||
return r, e
|
return r, e
|
||||||
end,
|
end,
|
||||||
--- Same as `:eval`, but evaluate the expression in the current scope.
|
--- Same as `:eval`, but evaluate the expression in the current scope.
|
||||||
eval_local = function(self, code, source)
|
eval_local = function(self, code, source, tags)
|
||||||
if type(code) == "string" then code = parser(code, source) end
|
if type(code) == "string" then code = parser(code, source) end
|
||||||
local stack_size = self.scope:size()
|
local stack_size = self.scope:size()
|
||||||
|
if tags then tag_manager:push(self, to_anselme(tags)) end
|
||||||
local s, e = pcall(code.eval, code, self)
|
local s, e = pcall(code.eval, code, self)
|
||||||
|
if tags then tag_manager:pop(self) end
|
||||||
if not s then
|
if not s then
|
||||||
self.scope:reset(stack_size)
|
self.scope:reset(stack_size)
|
||||||
return nil, e
|
return nil, e
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ return [[
|
||||||
:@arrondi = stdlib.round
|
:@arrondi = stdlib.round
|
||||||
:@aléatoire = stdlib.rand
|
:@aléatoire = stdlib.rand
|
||||||
|
|
||||||
:@égal = stdlib.equal
|
:@est égal = stdlib.is equal
|
||||||
:@est = stdlib.is
|
:@est = stdlib.is
|
||||||
:@est une ancre = stdlib.is anchor
|
:@est une ancre = stdlib.is anchor
|
||||||
:@est un booléen = stdlib.is boolean
|
:@est un booléen = stdlib.is boolean
|
||||||
|
|
|
||||||
238
doc/api.md
238
doc/api.md
|
|
@ -1,6 +1,6 @@
|
||||||
This document describes how to use the main Anselme modules. This is generated automatically from the source files.
|
This document describes how to use the main Anselme modules. This is generated automatically from the source files.
|
||||||
|
|
||||||
Note that this file only describes the `anselme` and `state.State` modules, which are only a selection of what I consider to be the "public API" of Anselme that I will try to keep stable.
|
Note that this file only describes the `anselme` and `state.State` modules, as well as the `TextEventData` and `ChoiceEventData` classes, which are only a selection of what I consider to be the "public API" of Anselme that I will try to keep stable.
|
||||||
If you need more advanced control on Anselme, feel free to look into the other source files to find more; the most useful functions should all be reasonably commented.
|
If you need more advanced control on Anselme, feel free to look into the other source files to find more; the most useful functions should all be reasonably commented.
|
||||||
|
|
||||||
# anselme
|
# anselme
|
||||||
|
|
@ -15,25 +15,20 @@ local anselme = require("anselme")
|
||||||
local state = anselme.new()
|
local state = anselme.new()
|
||||||
state:load_stdlib()
|
state:load_stdlib()
|
||||||
|
|
||||||
-- read an anselme script file
|
-- load an anselme script file in a new branch
|
||||||
local f = assert(io.open("script.ans"))
|
|
||||||
local script = anselme.parse(f:read("a"), "script.ans")
|
|
||||||
f:close()
|
|
||||||
|
|
||||||
-- load the script in a new branch
|
|
||||||
local run_state = state:branch()
|
local run_state = state:branch()
|
||||||
run_state:run(script)
|
run_state:run_file("script.ans")
|
||||||
|
|
||||||
-- run the script
|
-- run the script
|
||||||
while run_state:active() do
|
while run_state:active() do
|
||||||
local e, data = run_state:step()
|
local e, data = run_state:step()
|
||||||
if e == "text" then
|
if e == "text" then
|
||||||
for _, l in ipairs(data) do
|
for _, l in ipairs(data) do
|
||||||
print(l:format(run_state))
|
print(l)
|
||||||
end
|
end
|
||||||
elseif e == "choice" then
|
elseif e == "choice" then
|
||||||
for i, l in ipairs(data) do
|
for i, l in ipairs(data) do
|
||||||
print(("%s> %s"):format(i, l:format(run_state)))
|
print(("%s> %s"):format(i, l))
|
||||||
end
|
end
|
||||||
local choice = tonumber(io.read("l"))
|
local choice = tonumber(io.read("l"))
|
||||||
data:choose(choice)
|
data:choose(choice)
|
||||||
|
|
@ -56,31 +51,31 @@ Anselme expects that `require("anselme.module")` will try loading both `anselme/
|
||||||
|
|
||||||
Global version string. Follow semver.
|
Global version string. Follow semver.
|
||||||
|
|
||||||
_defined at line 58 of [anselme/init.lua](../anselme/init.lua):_ `version = "2.0.0-rc1",`
|
_defined at line 53 of [anselme/init.lua](../anselme/init.lua):_ `version = "2.0.0-rc1",`
|
||||||
|
|
||||||
### .versions
|
### .versions
|
||||||
|
|
||||||
Table containing per-category version numbers. Incremented by one for any change that may break compatibility.
|
Table containing per-category version numbers. Incremented by one for any change that may break compatibility.
|
||||||
|
|
||||||
_defined at line 61 of [anselme/init.lua](../anselme/init.lua):_ `versions = {`
|
_defined at line 56 of [anselme/init.lua](../anselme/init.lua):_ `versions = {`
|
||||||
|
|
||||||
#### .language
|
#### .language
|
||||||
|
|
||||||
Version number for language and standard library changes.
|
Version number for language and standard library changes.
|
||||||
|
|
||||||
_defined at line 63 of [anselme/init.lua](../anselme/init.lua):_ `language = 31,`
|
_defined at line 58 of [anselme/init.lua](../anselme/init.lua):_ `language = 31,`
|
||||||
|
|
||||||
#### .save
|
#### .save
|
||||||
|
|
||||||
Version number for save/AST format changes.
|
Version number for save/AST format changes.
|
||||||
|
|
||||||
_defined at line 65 of [anselme/init.lua](../anselme/init.lua):_ `save = 7,`
|
_defined at line 60 of [anselme/init.lua](../anselme/init.lua):_ `save = 7,`
|
||||||
|
|
||||||
#### .api
|
#### .api
|
||||||
|
|
||||||
Version number for Lua API changes.
|
Version number for Lua API changes.
|
||||||
|
|
||||||
_defined at line 67 of [anselme/init.lua](../anselme/init.lua):_ `api = 10`
|
_defined at line 62 of [anselme/init.lua](../anselme/init.lua):_ `api = 10`
|
||||||
|
|
||||||
### .parse (code, source)
|
### .parse (code, source)
|
||||||
|
|
||||||
|
|
@ -94,14 +89,14 @@ local ast = anselme.parse("1 + 2", "test")
|
||||||
ast:eval(state)
|
ast:eval(state)
|
||||||
```
|
```
|
||||||
|
|
||||||
_defined at line 79 of [anselme/init.lua](../anselme/init.lua):_ `parse = function(code, source)`
|
_defined at line 74 of [anselme/init.lua](../anselme/init.lua):_ `parse = function(code, source)`
|
||||||
|
|
||||||
### .parse_file (path)
|
### .parse_file (path)
|
||||||
|
|
||||||
Same as `:parse`, but reads the code from a file.
|
Same as `:parse`, but reads the code from a file.
|
||||||
`source` will be set as the file path.
|
`source` will be set as the file path.
|
||||||
|
|
||||||
_defined at line 84 of [anselme/init.lua](../anselme/init.lua):_ `parse_file = function(path)`
|
_defined at line 79 of [anselme/init.lua](../anselme/init.lua):_ `parse_file = function(path)`
|
||||||
|
|
||||||
### .generate_translation_template (code, source)
|
### .generate_translation_template (code, source)
|
||||||
|
|
||||||
|
|
@ -109,20 +104,20 @@ Generates and return Anselme code (as a string) that can be used as a base for a
|
||||||
This will include every translatable element found in this code.
|
This will include every translatable element found in this code.
|
||||||
`source` is an optional string; it will be used as the code source name in translation contexts.
|
`source` is an optional string; it will be used as the code source name in translation contexts.
|
||||||
|
|
||||||
_defined at line 93 of [anselme/init.lua](../anselme/init.lua):_ `generate_translation_template = function(code, source)`
|
_defined at line 88 of [anselme/init.lua](../anselme/init.lua):_ `generate_translation_template = function(code, source)`
|
||||||
|
|
||||||
### .generate_translation_template_file (path)
|
### .generate_translation_template_file (path)
|
||||||
|
|
||||||
Same as `:generate_translation_template`, but reads the code from a file.
|
Same as `:generate_translation_template`, but reads the code from a file.
|
||||||
`source` will be set as the file path.
|
`source` will be set as the file path.
|
||||||
|
|
||||||
_defined at line 98 of [anselme/init.lua](../anselme/init.lua):_ `generate_translation_template_file = function(path)`
|
_defined at line 93 of [anselme/init.lua](../anselme/init.lua):_ `generate_translation_template_file = function(path)`
|
||||||
|
|
||||||
### .new ()
|
### .new ()
|
||||||
|
|
||||||
Return a new [State](#state).
|
Return a new [State](#state).
|
||||||
|
|
||||||
_defined at line 102 of [anselme/init.lua](../anselme/init.lua):_ `new = function()`
|
_defined at line 97 of [anselme/init.lua](../anselme/init.lua):_ `new = function()`
|
||||||
|
|
||||||
|
|
||||||
# State
|
# State
|
||||||
|
|
@ -249,22 +244,23 @@ Returns `"inactive"` if no script is loaded.
|
||||||
|
|
||||||
_defined at line 171 of [anselme/state/State.lua](../anselme/state/State.lua):_ `state = function(self)`
|
_defined at line 171 of [anselme/state/State.lua](../anselme/state/State.lua):_ `state = function(self)`
|
||||||
|
|
||||||
### :run (code, source)
|
### :run (code, source, tags)
|
||||||
|
|
||||||
Load a script in this branch. It will become the active script.
|
Load a script in this branch. It will become the active script.
|
||||||
|
|
||||||
`code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
|
`code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
|
||||||
|
`tags` is an optional Lua table; its content will be added to the tags for the duration of the script.
|
||||||
|
|
||||||
Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State.
|
Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State.
|
||||||
|
|
||||||
_defined at line 183 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run = function(self, code, source)`
|
_defined at line 184 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run = function(self, code, source, tags)`
|
||||||
|
|
||||||
### :run_file (path)
|
### :run_file (path, tags)
|
||||||
|
|
||||||
Same as `:run`, but read the code from a file.
|
Same as `:run`, but read the code from a file.
|
||||||
`source` will be set as the file path.
|
`source` will be set as the file path.
|
||||||
|
|
||||||
_defined at line 194 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run_file = function(self, path)`
|
_defined at line 195 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run_file = function(self, path, tags)`
|
||||||
|
|
||||||
### :step ()
|
### :step ()
|
||||||
|
|
||||||
|
|
@ -274,42 +270,218 @@ Will error if no script is active.
|
||||||
|
|
||||||
Returns `event type string, event data`.
|
Returns `event type string, event data`.
|
||||||
|
|
||||||
_defined at line 205 of [anselme/state/State.lua](../anselme/state/State.lua):_ `step = function(self)`
|
See the [events](#events) section for details on event data types for built-in events.
|
||||||
|
|
||||||
### :interrupt (code, source)
|
_defined at line 208 of [anselme/state/State.lua](../anselme/state/State.lua):_ `step = function(self)`
|
||||||
|
|
||||||
|
### :interrupt (code, source, tags)
|
||||||
|
|
||||||
Stops the currently active script.
|
Stops the currently active script.
|
||||||
|
|
||||||
Will error if no script is active.
|
Will error if no script is active.
|
||||||
|
|
||||||
If `code` is given, the script will not be disabled but instead will be immediately replaced with this new script.
|
`code`, `source` and `tags` are all optional and have the same behaviour as in `:run`.
|
||||||
|
If they are given, the script will not be disabled but instead will be immediately replaced with this new script.
|
||||||
The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script.
|
The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script.
|
||||||
|
|
||||||
If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution.
|
If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution.
|
||||||
|
|
||||||
_defined at line 225 of [anselme/state/State.lua](../anselme/state/State.lua):_ `interrupt = function(self, code, source)`
|
_defined at line 229 of [anselme/state/State.lua](../anselme/state/State.lua):_ `interrupt = function(self, code, source, tags)`
|
||||||
|
|
||||||
### :eval (code, source)
|
### :eval (code, source, tags)
|
||||||
|
|
||||||
Evaluate an expression in the global scope.
|
Evaluate an expression in the global scope.
|
||||||
|
|
||||||
This can be called from outside a running script, but an error will be triggered the expression raise any event other than return.
|
This can be called from outside a running script, but an error will be triggered the expression raise any event other than return.
|
||||||
|
|
||||||
|
`code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
|
||||||
|
`tags` is an optional Lua table; its content will be added to the tags for the duration of the expression.
|
||||||
|
|
||||||
* returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value.
|
* returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value.
|
||||||
* returns `nil, error message` in case of error.
|
* returns `nil, error message` in case of error.
|
||||||
|
|
||||||
_defined at line 249 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval = function(self, code, source)`
|
_defined at line 256 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval = function(self, code, source, tags)`
|
||||||
|
|
||||||
### :eval_local (code, source)
|
### :eval_local (code, source, tags)
|
||||||
|
|
||||||
Same as `:eval`, but evaluate the expression in the current scope.
|
Same as `:eval`, but evaluate the expression in the current scope.
|
||||||
|
|
||||||
_defined at line 256 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval_local = function(self, code, source)`
|
_defined at line 263 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval_local = function(self, code, source, tags)`
|
||||||
|
|
||||||
If you want to perform more advanced manipulation of the resulting AST nodes, look at the `ast` modules.
|
If you want to perform more advanced manipulation of the resulting AST nodes, look at the `ast` modules.
|
||||||
In particular, every Node inherits the methods from [ast.abstract.Node](../ast/abstract/Node.lua).
|
In particular, every Node inherits the methods from [ast.abstract.Node](../ast/abstract/Node.lua).
|
||||||
Otherwise, each Node has its own module file defined in the [ast/](../ast) directory.
|
Otherwise, each Node has its own module file defined in the [ast/](../ast) directory.
|
||||||
|
|
||||||
|
|
||||||
|
# Events
|
||||||
|
|
||||||
|
Anselme scripts communicate with the game by sending events. See the [language documentation](language.md#events) for more details on events.
|
||||||
|
|
||||||
|
Custom events can be defined; to do so, simply yield the coroutine with your custom event type (using `coroutine.yield("event type", event_data)`) from a function called in the anselme script.
|
||||||
|
|
||||||
|
For example, to add a `wait` event that pauses the script for some time, you could do something along these lines:
|
||||||
|
```lua
|
||||||
|
state:define("wait", "(duration::is number)", function(duration) coroutine.yield("wait", duration) end)
|
||||||
|
waiting = false
|
||||||
|
|
||||||
|
-- and edit your Anselme event handler with something like:
|
||||||
|
if not waiting then
|
||||||
|
local event_type, event_data = run_state = run_state:step()
|
||||||
|
if e == "wait" then
|
||||||
|
waiting = true
|
||||||
|
call_after_duration(event_data, function() waiting = false end)
|
||||||
|
else
|
||||||
|
-- handle other event types...
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
And then from your Anselme script:
|
||||||
|
```
|
||||||
|
| Hello...
|
||||||
---
|
---
|
||||||
_file generated at 2024-11-09T17:00:43Z_
|
wait(5)
|
||||||
|
| ...world !
|
||||||
|
```
|
||||||
|
|
||||||
|
## TextEventData
|
||||||
|
|
||||||
|
TextEventData represent the data returned by an event with the type `"text"`.
|
||||||
|
See the [language documentation](language.md#texts) for more details on how to create a text event.
|
||||||
|
|
||||||
|
A TextEventData contains a list of [LuaText](#luatext), each LuaText representing a separate line of the text event.
|
||||||
|
|
||||||
|
For example, the following Anselme script:
|
||||||
|
|
||||||
|
```
|
||||||
|
| Hi!
|
||||||
|
| My name's John.
|
||||||
|
```
|
||||||
|
will return a text event containing two LuaTexts, the first containing the text "Hi!" and the second "My name's John.".
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
```lua
|
||||||
|
local event_type, event_data = run_state:step()
|
||||||
|
if event_type == "text" then
|
||||||
|
-- event_data is a TextEventData, i.e. a list of LuaText
|
||||||
|
for _, luatext in ipairs(event_data) do
|
||||||
|
-- luatext is a list of text parts { text = "text string", tags = { ... } }
|
||||||
|
for _, textpart in ipairs(luatext) do
|
||||||
|
write_text_part_with_color(textpart.text, textpart.tags.color)
|
||||||
|
end
|
||||||
|
write_text("\n") -- for example, if we want a newline between each text line
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- handle other event types...
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
_defined at line 74 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `local TextEventData`
|
||||||
|
|
||||||
|
### :group_by (tag_name)
|
||||||
|
|
||||||
|
Returns a list of TextEventData where the first part of each LuaText of each TextEventData has the same value for the tag `tag_name`.
|
||||||
|
|
||||||
|
In other words, this groups all the LuaTexts contained in this TextEventData using the `tag_name` tag and returns a list containing these groups.
|
||||||
|
|
||||||
|
For example, with the following Anselme script:
|
||||||
|
```
|
||||||
|
speaker: "John" #
|
||||||
|
| A
|
||||||
|
| B
|
||||||
|
speaker: "Lana" #
|
||||||
|
| C
|
||||||
|
speaker: "John" #
|
||||||
|
| D
|
||||||
|
```
|
||||||
|
calling `text_event_data:group_by("speaker")` will return a list of three TextEventData:
|
||||||
|
* the first with the texts "A" and "B"; both with the tag `speaker="John"`
|
||||||
|
* the second with the text "C"; with the tag `speaker="Lana"`
|
||||||
|
* the last with the text "D"; wiith the tag `speaker="John"`
|
||||||
|
|
||||||
|
_defined at line 96 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `group_by = function(self, tag_name)`
|
||||||
|
|
||||||
|
|
||||||
|
## ChoiceEventData
|
||||||
|
|
||||||
|
ChoiceEventData represent the data returned by an event with the type `"choice"`.
|
||||||
|
See the [language documentation](language.md#choices) for more details on how to create a choice event.
|
||||||
|
|
||||||
|
A ChoiceEventData contains a list of [LuaText](#luatext), each LuaText representing a separate choice of the choice event.
|
||||||
|
|
||||||
|
For example, the following Anselme script:
|
||||||
|
|
||||||
|
```
|
||||||
|
*| Yes!
|
||||||
|
*| No.
|
||||||
|
```
|
||||||
|
will return a choice event containing two LuaTexts, the first containing the text "Yes!" and the second "No.".
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
```lua
|
||||||
|
current_choice = nil
|
||||||
|
waiting_for_choice = false
|
||||||
|
|
||||||
|
-- in your anselem event handling loop:
|
||||||
|
if not waiting_for_choice then
|
||||||
|
local event_type, event_data = run_state:step()
|
||||||
|
if event_type == "choice" then
|
||||||
|
-- event_data is a ChoiceEventData, i.e. a list of LuaText
|
||||||
|
for i, luatext in ipairs(event_data) do
|
||||||
|
write(("Choice number %s:"):format(i))
|
||||||
|
-- luatext is a list of text parts { text = "text string", tags = { ... } }
|
||||||
|
for _, textpart in ipairs(luatext) do
|
||||||
|
write_choice_part_with_color(textpart.text, textpart.tags.color)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- handle other event types...
|
||||||
|
end
|
||||||
|
current_choice = event_data
|
||||||
|
waiting_for_choice = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- somewhere in your code where choices are selected
|
||||||
|
current_choice:select(choice_number)
|
||||||
|
waiting_for_choice = false
|
||||||
|
```
|
||||||
|
|
||||||
|
_defined at line 50 of [anselme/ast/Choice.lua](../anselme/ast/Choice.lua):_ `local ChoiceEventData = class {`
|
||||||
|
|
||||||
|
### :choose (choice)
|
||||||
|
|
||||||
|
Choose the choice at position `choice` (number).
|
||||||
|
|
||||||
|
A choice must be selected after receiving a choice event and before calling `:step` again.
|
||||||
|
|
||||||
|
_defined at line 58 of [anselme/ast/Choice.lua](../anselme/ast/Choice.lua):_ `choose = function(self, choice)`
|
||||||
|
|
||||||
|
|
||||||
|
## LuaText
|
||||||
|
|
||||||
|
A Lua-friendly representation of an Anselme Text value.
|
||||||
|
They appear in both TextEventData and ChoiceEventData to represent the text that has to be shown.
|
||||||
|
|
||||||
|
It contains a list of _text parts_, which are parts of a single text, each part potentially having differrent tags attached.
|
||||||
|
A text will typically only consist of a single part unless it was built using text interpolation.
|
||||||
|
|
||||||
|
Each text part is a table containing `text` (string) and `tags` (table) properties, for example: `{ text = "text part string", tags = { color = "red" } }`.
|
||||||
|
|
||||||
|
_defined at line 17 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `local LuaText`
|
||||||
|
|
||||||
|
### .raw
|
||||||
|
|
||||||
|
Anselme Text value this was created from. For advanced usage only. See the source file [Text.lua](anselme/ast/Text.lua) for more information.
|
||||||
|
|
||||||
|
_defined at line 25 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `raw = nil,`
|
||||||
|
|
||||||
|
### :__tostring ()
|
||||||
|
|
||||||
|
Returns a text representation of the LuaText, using Anselme's default formatting. Useful for debugging.
|
||||||
|
|
||||||
|
Usage: `print(luatext)`
|
||||||
|
|
||||||
|
_defined at line 39 of [anselme/ast/Text.lua](../anselme/ast/Text.lua):_ `__tostring = function(self)`
|
||||||
|
|
||||||
|
---
|
||||||
|
_file generated at 2024-11-11T13:33:43Z_
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
This document describes how to use the main Anselme modules. This is generated automatically from the source files.
|
This document describes how to use the main Anselme modules. This is generated automatically from the source files.
|
||||||
|
|
||||||
Note that this file only describes the `anselme` and `state.State` modules, which are only a selection of what I consider to be the "public API" of Anselme that I will try to keep stable.
|
Note that this file only describes the `anselme` and `state.State` modules, as well as the `TextEventData` and `ChoiceEventData` classes, which are only a selection of what I consider to be the "public API" of Anselme that I will try to keep stable.
|
||||||
If you need more advanced control on Anselme, feel free to look into the other source files to find more; the most useful functions should all be reasonably commented.
|
If you need more advanced control on Anselme, feel free to look into the other source files to find more; the most useful functions should all be reasonably commented.
|
||||||
|
|
||||||
# anselme
|
# anselme
|
||||||
|
|
@ -10,3 +10,40 @@ If you need more advanced control on Anselme, feel free to look into the other s
|
||||||
# State
|
# State
|
||||||
|
|
||||||
{{anselme/state/State.lua}}
|
{{anselme/state/State.lua}}
|
||||||
|
|
||||||
|
# Events
|
||||||
|
|
||||||
|
Anselme scripts communicate with the game by sending events. See the [language documentation](language.md#events) for more details on events.
|
||||||
|
|
||||||
|
Custom events can be defined; to do so, simply yield the coroutine with your custom event type (using `coroutine.yield("event type", event_data)`) from a function called in the anselme script.
|
||||||
|
|
||||||
|
For example, to add a `wait` event that pauses the script for some time, you could do something along these lines:
|
||||||
|
```lua
|
||||||
|
state:define("wait", "(duration::is number)", function(duration) coroutine.yield("wait", duration) end)
|
||||||
|
waiting = false
|
||||||
|
|
||||||
|
-- and edit your Anselme event handler with something like:
|
||||||
|
if not waiting then
|
||||||
|
local event_type, event_data = run_state = run_state:step()
|
||||||
|
if e == "wait" then
|
||||||
|
waiting = true
|
||||||
|
call_after_duration(event_data, function() waiting = false end)
|
||||||
|
else
|
||||||
|
-- handle other event types...
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
And then from your Anselme script:
|
||||||
|
```
|
||||||
|
| Hello...
|
||||||
|
---
|
||||||
|
wait(5)
|
||||||
|
| ...world !
|
||||||
|
```
|
||||||
|
|
||||||
|
{{anselme/ast/Text.lua}}
|
||||||
|
|
||||||
|
{{anselme/ast/Choice.lua}}
|
||||||
|
|
||||||
|
{{:lua text}}
|
||||||
|
|
@ -887,6 +887,8 @@ A text event value can be created using the [text literal](#text). A text is wri
|
||||||
text!
|
text!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
How the data returned by a Text event is structured is detailled in the [API documentation](api.md#texteventdata).
|
||||||
|
|
||||||
### Choices
|
### Choices
|
||||||
|
|
||||||
Choice events are intended to represent a player choice in the host game. Each choice event in the buffer list is intended to represent a distinct choice.
|
Choice events are intended to represent a player choice in the host game. Each choice event in the buffer list is intended to represent a distinct choice.
|
||||||
|
|
@ -902,6 +904,8 @@ A choice event can be written to the buffer using the `*_` operator on a text ev
|
||||||
| Choice B has been selected.
|
| Choice B has been selected.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
How the data returned by a Text event is structured is detailled in the [API documentation](api.md#choiceeventdata).
|
||||||
|
|
||||||
### Tags
|
### Tags
|
||||||
|
|
||||||
Text and choice events can also carry metadata through tags. Tags are stored as a [struct](#struct).
|
Text and choice events can also carry metadata through tags. Tags are stored as a [struct](#struct).
|
||||||
|
|
|
||||||
|
|
@ -38,14 +38,14 @@ local function run_loop(run_state, write_output, interactive)
|
||||||
for _, v in ipairs(grouped) do
|
for _, v in ipairs(grouped) do
|
||||||
if groups then write_output(":: group ::") end
|
if groups then write_output(":: group ::") end
|
||||||
for _, l in ipairs(v) do
|
for _, l in ipairs(v) do
|
||||||
write_output(l:format(run_state))
|
write_output(l.raw:format(run_state))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif e == "choice" then
|
elseif e == "choice" then
|
||||||
local choice
|
local choice
|
||||||
if interactive then
|
if interactive then
|
||||||
for i, l in ipairs(data) do
|
for i, l in ipairs(data) do
|
||||||
write_output(("%s> %s"):format(i, l:format(run_state)))
|
write_output(("%s> %s"):format(i, l.raw:format(run_state)))
|
||||||
end
|
end
|
||||||
io.write(("Select choice (1-%s): "):format(#data))
|
io.write(("Select choice (1-%s): "):format(#data))
|
||||||
choice = tonumber(io.read("l"))
|
choice = tonumber(io.read("l"))
|
||||||
|
|
@ -53,9 +53,9 @@ local function run_loop(run_state, write_output, interactive)
|
||||||
choice = assert(run_state:eval_local("choice"), "no choice selected"):to_lua()
|
choice = assert(run_state:eval_local("choice"), "no choice selected"):to_lua()
|
||||||
for i, l in ipairs(data) do
|
for i, l in ipairs(data) do
|
||||||
if i == choice then
|
if i == choice then
|
||||||
write_output(("=> %s"):format(l:format(run_state)))
|
write_output(("=> %s"):format(l.raw:format(run_state)))
|
||||||
else
|
else
|
||||||
write_output((" > %s"):format(l:format(run_state)))
|
write_output((" > %s"):format(l.raw:format(run_state)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue