Skip to content

Commit

Permalink
Add small user interaction module
Browse files Browse the repository at this point in the history
For now, only contains a `yes_no_prompt` function.
  • Loading branch information
euclidianAce committed May 18, 2023
1 parent 763f1ef commit ea2c9c1
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 0 deletions.
82 changes: 82 additions & 0 deletions build/cyan/interaction.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions cyan-dev-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ build = {
["cyan.fs.init"] = "build/cyan/fs/init.lua",
["cyan.fs.path"] = "build/cyan/fs/path.lua",
["cyan.graph"] = "build/cyan/graph.lua",
["cyan.interaction"] = "build/cyan/interaction.lua",
["cyan.log"] = "build/cyan/log.lua",
["cyan.meta"] = "build/cyan/meta.lua",
["cyan.sandbox"] = "build/cyan/sandbox.lua",
Expand All @@ -54,6 +55,7 @@ build = {
["cyan.fs.init"] = "src/cyan/fs/init.tl",
["cyan.fs.path"] = "src/cyan/fs/path.tl",
["cyan.graph"] = "src/cyan/graph.tl",
["cyan.interaction"] = "src/cyan/interaction.tl",
["cyan.log"] = "src/cyan/log.tl",
["cyan.meta"] = "src/cyan/meta.tl",
["cyan.sandbox"] = "src/cyan/sandbox.tl",
Expand Down
82 changes: 82 additions & 0 deletions src/cyan/interaction.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---@brief
--- Module for handling when input from the user is needed

local log <const> = require("cyan.log")
local cs <const> = require("cyan.colorstring")
local ansi <const> = require("cyan.ansi")

local interaction <const> = {}

local affirmative <const> = { ansi.color.dark.green }
local negative <const> = { ansi.color.dark.red }

local yesses <const> = { "yes", "yeah", "yea", "ye", "y" }
local nos <const> = { "no", "nope", "n" }

local function title_case(s: string): string
return s:sub(1, 1):upper() .. s:sub(2, -1):lower()
end

local function to_string_set(list: {string}): {string:boolean}
local result <const> = {}
for _, v in ipairs(list) do
result[v:lower()] = true
end
return result
end

---@desc
--- Ask the user to affirm or deny a given prompt. The user input will be
--- compared against the given `affirm` and `deny` lists (case-insensitive), with
--- defaults used if - they are not provided.
---
--- The given logger will be used to print the prompt, and `log.info` if none
--- is provided.
function interaction.yes_no_prompt(
prompt: string,
logger: log.Logger,
default: boolean,
affirm: {string},
deny: {string}
): boolean
logger = logger or log.info
affirm = affirm or yesses
deny = deny or nos

local y <const> = cs.highlight(
affirmative,
default and title_case(affirm[1]) or affirm[1]:lower()
)
local n <const> = cs.highlight(
negative,
default and deny[1]:lower() or title_case(deny[1])
)
local prompt_str <const> = prompt .. " [" .. y .. "/" .. n .. "]: "

local affirm_set <const> = to_string_set(affirm)
local deny_set <const> = to_string_set(deny)

while true do
logger:nonl(prompt_str)
logger.stream:flush()
local input = io.read("*l"):lower()

if #input == 0 then
logger:cont(
"Defaulting to ",
default
and cs.highlight(affirmative, title_case(affirm[1]))
or cs.highlight(negative, title_case(deny[1]))
)
return default or false
end

if affirm_set[input] then
return true
elseif deny_set[input] then
return false
end
end
end

return interaction

0 comments on commit ea2c9c1

Please sign in to comment.