Below is a solution to keeping a Lua version of TOC. I use inspect.lua
to show the structure of toc
variable. Here is an excerpt of it, you can see the full string in the log file. Each entity in the tree is associated with a label
field so that one can create links to it or access its page number.
I have a rough idea of how to recreate the TOC layout, but since you might be more interested in the Lua TOC part, I am not diving into that now. If you need help, please let me know.
{ {
arga = "",
argb = "Part 1",
content = { {
arga = "",
argb = "Chapter 1",
content = { {
arga = "",
argb = "Section I",
content = {},
index = 1,
label = "5371A59F385D7156E74C245C6A1225D3DAC02A8ED95DFBEF",
level = 3
}, {
arga = "",
argb = "Section II",
content = {},
index = 2,
label = "7F84FBD64E18D211C25EE7F86B00322F8602CE9093259EDD",
level = 3
}, {
arga = "",
argb = "Section III",
content = {},
index = 3,
label = "B834D3A96C2E4B71FE95D553AD63F5270272127F5892CADF",
level = 3
}, {...
\documentclass{scrbook}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{etoolbox}
\usepackage{blindtext}
\usepackage{luacode}
\usepackage{xparse}
\begin{luacode*}
--https://github.com/kikito/inspect.lua
inspect = require "inspect"
toc = {}
most_recent_hash = ""
function hash_and_store(parts)
local str = ""
for _, stuff in pairs(parts) do
str = str .. tostring(stuff)
end
local bin_hash = sha2.digest256(str)
local hex_hash = ""
for i=1,#bin_hash do
hex_hash = hex_hash .. string.format("%02X", bin_hash:byte(i))
end
most_recent_hash = hex_hash:sub(1, 48)
end
function get_toc_item(tbl)
local keys = {"level", "index", "label", "arga", "argb", "content"}
local default_vals = {0, 0, "", "", "", {}}
local item = {}
local temp = nil
for ind, key in pairs(keys) do
temp = tbl[key]
if temp == nil then
rawset(item, key, default_vals[ind])
else
rawset(item, key, temp)
end
end
return item
end
function insert_to_toc(level, arga, argb)
local search_level = 1
local tbl = toc
local hash_path = {}
while search_level < level do
table.insert(hash_path, #tbl)
if #tbl == 0 then
local item = get_toc_item{level=search_level, index=0}
table.insert(tbl, item)
tbl = item.content
else
tbl = tbl[#tbl].content
end
search_level = search_level + 1
end
table.insert(hash_path, argb)
hash_and_store(hash_path)
local item_index = #tbl + 1
local item = get_toc_item{level=level, index=item_index, label=most_recent_hash,arga=arga,argb=argb}
table.insert(tbl, item)
end
\end{luacode*}
% redefine commands to link Lua and TeX
\ExplSyntaxOn
\tl_new:N \l_doc_tmpa_tl
\cs_set:Npn \doc_patch_command:nn #1#2 {
\cs_gset_eq:cc {__doc_old_#1} {#1}
\exp_args:Nc \RenewDocumentCommand{#1}{som}{
\IfBooleanTF{##1}{
% starred commands are not numbered
\IfValueTF{##2}{
\use:c {__doc_old_#1} * [##2] {##3}
}{
\use:c {__doc_old_#1} * {##3}
}
}{
\IfValueTF{##2}{
\directlua{
insert_to_toc(#2, "\luaescapestring{##2}", "\luaescapestring{##3}")
}
\use:c {__doc_old_#1} [##2] {##3}
\label{\directlua{tex.print(most_recent_hash)}}
}{
\directlua{
insert_to_toc(#2, "", "\luaescapestring{##3}")
}
\use:c {__doc_old_#1} {##3}
\directlua{texio.write(most_recent_hash)}
\label{\directlua{tex.print(most_recent_hash)}}
}
}
}
}
\AtBeginDocument{
\doc_patch_command:nn {part}{1}
\doc_patch_command:nn {chapter}{2}
\doc_patch_command:nn {section}{3}
}
\ExplSyntaxOff
\begin{document}
\tableofcontents
% define some commands for creating a dummy document
\ExplSyntaxOn
\int_new:N \g_doc_part_int
\int_new:N \g_doc_chapter_int
\int_new:N \g_doc_section_int
\sys_gset_rand_seed:n {1}
\int_gset:Nn \g_doc_part_int {1}
\int_gset:Nn \g_doc_chapter_int {1}
\int_gset:Nn \g_doc_section_int {1}
\cs_set:Nn \doc_rand_text: {
\tl_set:Nx \l_tmpa_tl {\exp_not:N\Blindtext[\int_rand:nn {1}{12}]}
\tl_use:N \l_tmpa_tl
}
\newcommand{\dummypart}{
\exp_args:Nx \part{Part~\int_use:N \g_doc_part_int}
\int_gincr:N \g_doc_part_int
}
\newcommand{\dummychapter}{
\exp_args:Nx \chapter{Chapter~\int_use:N \g_doc_chapter_int}
\int_gincr:N \g_doc_chapter_int
}
\newcommand{\dummysection}{
\exp_args:Nx \section{Section~\int_to_Roman:n {\g_doc_section_int}}
\int_gincr:N \g_doc_section_int
}
\int_step_inline:nn {3} {
\dummypart
\int_set:Nn \l_tmpa_int {\int_rand:nn {2}{4}}
\int_step_inline:nn {\l_tmpa_int} {
\dummychapter
\int_set:Nn \l_tmpb_int {\int_rand:nn {5}{10}}
\int_step_inline:nn {\l_tmpb_int} {
\dummysection
\doc_rand_text:
}
}
}
\ExplSyntaxOff
\directlua{
texio.write(inspect(toc))
}
\end{document}
\l@chapter
,\l@section
etc to add to a Lua table as well as their existing use of writing to the toc file.\part
when you say that section numbers are unique to a part (i.e., no part can have the same section numbers within it)? What are the styles of a\section
number with and without a preceding\chapter
? Etc.