typo-man.lua /size: 2995 b    last modification: 2020-07-01 14:35
1if not modules then modules = { } end modules ['typo-man'] = {
2    version   = 1.001,
3    comment   = "companion to typo-prc.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9if not characters then
10    -- for testing stand-alone
11    require("char-def")
12    require("char-ini")
13end
14
15local lpegmatch  = lpeg.match
16local P, R, C, Ct, Cs, Carg = lpeg.P, lpeg.R, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg
17local global = global or _G
18
19local methods = {
20    uppercase = characters.upper,
21    lowercase = characters.lower,
22    Word      = converters.Word,
23    Words     = converters.Words,
24}
25
26local function nothing(s) return s end -- we already have that one somewhere
27
28-- table.setmetatableindex(methods,function(t,k)
29--     t[k] = nothing
30--     return nothing
31-- end)
32
33local splitter = lpeg.tsplitat(".")
34
35table.setmetatableindex(methods,function(t,k)
36    local s = lpegmatch(splitter,k)
37    local v = global
38    for i=1,#s do
39        v = v[s[i]]
40        if not v then
41            break
42        end
43    end
44    if not v or v == global then
45        v = nothing
46    end
47    t[k] = v
48    return v
49end)
50
51local whitespace = lpeg.patterns.whitespace^0
52local separator  = whitespace * P("->") * whitespace
53local pair       = C((1-separator)^1) * separator * C(P(1)^0)
54local list       = Ct((C((1-separator)^1) * separator)^1) * C(P(1)^0)
55
56local pattern = Carg(1) * pair / function(methods,operation,str)
57    return methods[operation](str) or str
58end
59
60local function apply(str,m)
61    return lpegmatch(pattern,str,1,m or methods) or str
62end
63
64local function splitspecification(field,m)
65    local m, f = lpegmatch(list,field,1,m or methods)
66    if m then
67        return m, f or field
68    else
69        return nil, field
70    end
71end
72
73local function applyspecification(actions,str)
74    if actions then
75        for i=1,#actions do
76            local action = methods[actions[i]]
77            if action then
78                str = action(str) or str
79            end
80        end
81    end
82    return str
83end
84
85if not typesetters then typesetters = { } end
86
87typesetters.manipulators = {
88    methods            = methods,
89    apply              = apply,
90    patterns           = {
91        pair = pair,
92        list = list,
93    },
94    splitspecification = splitspecification,
95    applyspecification = applyspecification,
96}
97
98local pattern = Cs((1 - P(1) * P(-1))^0 * (P(".")/"" + P(1)))
99
100methods.stripperiod = function(str) return lpegmatch(pattern,str) end
101
102-- print(apply("hans"))
103-- print(apply("uppercase->hans"))
104-- print(apply("string.reverse -> hans"))
105-- print(apply("uppercase->hans",{ uppercase = string.reverse } ))
106
107-- print(applyspecification(splitspecification("hans")))
108-- print(applyspecification(splitspecification("lowercase->uppercase->hans")))
109-- print(applyspecification(splitspecification("uppercase->stripperiod->hans.")))
110
111function commands.manipulated(str)
112    context(apply(str))
113end
114