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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 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
\handletokens– Aditya Oct 27 '12 at 17:07