重新审视:段落最后一行的最小长度

重新审视:段落最后一行的最小长度

这个问题“以前曾被问过”并得到回答:

段落最后一行的最小长度

确保最后一行的长度最短

但是我不希望 lualatex(或任何 tex)自动拉伸行或重新拆分段落。我想要做的是输入一条消息(到终端和日志文件),以引导编辑者的注意力。伪代码:

\HookShortLastLine{\typeout{Short last line in paragraph, page \thepage.}}

我目前尝试过的方法:手动破解impnattypo 软件包中的代码。由于我不太了解 Lua,所以我的结果太令人尴尬了,无法在这里展示。

理由:正如上面链接页面的评论中已经指出的那样,自动的最后换行可能会产生奇怪的结果。

我从事原创小说创作,文本很容易编辑以改善其外观。因此,我不需要 TeX 来更改我自己可以更改的内容。但记录下来确实有帮助,这样我就知道该去哪里找。

编辑:这是 lua 代码的简化部分,来自impnattypo

local glue_id  = node.id 'glue'
function lastline_length(head)
  while head do
    local _w,_h,_d = node.dimensions(head)
    if head.id == glue_id and head.subtype ~= 15 and (_w < 2 * tex.parindent)
    then
-- I know that the following commented-out routine will work,
-- but it is not what I need:
--      local p = node.new('penalty')
--      p.penalty = 10000
--      node.insert_after(head,head.prev,p}
-- The following line is my own code, which does not work:
      tex.print('\typeout{Short last line of paragraph, page \thepage.}')
    end
    head = head.next
  end
  return true
end
luatexbase.add_to_callback('pre_linebreak_filter',lastline_length,'lastline')

答案1

parfillskip由于您实际上并不想修改 TeX 做出的任何换行决定,而只是想更好地观察最后一行较短的段落,因此您可以在回调中查询宽度post_linebreak_filter

下面测试parfillskip其宽度是否至少为半行(即,段落的最后一行短于半行),如果是,它将用红色矩形填充段落末尾,并将“坏”段落末尾的页码和坐标写入名为的文件中shortlines.txt(如果愿意,您可以写入 .log 文件或终端)。

\documentclass{article}
\directlua{
 local file = io.open("shortlines.txt", "w")
 local function write_shortlines_data()
    file:write("Short line detected on page " .. 
                        tex.count['c@page'] .. 
                        (". Coordinates: (\csstring\%i, \csstring\%i)"):format(pdf.getpos()) 
                        .. "\string\n")
 end
 local function lastline_length(head,c)
    for line in node.traverse(head) do
        for n in node.traverse(line.list) do
            if n.id == node.id('glue') and n.subtype == 15 then
                local glue_width = node.effective_glue(n,line,true)
                if glue_width >= tex.hsize / 2 then --[[you can choose a different length...]]
                    local normalized_glue_width = glue_width / 65781
                    local colorbar = node.new("whatsit","pdf_literal")
                    colorbar.data = "q 1 0 0 rg 2 0 " .. 
                        normalized_glue_width .. " 5 re f Q"
                    line.head = node.insert_before(line.list,n,colorbar)
                    local shortlines_data = node.new("whatsit","late_lua")
                    shortlines_data.data = write_shortlines_data
                    line.head = node.insert_before(line.list, colorbar, shortlines_data)
                end
                return head
            end
        end
    end
 end
 luatexbase.add_to_callback('post_linebreak_filter',lastline_length,'lastline')
}
\begin{document}
Test test test test test test Test test test test test test 
Test test test test test test Test test test test test test 

Test test test test test test Test test test test test test 
Test test test test test test Test test test test test test 
Test test test test test test Test test test test test test 
Test test test test test test Test test test test test test 

\newpage
 Test test test test
\end{document}

这是第一页

在此处输入图片描述

该文件shortlines.txt包含

Short line detected on page 1. Coordinates: (17686202, 45729504)
Short line detected on page 2. Coordinates: (15601501, 46515936)

在这个例子中,坐标实际上并没有添加任何内容,但在阅读了你的回答后,我想展示一种获取段落末尾坐标的方法。

如果您更喜欢使用段落末尾的 x 坐标而不是查询parfillskip来描绘一个糟糕的段落,您可以进行write_shortlines_data相应的修改(名称可能没有意义......),并可能从中删除多余的内容lastline_length

例如

\documentclass{article}
\directlua{
 local file = io.open("shortlines.txt", "w")
 local function write_shortlines_data()
    local x,_ = pdf.getpos()
    if x < 17700000 then --[[ choose a different number if you want ]]
        file:write("Short line detected on page " .. 
                            tex.count['c@page'] .. 
                            (". Coordinates: (\csstring\%i, \csstring\%i)"):format(pdf.getpos()) 
                            .. "\string\n")
    end
 end
 local function lastline_length(head,c)
    for line in node.traverse(head) do
        for n in node.traverse(line.list) do
            if n.id == node.id('glue') and n.subtype == 15 then
                local shortlines_data = node.new("whatsit","late_lua")
                shortlines_data.data = write_shortlines_data
                line.head = node.insert_before(line.list, n, shortlines_data)
                return head
            end
        end
    end
 end
 luatexbase.add_to_callback('post_linebreak_filter',lastline_length,'lastline')
}
\begin{document}
Test test test test test test Test test test test test test 
Test test test test test test Test test test test test test 

Test test test test test test Test test test test test test 
Test test test test test test Test test test test test test 
Test test test test test test Test test test test test test 
Test test test test test test Test test test test test test 

\newpage
 Test test test test
\end{document}

这种方法产生与此示例相同的文本文件,但我没有添加红色规则,我将它留给你。

答案2

EDIT2:当我问这个问题时,我不知道包lua-typo,它似乎做了我最初想做的事情:突出显示或标记问题(通过重写自己修复它们)而不是自动更正。

编辑:我几乎放弃了希望,但后来 Udi(参见接受的答案)来拯救我了。对该代码的改进:按照编写方式(除非修改),它会标记短行,但也会标记故意空白的行(我将它们用于布局间距)。此修改不会标记空白行。这些数字特定于我的文本宽度,因此请根据需要更改它们。它们以 TeX 为单位sp。1000 似乎是吸收某种微小数学错误所必需的。

if glue_width >= tex.hsize - 2300000
and glue_width < tex.hsize - 1000

我将其作为“答案”写出来,以便其他发现此问题的人受益。

LaTeX(和 LualaTeX 具有\savepos相关命令,用于存储写入的 x 和 y 页面坐标。这些数字可以稍后检索。但是:显然保存位置的请求不会立即存储坐标。因为 TeX 实际上并不知道它们。这些数字直到页面发货时才最终确定。唉,似乎不可能按顺序保存每个段落的信息,然后一起检索它们(可能用逗号分隔),因为只有最后一次保存请求的信息才会被接受。

我可以理解为什么 y 坐标直到发货时才可用,这是由于垂直粘连。但在单列页面的情况下,我希望 x 坐标在每个段落的末尾都可用,甚至在发货之前。

相关内容