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 '20 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 '20 at 11:28
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 '20 at 12:37
  • There appears to be some code missing, including \documentclass
    – JPi
    Apr 19 '20 at 0:11
  • 1
    @JPi I added the missing line. (Except for the \documentclass everything was there.) Apr 19 '20 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 '20 at 14:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.