strc-blk.lua /size: 6432 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['strc-blk'] = {
2    version   = 1.001,
3    comment   = "companion to strc-blk.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
9-- this one runs on top of buffers and structure
10
11local type, next = type, next
12local find, formatters, validstring = string.find, string.formatters, string.valid
13local settings_to_set, settings_to_array = utilities.parsers.settings_to_set, utilities.parsers.settings_to_array
14local allocate = utilities.storage.allocate
15
16local context     = context
17local commands    = commands
18
19local implement   = interfaces.implement
20
21local structures  = structures
22
23structures.blocks = structures.blocks or { }
24
25local blocks      = structures.blocks
26local sections    = structures.sections
27local lists       = structures.lists
28local helpers     = structures.helpers
29
30local collected   = allocate()
31local tobesaved   = allocate()
32local states      = allocate()
33
34blocks.collected  = collected
35blocks.tobesaved  = tobesaved
36blocks.states     = states
37
38local function initializer()
39    collected = blocks.collected
40    tobesaved = blocks.tobesaved
41end
42
43job.register('structures.blocks.collected', tobesaved, initializer)
44
45local listitem = utilities.parsers.listitem
46local f_block  = formatters["block.%s"]
47
48function blocks.uservariable(index,key,default)
49    local c = collected[index]
50    if c then
51        local u = c.userdata
52        if u then
53            local v = u[key] or default
54            if v then
55                context(v)
56            end
57        end
58    end
59end
60
61local function printblock(index,name,data,hide)
62    if hide then
63        context.dostarthiddenblock(index,name)
64    else
65        context.dostartnormalblock(index,name)
66    end
67    context.viafile(data,f_block(validstring(name,"noname")))
68    if hide then
69        context.dostophiddenblock()
70    else
71        context.dostopnormalblock()
72    end
73end
74
75blocks.print = printblock
76
77function blocks.define(name)
78    states[name] = { all = "hide" }
79end
80
81function blocks.setstate(state,name,tag)
82    local all  = tag == ""
83    local tags = not all and settings_to_array(tag)
84    for n in listitem(name) do
85        local sn = states[n]
86        if not sn then
87            -- error
88        elseif all then
89            sn.all = state
90        else
91            for _, tag in next, tags do
92                sn[tag] = state
93            end
94        end
95    end
96end
97
98
99local function selectblocks(state,name,tag,criterium,action)
100    if not criterium or criterium == "" then
101        criterium = "text"
102    end
103    if find(tag,"=",1,true) then
104        tag = ""
105    end
106    local names  = settings_to_set(name)
107    local all    = tag == ""
108    local tags   = not all and settings_to_set(tag)
109    local hide   = state == "process"
110    local result = lists.filter {
111        names     = "all",
112        criterium = criterium,
113        number    = sections.numberatdepth(criterium), -- not needed
114        collected = collected,
115    }
116    for i=1,#result do
117        local ri = result[i]
118        local metadata = ri.metadata
119        if names[metadata.name] then
120            if all then
121                if action(ri.index,name,ri.data,hide) then
122                    return
123                end
124            else
125                local mtags = metadata.tags
126                if mtags then
127                    for tag, sta in next, tags do
128                        if mtags[tag] then
129                            if action(ri.index,name,ri.data,hide) then
130                                return
131                            else
132                                break
133                            end
134                        end
135                    end
136                end
137            end
138        end
139    end
140end
141
142function blocks.select(state,name,tag,criterium)
143    selectblocks(state,name,tag,criterium,printblock)
144end
145
146function blocks.empty(state,name,tag,criterium)
147    local found = false
148    local function checkempty(_,_,data)
149        found = type(data) == "string" and find(data,"%S")
150        return found
151    end
152    selectblocks(state,name,tag,criterium,checkempty)
153    return not found
154end
155
156function blocks.save(name,tag,userdata,buffer) -- wrong, not yet adapted
157    local data  = buffers.getcontent(buffer)
158    local tags  = settings_to_set(tag)
159    local plus  = false
160    local minus = false
161    local last  = #tobesaved + 1
162    local all   = states[name].all
163    if tags['+'] then
164        plus      = true
165        tags['+'] = nil
166    end
167    if tags['-'] then
168        minus     = true
169        tags['-'] = nil
170    end
171    tobesaved[last] = helpers.simplify {
172        metadata   = {
173            name  = name,
174            tags  = tags,
175            plus  = plus,
176            minus = minus,
177        },
178        index      = last,
179        data       = data or "error",
180        userdata   = userdata and type(userdata) == "string" and helpers.touserdata(userdata),
181        references = {
182            section = sections.currentid(),
183        },
184    }
185    if not next(tags) then
186        if all ~= "hide" then
187            printblock(last,name,data)
188        elseif plus then
189            printblock(last,name,data,true)
190        end
191    else
192        local sn = states[name]
193        for tag, _ in next, tags do
194            if sn[tag] == nil then
195                if all ~= "hide" then
196                    printblock(last,name,data)
197                    break
198                end
199            elseif sn[tag] ~= "hide" then
200                printblock(last,name,data)
201                break
202            end
203        end
204    end
205    buffers.erase(buffer)
206end
207
208
209-- interface
210
211implement { name = "definestructureblock",       actions = blocks.define,       arguments = "string" }
212implement { name = "savestructureblock",         actions = blocks.save,         arguments = "4 strings" }
213implement { name = "selectstructureblock",       actions = blocks.select,       arguments = "4 strings" }
214implement { name = "setstructureblockstate",     actions = blocks.setstate,     arguments = "3 strings" }
215implement { name = "structureblockuservariable", actions = blocks.uservariable, arguments = { "integer", "string" } }
216
217implement {
218    name      = "doifelsestructureblocksempty",
219    arguments = "3 strings",
220    actions   = function(name,tag,criterium)
221        commands.doifelse(blocks.empty(false,name,tag,criterium))
222    end,
223}
224