font-imp-ligatures.lua /size: 3594 b    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['font-imp-ligatures'] = {
2    version   = 1.001,
3    comment   = "companion to font-ini.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
9local lpegmatch = lpeg.match
10local utfsplit = utf.split
11local settings_to_array = utilities.parsers.settings_to_array
12
13local fonts              = fonts
14local otf                = fonts.handlers.otf
15local registerotffeature = otf.features.register
16local addotffeature      = otf.addfeature
17
18-- This is a quick and dirty hack.
19
20local lookups = { }
21local protect = { }
22local revert  = { }
23local zwjchar = 0x200C
24local zwj     = { zwjchar }
25
26addotffeature {
27    name    = "blockligatures",
28    type    = "chainsubstitution",
29    nocheck = true, -- because there is no 0x200C in the font
30    prepend = true, -- make sure we do it early
31    future  = true, -- avoid nilling due to no steps yet
32    lookups = {
33        {
34            type = "multiple",
35            data = lookups,
36        },
37    },
38    data = {
39        rules = protect,
40    }
41}
42
43addotffeature {
44    name     = "blockligatures",
45    type     = "chainsubstitution",
46    nocheck  = true,  -- because there is no 0x200C in the font
47    append   = true,  -- this is done late
48    overload = false, -- we don't want to overload the previous definition
49    lookups  = {
50        {
51            type = "ligature",
52            data = lookups,
53        },
54    },
55    data = {
56        rules = revert,
57    }
58}
59
60registerotffeature {
61    name        = 'blockligatures',
62    description = 'block certain ligatures',
63}
64
65local splitter = lpeg.splitat(":")
66
67local function blockligatures(str)
68
69    local t = settings_to_array(str)
70
71    for i=1,#t do
72        local ti = t[i]
73        local before, current, after = lpegmatch(splitter,ti)
74        if current and after then -- before is returned when no match
75            -- experimental joke
76            if before then
77                before = utfsplit(before)
78                for i=1,#before do
79                    before[i] = { before[i] }
80                end
81            end
82            if current then
83                current = utfsplit(current)
84            end
85            if after then
86                after = utfsplit(after)
87                for i=1,#after do
88                    after[i] = { after[i] }
89                end
90            end
91        else
92            before  = nil
93            current = utfsplit(ti)
94            after   = nil
95        end
96        if #current > 1 then
97            local one = current[1]
98            local two = current[2]
99            lookups[one] = { one, zwjchar }
100            local one = { one }
101            local two = { two }
102            local new = #protect + 1
103            protect[new] = {
104                before  = before,
105                current = { one, two },
106                after   = after,
107                lookups = { 1, false }, -- not shared !
108            }
109            revert[new] = {
110             -- before = before,
111                current = { one, zwj },
112             -- after   = { two, unpack(after) },
113                after   = { two },
114                lookups = { 1, false }, -- not shared !
115            }
116        end
117    end
118end
119
120-- blockligatures("\0\0")
121
122otf.helpers.blockligatures = blockligatures
123
124-- blockligatures("fi,ff")
125-- blockligatures("fl")
126-- blockligatures("u:fl:age")
127
128if context then
129
130    interfaces.implement {
131        name      = "blockligatures",
132        arguments = "string",
133        actions   = blockligatures,
134    }
135
136end
137