summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-12-19 03:42:29 -0600
committersanine <sanine.not@pm.me>2022-12-19 03:42:29 -0600
commit4e006be646fba8dde7284cfe4c18f0222e8298ad (patch)
treea4f7ee2c7c1f38164781a04a6306b3dd6a35fca4
parentfab85f8d639c8b7792775d02a2d3fe22fe96befd (diff)
add help page and hidden mode
-rwxr-xr-xamaryllis.cgi277
-rw-r--r--language.lua26
2 files changed, 180 insertions, 123 deletions
diff --git a/amaryllis.cgi b/amaryllis.cgi
index 83b6e4f..12d2c15 100755
--- a/amaryllis.cgi
+++ b/amaryllis.cgi
@@ -7,22 +7,30 @@ local h = marigold.h
local metavars = marigold.get_metavars()
local settings = marigold.decode_query(metavars.query_string or '')
-settings.seed = tonumber(settings.seed) or os.time()
-math.randomseed(settings.seed)
-settings.phonemes = settings.phonemes or [[
+local body
+if not settings.help then
+ settings.randomize_seed = settings.randomize_seed or false
+ if settings.randomize_seed then
+ settings.seed = os.time()
+ else
+ settings.seed = tonumber(settings.seed) or os.time()
+ end
+ math.randomseed(settings.seed)
+
+ settings.phonemes = settings.phonemes or [[
C=mnbdTLshzwrly
V=aeiou
T=1324
-]]
-
-settings.syllables = settings.syllables or [[
+ ]]
+
+ settings.syllables = settings.syllables or [[
CVT
CVTl
CVTn
-]]
-
-settings.orthography = settings.orthography or [[
+ ]]
+
+ settings.orthography = settings.orthography or [[
T=th
L=lh
z=zh
@@ -30,120 +38,161 @@ z=zh
(%V)2=%1%1́
(%V)3=%1
(%V)4=%1́%1
-]]
-
-settings.phonemes_decay = settings.phonemes_decay or 'Q'
-settings.syllables_decay = settings.syllables_decay or 'Q'
-
-settings.len_min = settings.len_min or "1"
-settings.len_max = settings.len_max or "3"
-settings.count = settings.count or "20"
-
-
-local distributions = {
- U=lang.uniform,
- Q=lang.quadratic,
-}
-
-local p_dist = distributions[settings.phonemes_decay]
-local s_dist = distributions[settings.syllables_decay]
-
-
-local l = lang.Language(
- settings.phonemes,
- settings.syllables,
- settings.orthography,
- tonumber(settings.len_min),
- tonumber(settings.len_max),
- p_dist,
- s_dist
-)
-
-
-local syllable_html = {}
-for i=1,tonumber(settings.count) do
- table.insert(
- syllable_html,
- h('li', l:romanize(l:word()))
+ ]]
+
+ settings.phonemes_decay = settings.phonemes_decay or 'Q'
+ settings.syllables_decay = settings.syllables_decay or 'Q'
+
+ settings.len_min = settings.len_min or "1"
+ settings.len_max = settings.len_max or "3"
+ settings.count = settings.count or "20"
+
+
+ local distributions = {
+ U=lang.uniform,
+ Q=lang.quadratic,
+ }
+
+ local p_dist = distributions[settings.phonemes_decay]
+ local s_dist = distributions[settings.syllables_decay]
+
+
+ local l = lang.Language(
+ settings.phonemes,
+ settings.syllables,
+ settings.orthography,
+ tonumber(settings.len_min),
+ tonumber(settings.len_max),
+ p_dist,
+ s_dist
)
-end
-syllable_html = h('ol', syllable_html)
-
-
-function radiobutton(label, name, value, checked)
- local radio = h('input', {
- type="radio",
- name=name,
- id = name .. value,
- value = value,
- checked = (checked and "true") or nil
+
+
+ local syllable_html = {}
+ for i=1,tonumber(settings.count) do
+ table.insert(
+ syllable_html,
+ h('li', l:romanize(l:word()))
+ )
+ end
+ syllable_html = h('ol', syllable_html)
+
+
+ function radiobutton(label, name, value, checked)
+ local radio = h('input', {
+ type="radio",
+ name=name,
+ id = name .. value,
+ value = value,
+ checked = (checked and "true") or nil
+ })
+ local lbl = {}
+ lbl['for'] = name .. value
+ local label = h('label', label, lbl)
+
+ return h('div', { radio, label })
+ end
+
+
+ function textarea(name, text, decay)
+ local children = { class="noborder",
+ h('legend', name),
+ h('textarea', text, { name=name, rows="6", spellcheck="false" }),
+ }
+
+ if decay then table.insert(children, h('fieldset', {
+ h('legend', name .. ' decay'),
+ radiobutton("uniform", name .. '_decay', 'U', settings[name .. '_decay'] == 'U'),
+ radiobutton("quadratic", name .. '_decay', 'Q', settings[name .. '_decay'] == 'Q'),
+ })
+ ) end
+
+ return h('fieldset', children)
+ end
+
+
+ local form = h('form', {
+ h('label', 'seed', {
+ h('input', { name="seed", type="number", value=tostring(settings.seed) }),
+ }),
+
+ h('input', { value="update", type="Submit" } ),
+ h('br'),
+ h('label', 'randomize seed', {
+ h('input', {
+ name="randomize_seed",
+ type="checkbox",
+ checked=(settings.randomize_seed and "true") or nil,
+ value=(settings.randomize_seed and "on") or nil,
+ }),
+ }),
+
+ h('br'),
+ h('div', { class="form-flex",
+ textarea('phonemes', settings.phonemes, true),
+ textarea('syllables', settings.syllables, true),
+ textarea('orthography', settings.orthography, false),
+ }),
+ h('br'),
+
+ h('label', 'min syllables', {
+ h('input', { name="len_min", type="number", min="1", value=settings.len_min }),
+ }),
+ h('br'),
+ h('label', 'max syllables', {
+ h('input', { name="len_max", type="number", min="1", value=settings.len_max }),
+ }),
+ h('br'),
+ h('label', '# to generate', {
+ h('input', { name="count", type="number", min="1", value=settings.count }),
+ }),
+
+ h('input', { value="update", type="Submit" } ),
})
- local lbl = {}
- lbl['for'] = name .. value
- local label = h('label', label, lbl)
- return h('div', { radio, label })
-end
-
-
-function textarea(name, text, decay)
- local children = { class="noborder",
- h('legend', name),
- h('textarea', text, { name=name, rows="6", spellcheck="false" }),
- }
- if decay then table.insert(children, h('fieldset', {
- h('legend', name .. ' decay'),
- radiobutton("uniform", name .. '_decay', 'U', settings[name .. '_decay'] == 'U'),
- radiobutton("quadratic", name .. '_decay', 'Q', settings[name .. '_decay'] == 'Q'),
+ if settings.hide then
+ form = h('div', {
+ h('form', { h('input', { value="Show details", type="Submit" })}),
+ h('form', {
+ h('input', { name="hide", value="1", type="hidden" }),
+ h('input', { value="Refresh", type="Submit" })
+ })
})
- ) end
+ end
+
+
+ local self_path = metavars.path_info .. '/' .. metavars.script_name
+ self_path = string.gsub(self_path, '^//', '/')
+
+ body = h('body', { h('div', { id="content",
+ h('a', '<- projects', { href='https://sanine.net/projects/' }),
+ h('br'), h('br'),
+ form,
+ h('hr'),
+ syllable_html,
+ h('a', 'share this link!', {
+ href=self_path .. '?' .. metavars.query_string
+ }),
+ h('a', 'what the heck is this?', { href=self_path .. '?help=1' }),
+ })})
+else
+ -- help page!
+ body = h('body', { h('div', { id="content",
+ h('a', '<- projects', { href='https://sanine.net/projects/' }),
+ h('p', 'This is a tool for generating words in invented languages. You can set up your basic phonology (int the phonemes tab), your phonotactics (in the syllables tab), and romanization/orthography issues (in the orthography tab).'),
+ h('p', "The 'seed' value, at the top, is the mathematical value used for all of the other random generation. Change it to get new words, or leave it alone to tinker with the settings and see how they change the words you get."),
+ h('p', "In the phonemes tab you should pick out the phonemes for your language. Because of how the syllables work, you should sort them into classes. Each line, you write something like <code>V=aeiou</code>, where V is the class and a, e, i, o, and u are the phones that are members of the class. (In this case the class letter V was selected to represent the vowels). The class name can only be one character long, but it can be any character. Take care not to make it a character that occurs within your phones; this may lead to strange results!"),
+ h('p', "In the syllables tab, you define which syllables are possible for your language, using the phoneme classes defined earlier. Each line defines one syllable type. For instance, if we have a C and V class, then <code>CVC</code> would be a traditional CVC syllable. If you use letters in your syllable definitions which are <i>not</i> phoneme classes, they will simply be output as part of that syllable type verbatim."),
+ h('p', "In the orthography tab, you define rewrite rules for text. Each rule looks like [pattern]=[replacement]. Anything that matches the pattern will be replaced with replacement. The special sequence (%x), where x is one of your phoneme classes, will match any one of the phones in that class. The special sequence %1 will then be replaced in the replacement with whichever phone matched the (%x) pattern. This can be useful to avoid writing a distinct rule for each element in the class."),
+ h('p', "Phonemes and syllables each have an additional parameter called 'decay' which is essentially the distribution of the probabilities. Uniform means that each element has an equal probability of being selected. Quadratic means that earlier elements have a higher probability of being selected than later elements, making the sequencing important."),
+ h('p', "Finally, min/max syllables is simply the minimum/maximum number of syllables to generate per word, and '# to generate' is the number of words to generate."),
+ h('p', "Have fun!!!"),
+ })})
- return h('fieldset', children)
end
-local form = h('form', {
- h('label', 'seed', {
- h('input', { name="seed", type="number", value=tostring(settings.seed) }),
- }),
-
- h('input', { value="update", type="Submit" } ),
-
- h('br'),
- h('div', { class="form-flex",
- textarea('phonemes', settings.phonemes, true),
- textarea('syllables', settings.syllables, true),
- textarea('orthography', settings.orthography, false),
- }),
- h('br'),
-
- h('label', 'min syllables', {
- h('input', { name="len_min", type="number", min="1", value=settings.len_min }),
- }),
- h('br'),
- h('label', 'max syllables', {
- h('input', { name="len_max", type="number", min="1", value=settings.len_max }),
- }),
- h('br'),
- h('label', '# to generate', {
- h('input', { name="count", type="number", min="1", value=settings.count }),
- }),
-
- h('input', { value="update", type="Submit" } ),
-})
-
-
-local body = h('body', { h('div', { id="content",
- h('a', '<- projects', { href='https://sanine.net/projects/' }),
- h('br'), h('br'),
- form,
- h('hr'),
- syllable_html,
- h('a', 'hello there c:', { href="#" }),
-})})
-
-
local head = h('head', {
h('meta', { charset="utf-8" }),
h('meta', { name="viewport", content="width=device-width, initial-scale=1" }),
diff --git a/language.lua b/language.lua
index cf6725f..b6a2f77 100644
--- a/language.lua
+++ b/language.lua
@@ -53,8 +53,12 @@ end
local function parse_syllables(str)
local syllables = {}
for line in lines(str) do
- line = string.gsub(line, "%s", "")
- table.insert(syllables, string_to_array(line))
+ if string.match(line, "^%s*$") then
+ -- ignore blank lines
+ else
+ line = string.gsub(line, "%s", "")
+ table.insert(syllables, string_to_array(line))
+ end
end
return syllables
end
@@ -70,13 +74,17 @@ local function parse_orthography(str, phonemes)
-- trim whitespace
line = string.gsub(line, "%s*$", "")
local pattern, replace = string.match(line, "(.*)=(.*)")
- pattern = string.gsub(pattern, "%%(.)", function(class)
- if phonemes[class] == nil then
- return '%' .. class
- end
- return '[' .. table.concat(phonemes[class], '') .. ']'
- end)
- table.insert(rules, { pattern=pattern, replace=replace })
+ if not pattern then
+ -- ???
+ else
+ pattern = string.gsub(pattern, "%%(.)", function(class)
+ if phonemes[class] == nil then
+ return '%' .. class
+ end
+ return '[' .. table.concat(phonemes[class], '') .. ']'
+ end)
+ table.insert(rules, { pattern=pattern, replace=replace })
+ end
end
end
return rules