summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-cap.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/typo-cap.lua')
-rw-r--r--tex/context/base/typo-cap.lua109
1 files changed, 80 insertions, 29 deletions
diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua
index 5f741da7c..a29e45810 100644
--- a/tex/context/base/typo-cap.lua
+++ b/tex/context/base/typo-cap.lua
@@ -8,13 +8,16 @@ if not modules then modules = { } end modules ['typo-cap'] = {
local next, type = next, type
local format, insert = string.format, table.insert
+local div = math.div
-local trace_casing = false trackers.register("nodes.casing", function(v) trace_casing = v end)
+local trace_casing = false trackers.register("typesetting.casing", function(v) trace_casing = v end)
-local has_attribute = node.has_attribute
-local unset_attribute = node.unset_attribute
-local set_attribute = node.set_attribute
-local traverse_id = node.traverse_id
+local report_casing = logs.new("casing")
+
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local set_attribute = node.set_attribute
+local traverse_id = node.traverse_id
local glyph = node.id("glyph")
local kern = node.id("kern")
@@ -23,14 +26,28 @@ local fontdata = fonts.ids
local fontchar = fonts.chr
local chardata = characters.data
-cases = cases or { }
+typesetting = typesetting or { }
+typesetting.cases = typesetting.cases or { }
+
+local cases = typesetting.cases
+
cases.actions = { }
-cases.attribute = attributes.private("case")
+cases.attribute = attributes.private("case") -- no longer needed
+
+local a_cases = cases.attribute
local actions = cases.actions
local lastfont = nil
--- we use char0 as placeholder for the larger font
+-- we use char(0) as placeholder for the larger font, so we need to remove it
+-- before it can do further harm
+--
+-- we could do the whole glyph run here (till no more attributes match) but
+-- then we end up with more code .. maybe i will clean this up anyway as the
+-- lastfont hack is somewhat ugly .. on the other hand, we need to deal with
+-- cases like:
+--
+-- \WORD {far too \Word{many \WORD{more \word{pushed} in between} useless} words}
local function helper(start, code, codes, special, attribute, once)
local char = start.char
@@ -38,6 +55,7 @@ local function helper(start, code, codes, special, attribute, once)
if dc then
local fnt = start.font
if special then
+ -- will become function
if start.char == 0 then
lastfont = fnt
local prev, next = start.prev, start.next
@@ -51,7 +69,6 @@ local function helper(start, code, codes, special, attribute, once)
start.font = lastfont
end
end
- -- local ifc = fontdata[fnt].characters
local ifc = fontchar[fnt]
local ucs = dc[codes]
if ucs then
@@ -106,7 +123,7 @@ actions[2] = function(start,attribute)
return helper(start,'lccode','lccodes')
end
-actions[3] = function(start,attribute)
+actions[3] = function(start,attribute,attr)
lastfont = nil
local prev = start.prev
if prev and prev.id == kern and prev.subtype == 0 then
@@ -115,10 +132,14 @@ actions[3] = function(start,attribute)
if not prev or prev.id ~= glyph then
--- only the first character is treated
for n in traverse_id(glyph,start.next) do
- if has_attribute(n,attribute) then
+ if has_attribute(n,attribute) == attr then
unset_attribute(n,attribute)
+ else
+ -- break -- we can have nested mess
end
end
+ -- we could return the last in the range and save some scanning
+ -- but why bother
return helper(start,'uccode','uccodes')
else
return start, false
@@ -174,37 +195,67 @@ actions[8] = function(start)
end
end
end
- else
- return start, false
end
+ return start, false
end
-- node.traverse_id_attr
-function cases.process(namespace,attribute,head) -- not real fast but also not used on much data
+local function process(namespace,attribute,head) -- not real fast but also not used on much data
lastfont = nil
+ local lastattr = nil
local done = false
- for start in traverse_id(glyph,head) do
- local attr = has_attribute(start,attribute)
- if attr and attr > 0 then
- unset_attribute(start,attribute)
- local action = actions[attr]
- if action then
- local _, ok = action(start,attribute)
- done = done and ok
+ local start = head
+ while start do -- while because start can jump ahead
+ local id = start.id
+ if id == glyph then
+ local attr = has_attribute(start,attribute)
+ if attr and attr > 0 then
+ if attr ~= lastattr then
+ lastfont = nil
+ lastattr = attr
+ end
+ unset_attribute(start,attribute)
+ local action = actions[attr%100] -- map back to low number
+ if action then
+ start, ok = action(start,attribute,attr)
+ done = done and ok
+ if trace_casing then
+ report_casing("case trigger %s, instance %s, result %s",attr%100,div(attr,100),tostring(ok))
+ end
+ elseif trace_casing then
+ report_casing("unknown case trigger %s",attr)
+ end
end
end
+ if start then
+ start = start.next
+ end
end
lastfont = nil
return head, done
end
-chars.handle_casing = nodes.install_attribute_handler {
- name = "case",
- namespace = cases,
- processor = cases.process,
-}
+local m = 0 -- a trick to make neighbouring ranges work
-function cases.enable()
- tasks.enableaction("processors","chars.handle_casing")
+function cases.set(n)
+ if trace_casing then
+ report_casing("enabling case handler")
+ end
+ tasks.enableaction("processors","typesetting.cases.handler")
+ function cases.set(n)
+ if m == 100 then
+ m = 1
+ else
+ m = m + 1
+ end
+ tex.attribute[a_cases] = m * 100 + n
+ end
+ cases.set(n)
end
+
+cases.handler = nodes.install_attribute_handler {
+ name = "case",
+ namespace = cases,
+ processor = process,
+}