--
-- This is file `persian-tex-ligs.lua',
-- generated with the docstrip utility.
--
-- The original source files were:
--
-- xepersian.dtx  (with options: `persian-tex-ligs.lua')
-- 
--   __________________________________________________
--   Vafa Khalighi
-- 
--   Copyright (c) 2008--2025  Vafa Khalighi
--   Copyright (c) 2018--2020 bidi-tex GitHub Organization
-- 
--   It may be distributed and/or modified under the LaTeX Project Public License,
--   version 1.3c or higher (your choice). The latest version of
--   this license is at: http://www.latex-project.org/lppl.txt
-- 
--   This work is “author-maintained” (as per LPPL maintenance status)
--   by Vafa Khalighi.
-- 
-- 
local otf = fonts.handlers.otf
local registerotffeature = otf.features.register
local addotffeature = otf.addfeature

local persiantexlig = {
  {
    type = "substitution",
    order = {"persiantexlig"},
    prepend = true,
    data = {
      [0x0030] = 0x06F0,
      [0x0031] = 0x06F1,
      [0x0032] = 0x06F2,
      [0x0033] = 0x06F3,
      [0x0034] = 0x06F4,
      [0x0035] = 0x06F5,
      [0x0036] = 0x06F6,
      [0x0037] = 0x06F7,
      [0x0038] = 0x06F8,
      [0x0039] = 0x06F9,
      [0x002C] = 0x060C, -- comma ­> arabic comma
      [0x003F] = 0x061F, -- question mark -> arabic qm
      [0x003B] = 0x061B, -- semicolon -> arabic semicolon
      [0x0027] = 0x2019, -- ' -> right single quote
      [0x0022] = 0x201D, -- " -> right double quote
      [0x0060] = 0x2018 -- ` -> left single quote
  }
  },
  {
    type = "ligature",
    order = {"persiantexlig"},
    prepend = true,
    data = {
      -- ligatures from Knuth's original CMR fonts
      [0x2013] = {0x002D, 0x002D}, -- -- -> en dash
      [0x2014] = {0x002D, 0x002D, 0x002D}, -- --- -> em dash
      [0x201D] = {0x0027, 0x0027}, -- '' -> right double quote
      [0x201C] = {0x0060, 0x0060}, -- `` -> left double quote
      [0x00A1] = {0x0021, 0x0060}, -- !` -> inverted exclam
      [0x00BF] = {0x003F, 0x0060}, -- ?` -> inverted question
      -- additions supported in T1 encoding
      [0x201E] = {0x002C, 0x002C}, -- ,, -> DOUBLE LOW-9 QUOTATION MARK
      [0x00AB] = {0x003C, 0x003C}, -- << -> LEFT POINTING GUILLEMET
      [0x00BB] = {0x003E, 0x003E} -- >> -> RIGHT POINTING GUILLEMET
  }
  }
}

local persiantexlignonum = {
  {
    type = "substitution",
    order = {"persiantexlignonum"},
    prepend = true,
    data = {
      [0x002C] = 0x060C, -- comma ­> arabic comma
      [0x003F] = 0x061F, -- question mark -> arabic qm
      [0x003B] = 0x061B, -- semicolon -> arabic semicolon
      [0x0027] = 0x2019, -- ' -> right single quote
      [0x0022] = 0x201D, -- " -> right double quote
      [0x0060] = 0x2018 -- ` -> left single quote
  }
  },
  {
    type = "ligature",
    order = {"persiantexlignonum"},
    prepend = true,
    data = {
      -- ligatures from Knuth's original CMR fonts
      [0x2013] = {0x002D, 0x002D}, -- -- -> en dash
      [0x2014] = {0x002D, 0x002D, 0x002D}, -- --- -> em dash
      [0x201D] = {0x0027, 0x0027}, -- '' -> right double quote
      [0x201C] = {0x0060, 0x0060}, -- `` -> left double quote
      [0x00A1] = {0x0021, 0x0060}, -- !` -> inverted exclam
      [0x00BF] = {0x003F, 0x0060}, -- ?` -> inverted question
      -- additions supported in T1 encoding
      [0x201E] = {0x002C, 0x002C}, -- ,, -> DOUBLE LOW-9 QUOTATION MARK
      [0x00AB] = {0x003C, 0x003C}, -- << -> LEFT POINTING GUILLEMET
      [0x00BB] = {0x003E, 0x003E} -- >> -> RIGHT POINTING GUILLEMET
  }
  }
}

