summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/spelling/spelling-stage-3.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/spelling/spelling-stage-3.lua')
-rw-r--r--macros/luatex/generic/spelling/spelling-stage-3.lua301
1 files changed, 301 insertions, 0 deletions
diff --git a/macros/luatex/generic/spelling/spelling-stage-3.lua b/macros/luatex/generic/spelling/spelling-stage-3.lua
new file mode 100644
index 0000000000..613e6af995
--- /dev/null
+++ b/macros/luatex/generic/spelling/spelling-stage-3.lua
@@ -0,0 +1,301 @@
+--- spelling-stage-3.lua
+--- Copyright 2012, 2013 Stephan Hennig
+--
+-- This work may be distributed and/or modified under the conditions of
+-- the LaTeX Project Public License, either version 1.3 of this license
+-- or (at your option) any later version. The latest version of this
+-- license is in http://www.latex-project.org/lppl.txt
+-- and version 1.3 or later is part of all distributions of LaTeX
+-- version 2005/12/01 or later.
+--
+-- See file README for more information.
+--
+
+
+--- Store the text of a LuaTeX document in a text document data
+--- structure.
+-- This module provides means to extract text from a LuaTeX document and
+-- to store it in a text document data structure.
+--
+-- In the text document, words are stored as UTF-8 encoded strings. A
+-- mapping mechanism is provided by which, during word string
+-- recognition, individual code-points, e.g., of glyph nodes, can be
+-- translated to arbitrary UTF-8 strings, e.g., ligatures to single
+-- letters.
+--
+-- @author Stephan Hennig
+-- @copyright 2012, 2013 Stephan Hennig
+-- @release version 0.41
+--
+-- @trick Prevent LuaDoc from looking past here for module description.
+--[[ Trick LuaDoc into entering 'module' mode without using that command.
+module(...)
+--]]
+
+
+-- Module table.
+local M = {}
+
+
+-- Import external modules.
+local recurse = require('spelling-recurse')
+
+
+-- Function short-cuts.
+local recurse_node_list = recurse.recurse_node_list
+
+local tabinsert = table.insert
+local tabremove = table.remove
+
+
+-- Short-cuts for constants.
+local WHATSIT = node.id('whatsit')
+local LOCAL_PAR = node.subtype('local_par')
+local USER_DEFINED = node.subtype('user_defined')
+
+
+-- Declare local variables to store references to resources that are
+-- provided by external code.
+--
+-- Text document data structure.
+local __text_document
+--
+-- ID of user-defined whatsit nodes marking the start of a word.
+local __uid_start_tag
+--
+-- ID of user-defined whatsit nodes marking the end of a word.
+local __uid_end_tag
+
+
+--- Module options.
+-- This table contains all module options. User functions to set
+-- options are provided.
+--
+-- @class table
+-- @name __opts
+-- @field table_par When processing a table, when should paragraphs be
+-- inserted into the text document?<br />
+--
+-- <ul>
+-- <li> 0 - Don't touch tables in any way.</li>
+-- <li> 1 - Insert paragraphs before and after hlists of type
+-- <i>alignment column or row</i>, i.e., before and after
+-- every table row.</li>
+-- <li> 2 - Insert paragraphs before and after hlists of type
+-- <i>alignment cell</i>, i.e., before and after every table
+-- cell.</li>
+-- </ul>
+local __opts = {
+ table_par,
+}
+
+
+--- Set table behaviour.
+-- Determine when paragraphs are inserted within tables.
+--
+-- @param value New value.
+local function set_table_paragraphs(value)
+ __opts.table_par = value
+end
+M.set_table_paragraphs = set_table_paragraphs
+
+
+--- Data structure that stores the word strings found in a node list.
+--
+-- @class table
+-- @name __curr_paragraph
+local __curr_paragraph
+
+
+--- Act upon detection of end of current word string.
+-- If the current word contains visible characters, store the current
+-- word in the current paragraph.
+--
+-- @param n String tag node.
+local function __finish_current_word(n)
+ -- Provide new empty paragraph, if necessary.
+ if not __curr_paragraph then
+ __curr_paragraph = {}
+ end
+ -- Append current string to current paragraph.
+ tabinsert(__curr_paragraph, n.value)
+end
+
+
+--- Act upon detection of end of current paragraph.
+-- If the current paragraph contains words, store the current paragraph
+-- in the text document.
+local function __finish_current_paragraph()
+ -- Finish a paragraph?
+ if __curr_paragraph then
+ -- Append current paragraph to document structure.
+ tabinsert(__text_document, __curr_paragraph)
+ __curr_paragraph = nil
+ end
+end
+
+
+--- Paragraph management stack.
+-- Stack of boolean flags, that are used for logging the occurence of a
+-- new paragraph within nested vlists.
+local __is_vlist_paragraph
+
+
+--- Paragraph management.
+-- This function puts a new boolean flag onto a stack that is used to
+-- log the occurence of a new paragraph, while recursing into the coming
+-- vlist. After finishing recursing into the vlist, the flag needs to
+-- be removed from the stack. Depending on the flag, the then current
+-- paragraph can be finished.
+local function __vlist_pre_recurse()
+ tabinsert(__is_vlist_paragraph, false)
+end
+
+
+--- Paragraph management.
+-- Remove flag from stack after recursing into a vlist. If necessary,
+-- finish the current paragraph.
+local function __vlist_post_recurse()
+ local p = tabremove(__is_vlist_paragraph)
+ if p then
+ __finish_current_paragraph()
+ end
+end
+
+
+--- Handle tables lines and cells.
+-- Start a new paragraph before and after an hlist of subtype `alignment
+-- column or row` or `alignment cell`, depending on option `table_par`.
+--
+-- @param n hlist node.
+local function __handle_table(n)
+ local subtype = n.subtype
+ local table_par = __opts.table_par
+ if (subtype == 4) and (table_par == 1) then
+ __finish_current_paragraph()
+ elseif (subtype == 5) and (table_par == 2) then
+ __finish_current_paragraph()
+ end
+end
+
+
+--- Find paragraphs and strings.
+-- While scanning a node list, this call-back function finds nodes
+-- representing the start of a paragraph (local_par whatsit nodes) and
+-- string tags (user_defined whatsit nodes).
+--
+-- @param head Head node of current branch.
+-- @param n The current node.
+local function __visit_node(head, n)
+ local nid = n.id
+ -- Test for node containing a word string.
+ if nid == WHATSIT then
+ -- Test for word string tag.
+ if (n.subtype == USER_DEFINED) and (n.user_id == __uid_end_tag) then
+ __finish_current_word(n)
+ -- Test for paragraph start.
+ elseif n.subtype == LOCAL_PAR then
+ __finish_current_paragraph()
+ __is_vlist_paragraph[#__is_vlist_paragraph] = true
+ end
+ end
+end
+
+
+--- Table of call-back functions for node list recursion: store the
+--- word strings found in a node list.
+-- The call-back functions in this table identify chains of nodes
+-- representing word strings in a node list and stores the strings in
+-- the text document. A new paragraph is started at local_par whatsit
+-- nodes and after finishing a vlist containing a local_par whatsit
+-- node. Nodes of type `hlist` are recursed into as if they were
+-- non-existent. As an example, the LaTeX input `a\mbox{a b}b` is
+-- recognized as two strings `aa` and `bb`.
+--
+-- @class table
+-- @name __cb_store_words
+-- @field vlist_pre_recurse Paragraph management.
+-- @field vlist_post_recurse Paragraph management.
+-- @field hlist_pre_recurse Table management.
+-- @field hlist_post_recurse Table management.
+-- @field visit_node Find nodes representing paragraphs and words.
+local __cb_store_words = {
+
+ vlist_pre_recurse = __vlist_pre_recurse,
+ vlist_post_recurse = __vlist_post_recurse,
+ hlist_pre_recurse = __handle_table,
+ hlist_post_recurse = __handle_table,
+ visit_node = __visit_node,
+
+}
+
+
+--- Process node list according to this stage.
+-- This function recurses into the given node list, finds strings in
+-- tags and stores them in the text document.
+--
+-- @param head Node list.
+local function __process_node_list(head)
+ recurse_node_list(head, __cb_store_words)
+ -- Clean-up left-over word and/or paragraph.
+ __finish_current_paragraph()
+end
+
+
+-- Call-back status.
+local __is_active_storage
+
+
+--- Call-back function that processes the node list.
+-- <i>This function is not made available in the module table, but in
+-- the global package table!</i>
+--
+-- @param head Node list.
+local function cb_AtBeginShipout(box)
+ if __is_active_storage then
+ __process_node_list(tex.box[box])
+ end
+end
+
+
+--- Start storing text.
+-- After calling this function, text is stored in the text document.
+local function enable_text_storage()
+ __is_active_storage = true
+end
+M.enable_text_storage = enable_text_storage
+
+
+--- Stop storing text.
+-- After calling this function, no more text is stored in the text
+-- document.
+local function disable_text_storage()
+ __is_active_storage = false
+end
+M.disable_text_storage = disable_text_storage
+
+
+--- Module initialisation.
+--
+local function __init()
+ -- Get local references to package ressources.
+ __text_document = PKG_spelling.res.text_document
+ __uid_start_tag = PKG_spelling.res.whatsit_ids.start_tag
+ __uid_end_tag = PKG_spelling.res.whatsit_ids.end_tag
+ -- Make \AtBeginShipout function available in package table.
+ PKG_spelling.cb_AtBeginShipout = cb_AtBeginShipout
+ -- Create empty paragraph management stack.
+ __is_vlist_paragraph = {}
+ -- Remember call-back status.
+ __is_active_storage = false
+ -- Set default table paragraph behaviour.
+ set_table_paragraphs(0)
+end
+
+
+-- Initialize module.
+__init()
+
+
+-- Return module table.
+return M