Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have some text appearing in a macro, like this:

\printascolumn{This is some text.}

How can I place a line break between each letter or printed symbol, such that it appears like this?

T
h
i
s

i
s

s
o
m
e

t
e
x
t
.
share|improve this question
1  
Search for \handletokens –  Aditya Oct 27 '12 at 17:07

3 Answers 3

up vote 9 down vote accepted

ConTeXt provides a macro \handletokens which passes each token to a command. You can use \handletokens to print text vertically (or along a path, as shown in the MetaFun manual). In the example below, I also horizontally align the letters, which gives a nicer output than the default left aligned letters.

\define[1]\AddLine{#1\crlf}

\define[1]\printascolumn
    {\framed[align=middle, frame=off]{\handletokens #1 \with\AddLine}}

\starttext
\printascolumn{This is some text}
\stoptext

which gives

enter image description here

share|improve this answer
    
+1 for using the right interface and aligning the letters:-) –  David Carlisle Oct 27 '12 at 20:38

Context may have something packaged, this just uses TeX primitives.

enter image description here

\def\printascolumn#1{%
  \printa#1\relax}

\def\printa{\futurelet\tmp\printb}

\def\printb{%
\ifx\tmp\relax\printe\fi
\hbox{\tmp}%
\ifx\tmp\spchar
   \expandafter\printc
\else
   \expandafter\printd
\fi
  }

\def\printe#1\fi#2\fi{\fi}

\def\tmp#1{%
\let\spchar= #1%
\def\printc#1{\printa}}
\tmp{ }

\def\printd#1{\printa}

\printascolumn{This is some text.}

\bye
share|improve this answer
1  
Interestingly, this is the exact implementation of \handletokens in ConTeXt (except for different variable names, and a slightly different interface). –  Aditya Oct 27 '12 at 20:33

While the approach with \handletokens has its merits, it operates on token level and will fail if you have, say, an hbox in the argument. (Try \printascolumn{foo \hbox{bar} baz} ...) This is true for math mode as well.

Luckily we can do the same on node level, avoiding all the expansion issues and whatnot. The only prerequisite is that we must know which nodes to insert a break after. For our purpose it will suffice if we handle nodes of type glyph (“characters”), hlist and vlist (boxes). We specify their corresponding ids (type int) in the table breakafter using the convenient table nodes.nodecodes that is created with every Context run.

Then we create an action, which is just the Context jargon for LuaTeX callbacks (more or less, anyways ...). This action is required to be accessible from _G (locals won’t work because of the implementation), so we assign them the namespace document. We add it to the list processors which in many respects works like the pre_linebreak_filter: receive the head of a node list, manipulate the list, return a list. Once registered this action can be toggled on and off through the functions nodes.enableaction() and nodes.disableaction().

Inside the action we walk the paragraph node list. Once we encounter a node whose type is set in the breakafter table, we append a -10k penalty and a glue. This triggers a carriage return. Also, we must handle non-empty hboxes separately.[*] It is necessary to omit anything until the first glyph node. (For some obscure reason we can’t rely on the function node.first_glyph here, because it will return nil even though there are character nodes inside the box.)

One caveat: this solution as it is works on entire paragraphs only. To restrict it to some part of the paragraph list should be possible but would complicate things quite a bit.

[*] Hint: in Context the “processors” action is not totally equivalent to the pre_linebreak_filter: namely because it is applied to the hpack_filter callback as well. Under other circumstances this does mess up the iteration order quite thoroughly but here it can be considered a benefit for we don’t need to handle node lists recursively.

demo

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%                          implementation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\startluacode
  --- 1. namespace, required for callback insertion
  document = document or { }

  --- 2. reserve some locals for convenience and a marginal performance
  ---    gain
  local copy_node       = node.copy
  local count_nodes     = node.count
  local traverse_nodes  = node.traverse
  local new_node        = node.new
  local find_tail       = node.tail

  local tasks     = nodes.tasks
  local nodecodes = nodes.nodecodes

  --- 3. prepare our breaks. a break consists of (1) a penalty
  ---    and (2) an infinite horizontal glue.
  local generic_fill                = new_node(nodecodes.glue)
  generic_fill.spec                 = new_node(nodecodes.gluespec)
  generic_fill.spec.width           = 0
  generic_fill.spec.stretch         = 2^16 --> 1pt
  generic_fill.spec.shrink          = 0
  generic_fill.spec.stretch_order   = 2
  local generic_break               = new_node(nodecodes.penalty)
  generic_break.penalty             = -10^4

  --- 4. which nodes do we intend to inserts breaks after?
  local breakafter = {
    [nodecodes.glyph] = true,
    [nodecodes.hlist] = true,
    [nodecodes.vlist] = true,
  }

  --- 5. the main “action” (Contextese for callback). nothing special:
  ---    we hop over the node list prior to linebreaking and ensure that
  ---    every node of type “glyph”, as long as it is not the last node
  ---    in the list, is followed by a break.
  local glyph_breaking glyph_breaking = function (head)
    for n in traverse_nodes(head) do
      local id, len = n.id, count_nodes(nodecodes.glyph, n)
      if id == nodecodes.hlist and n.list then -- unbox
        local hd = n.list
        while hd and hd.id ~= nodecodes.glyph do
          hd = hd.next
        end
        if hd then
          local tl = find_tail(hd)
          tl.next, hd.prev         = n.next, n.prev
          n.prev.next, n.next.prev = hd, tl
          n = tl
        end
      end
      if breakafter[id] then
        local nxt = n.next
        if nxt then
          local brk  = copy_node(generic_break)
          local fill = copy_node(generic_fill)
          n.next, brk.prev    = brk, n
          brk.next, fill.prev = fill, brk
          fill.next, nxt.prev = nxt, fill
        end
      end
    end
    return head
  end

  document.glyph_breaking = glyph_breaking

  --- 6. register the glyph breaking as an action and activate it.
  tasks.appendaction ("processors", "before", "document.glyph_breaking")
  tasks.disableaction("processors",           "document.glyph_breaking")

  commands.start_as_column = function ( )
    tasks.enableaction("processors", "document.glyph_breaking")
  end
  commands.stop_as_column = function ( )
    tasks.disableaction("processors", "document.glyph_breaking")
  end
\stopluacode

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%                              macros
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 7. user interface commands. these work on per-paragraph base only as
%%    the callback is only triggered before hyphenation.
\def\startascolumn{\par\bgroup\dontcomplain\ctxcommand{start_as_column()}}
\def\stopascolumn{\par\ctxcommand{stop_as_column()}\egroup}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%                              testing
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\starttext
  Normal text.
  \startascolumn
    foo \hbox{bar \framed[corner=00,align=right]{baz}} xyzzy
    \m{\pi(x)\sim\frac{x}{\ln x}.} %% <== looks funny ...
  \stopascolumn
  Normal text.

  % \startascolumn
  %   \input knuth
  % \stopascolumn
\stoptext
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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