addotffeature("persiantexlignonum", persiantexlignonum)
addotffeature("persiantexlig", persiantexlig)

registerotffeature {name = "persiantexlig", description = "Persian TeX ligatures"}
registerotffeature {name = "persiantexlignonum", description = "Persian TeX ligatures without numbers"}

-- We implement persiantexlig and persiantexlignonum for HarfBuzz too
local direct = node.direct
local otfregister = fonts.constructors.features.otf.register

local getdisc = direct.getdisc
local getnext = direct.getnext
local is_char = direct.is_char
local setchar = direct.setchar

local persiandigits = {
  [0x0030] = 0x06F0,
  [0x0031] = 0x06F1,
  [0x0032] = 0x06F2,
  [0x0033] = 0x06F3,
  [0x0034] = 0x06F4,
  [0x0035] = 0x06F5,
  [0x0036] = 0x06F6,
  [0x0037] = 0x06F7,
  [0x0038] = 0x06F8,
  [0x0039] = 0x06F9
}

local persianpuncts = {
  [0x002C] = 0x060C, -- comma ­> arabic comma
  [0x003F] = 0x061F, -- question mark -> arabic qm
  [0x003B] = 0x061B, -- semicolon -> arabic semicolon
  [0x0027] = 0x2019, -- ' -> right single quote
  [0x0022] = 0x201D, -- " -> right double quote
  [0x0060] = 0x2018 -- ` -> left single quote
}

local persiantexlig = {
  [0x002D] = {[0x002D] = {char = 0x2013}}, -- -- -> en dash
  [0x2013] = {[0x002D] = {char = 0x2014}}, -- --- -> em dash
  [0x0027] = {[0x0027] = {char = 0x201D}}, -- '' -> right double quote
  [0x0060] = {[0x0060] = {char = 0x201C}}, -- `` -> left double quote
  [0x0021] = {[0x0060] = {char = 0x00A1}}, -- !` -> inverted exclam
  [0x003F] = {[0x0060] = {char = 0x00BF}}, -- ?` -> inverted question
  -- additions supported in T1 encoding
  [0x002C] = {[0x002C] = {char = 0x201E}}, -- ,, -> DOUBLE LOW-9 QUOTATION MARK
  [0x003C] = {[0x003C] = {char = 0x00AB}}, -- << -> LEFT POINTING GUILLEMET
  [0x003E] = {[0x003E] = {char = 0x00BB}} -- >> -> RIGHT POINTING GUILLEMET
}

local function persiantexligprocessor(head, font)
  local n = head
  while n do
    local c, id = is_char(n, font)
    local persiannum = persiandigits[c]
    local persianpunct = persianpuncts[c]
    if persiannum then
      setchar(n, persiannum)
    elseif persianpunct then
      setchar(n, persianpunct)
    elseif id == disc_t then
      local pre, post, replace = getdisc(n)
      persiantexligprocessor(pre, font)
      persiantexligprocessor(post, font)
      persiantexligprocessor(replace, font)
    end
    n = getnext(n)
  end
end

otfregister {
  name = 'persiantexlig',
  description = 'Persian TeX ligatures',
  default = false,
  manipulators = {
    plug = function(tfmdata, _, value)
      local characters = tfmdata.characters
      for codepoint, ligatures in next, persiantexlig do
        local char = characters[codepoint]
        if char then
          char.ligatures = ligatures
        end
      end
    end,
  },
  processors = {
    position=1,
    plug = persiantexligprocessor,
  },
}

local function persiantexlignonumprocessor(head, font)
  local n = head
  while n do
    local c, id = is_char(n, font)
    local persianpunct = persianpuncts[c]
    if persianpunct then
      setchar(n, persianpunct)
    elseif id == disc_t then
      local pre, post, replace = getdisc(n)
      persiantexlignonumprocessor(pre, font)
      persiantexlignonumprocessor(post, font)
      persiantexlignonumprocessor(replace, font)
    end
    n = getnext(n)
  end
end

otfregister {
  name = 'persiantexlignonum',
  description = 'Persian TeX ligatures without numbers',
  default = false,
  manipulators = {
    plug = function(tfmdata, _, value)
      local characters = tfmdata.characters
      for codepoint, ligatures in next, persiantexlig do
        local char = characters[codepoint]
        if char then
          char.ligatures = ligatures
        end
      end
    end,
  },
  processors = {
    position=1,
    plug = persiantexlignonumprocessor,
  },
}
--
-- End of file `persian-tex-ligs.lua'.
