summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/spelling/spelling-stage-2.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/scripts/spelling/spelling-stage-2.lua')
-rwxr-xr-xMaster/texmf-dist/scripts/spelling/spelling-stage-2.lua208
1 files changed, 166 insertions, 42 deletions
diff --git a/Master/texmf-dist/scripts/spelling/spelling-stage-2.lua b/Master/texmf-dist/scripts/spelling/spelling-stage-2.lua
index 5db44d41634..1a397217a16 100755
--- a/Master/texmf-dist/scripts/spelling/spelling-stage-2.lua
+++ b/Master/texmf-dist/scripts/spelling/spelling-stage-2.lua
@@ -21,7 +21,7 @@
--
-- @author Stephan Hennig
-- @copyright 2012, 2013 Stephan Hennig
--- @release version 0.3
+-- @release version 0.4
--
-- @trick Prevent LuaDoc from looking past here for module description.
--[[ Trick LuaDoc into entering 'module' mode without using that command.
@@ -33,20 +33,29 @@ module(...)
local M = {}
--- Import helper module.
-local __recurse = require 'spelling-recurse'
-local __recurse_node_list = __recurse.recurse_node_list
+-- Import external modules.
+local recurse = require('spelling-recurse')
+local unicode = require('unicode')
-- Function short-cuts.
local tabconcat = table.concat
local tabinsert = table.insert
local tabremove = table.remove
-local utf8char = unicode.utf8.char
+
local node_new = node.new
local node_insert_after = node.insert_after
local node_insert_before = node.insert_before
+local recurse_node_list = recurse.recurse_node_list
+
+local Sfind = string.find
+local Sgmatch = string.gmatch
+local Smatch = string.match
+
+local Uchar = unicode.utf8.char
+local Umatch = unicode.utf8.match
+
-- Short-cuts for constants.
local DISC = node.id('disc')
@@ -61,27 +70,17 @@ local PDF_COLORSTACK = node.subtype('pdf_colorstack')
-- Declare local variables to store references to resources that are
-- provided by external code.
--
--- Table of known bad spellings.
-local __is_bad
+-- Table of bad rules.
+local __rules_bad
--
--- Table of known good spellings.
-local __is_good
+-- Table of good rules.
+local __rules_good
--
--- ID of user-defined whatsit nodes.
-local __whatsit_uid
-
-
---- Set module resources.
--- Make various resources, that are provided by external code, available
--- to this module.
+-- ID of user-defined whatsit nodes marking the start of a word.
+local __uid_start_tag
--
--- @param res Ressource table.
-local function set_resources(res)
- __is_bad = res.is_bad
- __is_good = res.is_good
- __whatsit_uid = res.whatsit_uid
-end
-M.set_resources = set_resources
+-- ID of user-defined whatsit nodes marking the end of a word.
+local __uid_end_tag
--- Module options.
@@ -98,18 +97,94 @@ local __opts = {
--- Set colour used for highlighting.
--- Set colourused for highlighting bad spellings in PDF output.
+-- Set colour used for highlighting bad spellings in PDF output. The
+-- argument is checked for a valid PDF colour statement. As an example,
+-- the string `1 0 0 rg` represents a red colour in the RGB colour
+-- space. A similar colour in the CMYK colour space would be
+-- represented by the string '0 1 1 0 k'.
--
--- @param col New colour. This must be a colour statement in PDF format
--- given as string. As an example, the string `1 0 0 rg` represents a
--- red colour in the RGB colour space. A similar colour in the CMYK
--- colour space would be represented by the string '0 1 1 0 k'.
+-- @param col New colour.
local function set_highlight_color(col)
- __opts.hl_color = col
+ -- Extract all colour components.
+ local components = Smatch(col, '^(%S+ %S+ %S+) rg$') or Smatch(col, '^(%S+ %S+ %S+ %S+) k$')
+ local is_valid_arg = components
+ if is_valid_arg then
+ -- Validate colour components.
+ for comp in Sgmatch(components, '%S+') do
+ -- Check number syntax.
+ local is_valid_comp = Sfind(comp, '^%d+%.?%d*$') or Sfind(comp, '^%d*%.?%d+$')
+ if is_valid_comp then
+ -- Check number range.
+ comp = tonumber(comp)
+ is_valid_comp = comp >= 0 and comp <= 1
+ end
+ is_valid_arg = is_valid_arg and is_valid_comp
+ end
+ end
+ if is_valid_arg then
+ __opts.hl_color = col
+ else
+ error('package spelling: Error! Invalid PDF colour statement: ' .. tostring(col))
+ end
end
M.set_highlight_color = set_highlight_color
+--- Highlighting status cache table.
+-- Determining the highlighting status of a string can be an expensive
+-- operation. To reduce average run-time penalty per string,
+-- highlighting status of all strings found in a document is cached in
+-- this table, so that determining the highlighting status of a known
+-- string requires only one table look-up.<br />
+--
+-- This table needs an `__index` meta method calculating the
+-- highlighting status of unknown keys (strings).
+--
+-- @class table
+-- @name __is_highlighting_needed
+local __is_highlighting_needed = {}
+
+
+--- Calculate and cache the highlighting status of a string.
+-- First, surrounding punctuation is stripped from the string argument.
+-- Then, the given raw as well as the stripped string are checked
+-- against all rules. Highlighting of the string is required, if any
+-- bad rule matches, but no good rule matches. That is, good rules take
+-- precedence over bad rules.
+--
+-- @param t Original table.
+-- @param raw Raw string to check.
+-- @return True, if highlighting is required. False, otherwise.
+local function __calc_is_highlighting_needed(t, raw)
+ -- Strip surrounding punctuation from string.
+ local stripped = Umatch(raw, '^%p*(.-)%p*$')
+ -- Check for a bad match.
+ local is_bad = false
+ for _,matches_bad in ipairs(__rules_bad) do
+ is_bad = is_bad or matches_bad(raw, stripped)
+ if is_bad then break end
+ end
+ -- Check for a good match.
+ local is_good = false
+ for _,matches_good in ipairs(__rules_good) do
+ is_good = is_good or matches_good(raw, stripped)
+ if is_good then break end
+ end
+ -- Calculate highlighting status.
+ local status = (is_bad and not is_good) or false
+ -- Store status in cache table.
+ rawset(t, raw, status)
+ -- Return status.
+ return status
+end
+
+
+-- Set-up meta table for highlighting status cache table.
+setmetatable(__is_highlighting_needed, {
+ __index = __calc_is_highlighting_needed,
+})
+
+
--- Convert a Unicode code point to a regular UTF-8 encoded string.
-- This function can be used as an `__index` meta method.
--
@@ -117,7 +192,7 @@ M.set_highlight_color = set_highlight_color
-- @param cp originl key, a Unicode code point
-- @return UTF-8 encoded string corresponding to the Unicode code point.
local function __meta_cp2utf8(t, cp)
- return utf8char(cp)
+ return Uchar(cp)
end
@@ -146,8 +221,6 @@ local __codepoint_map = {
[0x0153] = 'oe',-- LATIN SMALL LIGATURE OE
[0x017f] = 's',-- LATIN SMALL LETTER LONG S
- [0x1e9e] = 'SS',-- LATIN CAPITAL LETTER SHARP S
-
[0xfb00] = 'ff',-- LATIN SMALL LIGATURE FF
[0xfb01] = 'fi',-- LATIN SMALL LIGATURE FI
[0xfb02] = 'fl',-- LATIN SMALL LIGATURE FL
@@ -250,7 +323,7 @@ local function __tag_word(word)
local start_tag = node_new(WHATSIT, USER_DEFINED)
-- Mark whatsit node with module ID, so that we can recognize it
-- later.
- start_tag.user_id = __whatsit_uid
+ start_tag.user_id = __uid_start_tag
-- Value is an empty string.
start_tag.type = 115
start_tag.value = ''
@@ -261,7 +334,7 @@ local function __tag_word(word)
local end_tag = node_new(WHATSIT, USER_DEFINED)
-- Mark whatsit node with module ID, so that we can recognize it
-- later.
- end_tag.user_id = __whatsit_uid
+ end_tag.user_id = __uid_end_tag
-- Value of end tag is an index (a number).
end_tag.type = 115
end_tag.value = word
@@ -283,6 +356,29 @@ local function __highlight_by_color()
local pop = node_new(WHATSIT, PDF_COLORSTACK)
push.stack = 0
pop.stack = 0
+ push.command = 1
+ pop.command = 2
+ push.data = __opts.hl_color
+ node_insert_before(__curr_word_start_head, __curr_word_start, push)
+ node_insert_after(__curr_word_end_head, __curr_word_end, pop)
+ end
+end
+
+
+--- Highlight bad spelling by colour (using node field `cmd`).
+-- Insert colour whatsits before and after the first and last nodes
+-- known to belong to the current word.
+-- @see function __highlight_by_color
+local function __highlight_by_color_cmd()
+ -- Check, if start node of current word is a head node. Inserting
+ -- before head nodes needs special attention. This is not yet
+ -- implemented.
+ if (__curr_word_start ~= __curr_word_start_head) then
+ -- Create pdf_colorstack whatsit nodes.
+ local push = node_new(WHATSIT, PDF_COLORSTACK)
+ local pop = node_new(WHATSIT, PDF_COLORSTACK)
+ push.stack = 0
+ pop.stack = 0
push.cmd = 1
pop.cmd = 2
push.data = __opts.hl_color
@@ -332,13 +428,10 @@ local function __finish_current_word()
if start_prev and end_next
and (start_prev.id == WHATSIT)
and (start_prev.subtype == USER_DEFINED)
- and (start_prev.user_id == __whatsit_uid)
- and (start_prev.type == 115)
- and (start_prev.value == '')
+ and (start_prev.user_id == __uid_start_tag)
and (end_next.id == WHATSIT)
and (end_next.subtype == USER_DEFINED)
- and (end_next.user_id == __whatsit_uid)
- and (end_next.type == 115)
+ and (end_next.user_id == __uid_end_tag)
and (end_next.value == word) then
__curr_word = nil
__curr_word_start_head = nil
@@ -351,8 +444,8 @@ local function __finish_current_word()
if __is_active_tagging then
__tag_word(word)
end
- -- Test for bad spelling.
- if __is_active_highlighting and __is_bad[word] and not __is_good[word] then
+ -- Highlighting needed?
+ if __is_highlighting_needed[word] and __is_active_highlighting then
__highlight_bad_word()
end
__curr_word = nil
@@ -475,7 +568,7 @@ local function __process_node_list(head)
__curr_word_start = nil
__curr_word_end_head = nil
__curr_word_end = nil
- __recurse_node_list(head, __cb_tag_words)
+ recurse_node_list(head, __cb_tag_words)
-- Clean-up left-over word and/or paragraph.
__finish_current_paragraph()
end
@@ -526,9 +619,40 @@ end
M.disable_word_highlighting = disable_word_highlighting
+--- Try to maintain compatibility with older LuaTeX versions.
+-- Between LuaTeX 0.70.2 and 0.76.0 node field `cmd` of `whatsits` nodes
+-- of subtype `pdf_colorstack` has been renamed to `command`. This
+-- function checks which node field is the correct one and activates a
+-- fall-back function in case. Due to a bug in LuaTeX 0.76.0 (shipped
+-- with TL2013) function `node.has_field()` doesn't return correct
+-- results. It is therefore tested if an assignment to field `command`
+-- raises an error or not.
+local function __maintain_compatibility()
+ -- Create pdf_colorstack whatsit node.
+ local n = node.new(WHATSIT, PDF_COLORSTACK)
+ -- Function that assigns a value to node field 'command'.
+ local f = function()
+ n.command = 1
+ end
+ -- If the assignment is not successful, fall-back to node field 'cmd'.
+ if not pcall(f) then
+ __highlight_by_color = __highlight_by_color_cmd
+ end
+ -- Delete test node.
+ node.free(n)
+end
+
+
--- Module initialisation.
--
local function __init()
+ -- Try to maintain compatibility with older LuaTeX versions.
+ __maintain_compatibility()
+ -- Get local references to package ressources.
+ __rules_bad = PKG_spelling.res.rules_bad
+ __rules_good = PKG_spelling.res.rules_good
+ __uid_start_tag = PKG_spelling.res.whatsit_ids.start_tag
+ __uid_end_tag = PKG_spelling.res.whatsit_ids.end_tag
-- Create empty paragraph management stack.
__is_vlist_paragraph = {}
-- Remember tagging status.