3

Let's say I have a document, and I want to colorize the first word of each line. That is to say, when a word is the first word of a line, it should be replaced by \textcolor{red}{[the word]}.

This question had answered this in part, using discretionary ligatures, but this does not work when you begin a paragraph with a word, as well as the spacing problem.

I would think that a Lua(La)TeX solution is possible. Is there a way to go through each (typeset) line, get the first word of each (typeset) line and then replace that word with a colorized version using LuaTeX? That way, one doesn't have to manually color words, whether or not they occur at a spot for a discretionary ligature.

2
  • How should this work with hyphenation? Should the first full word be highlighted, everything until the first space or something else? Apr 18, 2020 at 11:17
  • also what do you want to do if the line starts with punctuation like (a phrase in parens) make ( red or a red or (a red? Apr 18, 2020 at 11:28

1 Answer 1

11

The question doesn't really give enough details to determine the correct behavior in many cases, so this is a rather simple approach:

Only consider lines which go through the line breaking routines (So horizontal boxes are ignored) and then color all glyphs until a glue node is found. In most cases this seems to do "the right thing":

\documentclass{article}
\usepackage{blindtext,luacolor}
\newattribute\ColFirstAttr
\directlua{
  local ourattr = \number\allocationnumber;
  local glyph_id = node.id'glyph'
  local glue_id = node.id'glue'
  require'pre_append_to_vlist_filter'
  local luacolorattr = oberdiek.luacolor.getattribute()
  luatexbase.add_to_callback('pre_append_to_vlist_filter', function(head, kind)
    if not kind == 'post_linebreak' then return true end
    local attr = node.has_attribute(head, ourattr)
    if not attr then return true end
    local wordfound
    for n, id in node.traverse(head.head) do
      if id == glyph_id then
        node.set_attribute(n, luacolorattr, attr)
        wordfound = true
      elseif id == glue_id and wordfound then
        break
      end
    end
    return true
  end, 'color first word')
}
\makeatletter
\newcommand\SetFirstColor{}
\protected\def\SetFirstColor#1#{%
  \@SetFirstColor{#1}%
}
\def\@SetFirstColor#1#2{%
  \begingroup
    \color#1{#2}%
  \expandafter\endgroup
  \expandafter\ColFirstAttr\the\LuaCol@Attribute\space
}
\makeatother

\begin{document}

\SetFirstColor{red}
\blinddocument
\end{document}

enter image description here

4
  • 4
    +1 even though that's a very funny shade of red:-) Apr 18, 2020 at 12:37
  • There appears to be some code missing, including \documentclass
    – JPi
    Apr 19, 2020 at 0:11
  • 1
    @JPi I added the missing line. (Except for the \documentclass everything was there.) Apr 19, 2020 at 0:21
  • @MarcelKrüger: I would like linenumber for each line instead of color. How to achieve this. I have tried and not get the results. lineno package is having some problems in figure and table floats. So i would like to achieve in LuaLaTeX.
    – Balaji
    Dec 9, 2020 at 14:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .