summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-brk.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/typo-brk.lua')
-rw-r--r--tex/context/base/typo-brk.lua208
1 files changed, 208 insertions, 0 deletions
diff --git a/tex/context/base/typo-brk.lua b/tex/context/base/typo-brk.lua
new file mode 100644
index 000000000..8f7a00f9d
--- /dev/null
+++ b/tex/context/base/typo-brk.lua
@@ -0,0 +1,208 @@
+if not modules then modules = { } end modules ['typo-brk'] = {
+ version = 1.001,
+ comment = "companion to typo-brk.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this code dates from the beginning and is kind of experimental; it
+-- will be optimized and improved soon
+
+local next, type, tonumber = next, type, tonumber
+local utfbyte, utfchar = utf.byte, utf.char
+local format = string.format
+
+local settings_to_array = aux.settings_to_array
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local set_attribute = node.set_attribute
+local copy_node = node.copy
+local free_node = node.free
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+local make_penalty_node = nodes.penalty
+local make_glue_node = nodes.glue
+local make_disc_node = nodes.disc
+local make_glyph_node = nodes.glyph
+local remove_node = nodes.remove -- ! nodes
+local tonodes = blobs.tonodes
+
+local glyph = node.id("glyph")
+local kern = node.id("kern")
+
+breakpoints = breakpoints or { }
+breakpoints.mapping = breakpoints.mapping or { }
+breakpoints.methods = breakpoints.methods or { }
+breakpoints.attribute = attributes.private("breakpoint")
+
+storage.register("breakpoints/mapping", breakpoints.mapping, "breakpoints.mapping")
+
+local mapping = breakpoints.mapping
+
+function breakpoints.setreplacement(id,char,language,settings)
+ char = utfbyte(char)
+ local map = mapping[id]
+ if not map then
+ map = { }
+ mapping[id] = map
+ end
+ local cmap = map[char]
+ if not cmap then
+ cmap = { }
+ map[char] = cmap
+ end
+ local left, right, middle = settings.left, settings.right, settings.middle
+ cmap[language or ""] = {
+ kind = tonumber(settings.kind) or 1,
+ nleft = tonumber(settings.nleft) or 1,
+ nright = tonumber(settings.nright) or 1,
+ left = left ~= "" and left or nil,
+ right = right ~= "" and right or nil,
+ middle = middle ~= "" and middle or nil,
+ } -- was { kind or 1, before or 1, after or 1 }
+end
+
+local function insert_break(head,start,before,after)
+ insert_node_before(head,start,make_penalty_node(before))
+ insert_node_before(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_penalty_node(after))
+end
+
+breakpoints.methods[1] = function(head,start)
+ if start.prev and start.next then
+ insert_break(head,start,10000,0)
+ end
+ return head, start
+end
+breakpoints.methods[2] = function(head,start) -- ( => (-
+ if start.prev and start.next then
+ local tmp
+ head, start, tmp = remove_node(head,start)
+ head, start = insert_node_before(head,start,make_disc_node())
+ start.replace = tmp
+ local tmp, hyphen = copy_node(tmp), copy_node(tmp)
+ hyphen.char = languages.prehyphenchar(tmp.lang)
+ tmp.next, hyphen.prev = hyphen, tmp
+ start.post = tmp
+ insert_break(head,start,10000,10000)
+ end
+ return head, start
+end
+breakpoints.methods[3] = function(head,start) -- ) => -)
+ if start.prev and start.next then
+ local tmp
+ head, start, tmp = remove_node(head,start)
+ head, start = insert_node_before(head,start,make_disc_node())
+ start.replace = tmp
+ local tmp, hyphen = copy_node(tmp), copy_node(tmp)
+ hyphen.char = languages.prehyphenchar(tmp.lang)
+ tmp.prev, hyphen.next = hyphen, tmp
+ start.pre = hyphen
+ insert_break(head,start,10000,10000)
+ end
+ return head, start
+end
+breakpoints.methods[4] = function(head,start) -- - => - - -
+ if start.prev and start.next then
+ local tmp
+ head, start, tmp = remove_node(head,start)
+ head, start = insert_node_before(head,start,make_disc_node())
+ start.pre, start.post, start.replace = copy_node(tmp), copy_node(tmp), tmp
+ insert_break(head,start,10000,10000)
+ end
+ return head, start
+end
+breakpoints.methods[5] = function(head,start,settings) -- x => p q r
+ if start.prev and start.next then
+ local tmp
+ head, start, tmp = remove_node(head,start)
+ head, start = insert_node_before(head,start,make_disc_node())
+ start.pre, start.post, start.replace = tonodes(settings.right,tmp), tonodes(settings.left,tmp), tonodes(settings.middle,tmp)
+ free_node(tmp)
+ insert_break(head,start,10000,10000)
+ end
+ return head, start
+end
+
+local methods = breakpoints.methods
+
+function breakpoints.process(namespace,attribute,head)
+ local done, numbers = false, languages.numbers
+ local start, n = head, 0
+ while start do
+ local id = start.id
+ if id == glyph then
+ local attr = has_attribute(start,attribute)
+ if attr and attr > 0 then
+ unset_attribute(start,attribute) -- maybe test for subtype > 256 (faster)
+ -- look ahead and back n chars
+ local map = mapping[attr]
+ if map then
+ local cmap = map[start.char]
+ if cmap then
+ local lang = start.lang
+ -- we do a sanity check for language
+ local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""])
+ if smap then
+ if n >= smap.nleft then
+ local m = smap.nright
+ local next = start.next
+ while next do -- gamble on same attribute (not that important actually)
+ local id = next.id
+ if id == glyph then -- gamble on same attribute (not that important actually)
+ if map[next.char] then
+ break
+ elseif m == 1 then
+ local method = methods[smap.kind]
+ if method then
+ head, start = method(head,start,smap)
+ done = true
+ end
+ break
+ else
+ m = m - 1
+ next = next.next
+ end
+ elseif id == kern and next.subtype == 0 then
+ next = next.next
+ -- ignore intercharacter kerning, will go way
+ else
+ -- we can do clever and set n and jump ahead but ... not now
+ break
+ end
+ end
+ end
+ n = 0
+ else
+ n = n + 1
+ end
+ else
+ n = n + 1
+ end
+ else
+ n = 0
+ end
+ else
+ -- n = n + 1 -- if we want single char handling (|-|) then we will use grouping and then we need this
+ end
+ elseif id == kern and start.subtype == 0 then
+ -- ignore intercharacter kerning, will go way
+ else
+ n = 0
+ end
+ start = start.next
+ end
+ return head, done
+end
+
+chars.handle_breakpoints = nodes.install_attribute_handler {
+ name = "breakpoint",
+ namespace = breakpoints,
+ processor = breakpoints.process,
+}
+
+function breakpoints.enable()
+ tasks.enableaction("processors","chars.handle_breakpoints")
+end