Rounded box around placeholder text that supports line breaking

This is not a perfect solution, but it is close, and you can get there with very little effort. Basically use textbackground and change the radius using the radius key. For example:

\definecolor [lightblue] [r=0.5, g=0.5, b=1]


\definetextbackground
    [placeholder]
    [
      location=text,
      background=color,
      backgroundcolor=lightblue,
      frame=on,
      corner=round,
      radius=0.8\lineheight,
    ]

\starttext

  This is a \placeholder{placeholder text \input ward again} continuing

  /foo/\placeholder{placeholder}/bar

\stoptext

which gives

enter image description here

This does not behave well when it is split across only one line.

enter image description here


This answer uses a different mechanism, so I am posting it as a separate answer rather than editing the previous one. This is not a complete answer, but a proof of concept that works if the phrase is split across lines only once. It is possible to extend it so that it works if the phrase is split across multiple lines and/or multiple pages, but that requires more code.

The main idea is to use the anchoring mechanism of ConTeXt (similar to the \Tikzmark macro), record the beginning and end of the phrase, and use that the draw the background. Since the actual code of drawing the background is a bit messy, let me start by the simple task of underlining the phrase so that the underline splits across lines.

\definecolor[lightblue][b=1,r=0.5,g=0.5]

\unprotect
\newcount\c_placeholder_n

\def\placeholder#1%
    {\global\advance\c_placeholder_n\plusone
     \startpositionoverlay{text-1}% The layer just below text
     \setMPpositiongraphicrange 
       {b:placeholder:\the\c_placeholder_n}%
       {e:placeholder:\the\c_placeholder_n}%
       {mpos:placeholder}%
       {self=placeholder:\the\c_placeholder_n,
        linewidth=1bp,
        linecolor=red,
        color=lightblue,
        radius=0.5\lineheight}%
     \stoppositionoverlay
     \bpos{placeholder:\the\c_placeholder_n}%
     #1%
     \epos{placeholder:\the\c_placeholder_n}}

\protect

% This is a simple proof of concept. I assume that there is at most one line
% break, and no page break between the text.
\startMPpositionmethod{mpos:placeholder}
    \startMPpositiongraphic{mpos:placeholder}{linecolor,linewidth,color,radius}%
        begingroup;
        newnumeric x,y, w, a_x, a_y, a_h, a_d, b_x, b_y, b_h, b_d, r ;
        (x,y)     = \MPxy\textanchor; % The overlay is anchored at (x,y). 
        % So, we have to subtract (x,y) from each point.

        (a_x,a_y) = \MPxy\MPbself; % The localtion of the beginning of the line.

        % Height and depth at the beginning of the line
        a_h := \MPh\MPbself; a_d := \MPd\MPbself;

        (b_x,b_y) = \MPxy\MPeself; % The location of the end of the line

        % Height and depth at the end of the line
        b_h := \MPh\MPeself; b_d := \MPd\MPeself;

        w := \MPw{\textanchor}; % equal to line width for split words.

        r := \MPvar{radius};

        newpath p;

        drawoptions (withpen pencircle scaled \MPvar{linewidth} withcolor \MPvar{linecolor});

        % Note that the line is drawn at the baseline of the word.
        % If you subtract a_d to the y-coordinate, then the line will 
        % be drawn so that it is below the depth of the characters (i.e., below the
        % 'p' in placeholder).
        % If you add a_h to the y-coordinate, then the line will be drawn so
        % that it is at the top of the characters.
        if a_y = b_y : % Word is not split
          p := (-x + a_x, -y + a_y ) -- (-x + b_x, -y + b_y) ;
          draw p;
        else : % word is split across lines
          % Draw the first part
          p := (-x + a_x, -y + a_y) -- (w, -y + a_y);
          draw p;
          % Draw the second part
          p := (0, -y + b_y) -- (-x + b_x, -y + b_y);
          draw p;
        fi
        endgroup;
        % Now, to complete the solution, all you need to do is to constuct an
        % appropriate metapost shape.
    \stopMPpositiongraphic
    \MPpositiongraphic{mpos:placeholder}{}%
\stopMPpositionmethod

\setuppapersize[A5]

\starttext

A short \placeholder{placeholder} in a line

A very long line that splits across lines at the word \placeholder{place\-holder~word} and continues after that.

\stoptext

which gives

enter image description here

The rest is just a matter of details to tweak the MP position method so that it draws the required shape. For example, if you change it to

\startMPpositionmethod{mpos:placeholder}
    \startMPpositiongraphic{mpos:placeholder}{linecolor,linewidth,color,radius}%
        begingroup;
        newnumeric x,y, w, a_x, a_y, a_h, a_d, b_x, b_y, b_h, b_d, r ;
        (x,y)     = \MPxy\textanchor; % The overlay is anchored at (x,y). 
        % So, we have to subtract (x,y) from each point.

        (a_x,a_y) = \MPxy\MPbself; % The localtion of the beginning of the line.

        % Height and depth at the beginning of the line
        a_h := \MPh\MPbself; a_d := \MPd\MPbself;

        (b_x,b_y) = \MPxy\MPeself; % The location of the end of the line

        % Height and depth at the end of the line
        b_h := \MPh\MPeself; b_d := \MPd\MPeself;

        w := \MPw{\textanchor}; % equal to line width for split words.

        r := \MPvar{radius};

        newpath p;

        drawoptions (withpen pencircle scaled \MPvar{linewidth} withcolor \MPvar{linecolor});

      if a_y = b_y : % Word is not split
          p := (-x + a_x + r/2 , -y + a_y - a_d) {left}
            .. {up}(-x + a_x - r/2, -y + a_y + (a_h - a_d)/2 ){up} 
            .. {right}( -x + a_x + r/2, -y + a_y + a_h) 
            -- (-x + b_x - r/2, -y + b_y + b_h) {right}
            .. {down} (-x + b_x + r/2, -y + b_y + (b_h - b_d)/2 ) {down}
            .. (-x + b_x - r/2, -y + b_y - b_d) 
            -- cycle;
          fill p withcolor \MPvar{color};
          draw p;
        else : % word is split across lines
          % Draw the first part
          p := (-x + a_x + r/2 , -y + a_y - a_d) {left}
            .. {up}(-x + a_x - r/2, -y + a_y + (a_h - a_d)/2 ){up} 
            .. {right}( -x + a_x + r/2, -y + a_y + a_h) 
            -- (w , -y + a_y + a_h) 
            -- (w , -y + a_y - a_d)
            -- cycle;
          fill p withcolor \MPvar{color};
          draw p;

          % Draw the second part
          p := (0, -y + b_y - b_d)
            -- (0, -y + b_y + b_h) 
            -- (-x + b_x - r/2, -y + b_y + b_h) {right}
            .. {down} (-x + b_x + r/2, -y + b_y + (b_h - b_d)/2 ) {down}
            .. (-x + b_x - r/2, -y + b_y - b_d) 
            -- cycle;
          fill p withcolor \MPvar{color};
          draw p;
        fi
        endgroup;
        % Now, to complete the solution, all you need to do is to constuct an
        % appropriate metapost shape.
    \stopMPpositiongraphic
    \MPpositiongraphic{mpos:placeholder}{}%
\stopMPpositionmethod

you get

enter image description here

As I said earlier, it is possible to add support for multiple lines (similar to the MkII version of the underline macro, but that assumes that the interline spacing is constant; an assumption that may not always be true). The underline macro in MkIV uses a completely different attributes based mechanism to draw the underline. It may be possible to tweak that to get rounded corners, but I don't understand that code well enough to suggest how to do that.

EDIT: The version below takes care of the placeholder splitting across pages.

\startMPpositionmethod{mpos:placeholder}
    \startMPpositiongraphic{mpos:placeholder}{linecolor,linewidth,color,radius}%
        begingroup;
        newnumeric x,y, w, a_x, a_y, a_h, a_d, b_x, b_y, b_h, b_d, a_p, p_h, r ;
        (x,y)     = \MPxy\textanchor; % The overlay is anchored at (x,y). 
        % So, we have to subtract (x,y) from each point.

        (a_x,a_y) = \MPxy\MPbself; % The localtion of the beginning of the line.

        % Height and depth at the beginning of the line
        a_h := \MPh\MPbself; a_d := \MPd\MPbself;

        (b_x,b_y) = \MPxy\MPeself; % The location of the end of the line

        % Height and depth at the end of the line
        b_h := \MPh\MPeself; b_d := \MPd\MPeself;

        % Page number of the anchors
        a_p := \MPp\MPbself; b_p := \MPp\MPeself;

        w := \MPw{\textanchor}; % equal to line width for split words.

        r := \MPvar{radius};

        newpath p;

        drawoptions (withpen pencircle scaled \MPvar{linewidth} withcolor \MPvar{linecolor});

        if a_y = b_y : % Word is not split
          p := (-x + a_x + r/2 , -y + a_y - a_d) {left}
            .. {up}(-x + a_x - r/2, -y + a_y + (a_h - a_d)/2 ){up} 
            .. {right}( -x + a_x + r/2, -y + a_y + a_h) 
            -- (-x + b_x - r/2, -y + b_y + b_h) {right}
            .. {down} (-x + b_x + r/2, -y + b_y + (b_h - b_d)/2 ) {down}
            .. (-x + b_x - r/2, -y + b_y - b_d) 
            -- cycle;
          fill p withcolor \MPvar{color};
          draw p;
        else : % word is split across lines
          % If the beginning anchor is on the current page, draw the first part
          if a_p = RealPageNumber :
              p := (-x + a_x + r/2 , -y + a_y - a_d) {left}
                .. {up}(-x + a_x - r/2, -y + a_y + (a_h - a_d)/2 ){up} 
                .. {right}( -x + a_x + r/2, -y + a_y + a_h) 
                -- (w , -y + a_y + a_h) 
                -- (w , -y + a_y - a_d)
                -- cycle;
              fill p withcolor \MPvar{color};
              draw p;
          fi

          % The the end of the anchor is on the current page, draw the second
          % part
          if b_p = RealPageNumber :
              p := (0, -y + b_y - b_d)
                -- (0, -y + b_y + b_h) 
                -- (-x + b_x - r/2, -y + b_y + b_h) {right}
                .. {down} (-x + b_x + r/2, -y + b_y + (b_h - b_d)/2 ) {down}
                .. (-x + b_x - r/2, -y + b_y - b_d) 
                -- cycle;
              fill p withcolor \MPvar{color};
              draw p;
          fi
        fi
        endgroup;
    \stopMPpositiongraphic
    \MPpositiongraphic{mpos:placeholder}{}%
\stopMPpositionmethod

This solution is based on a modification of my censor package to replace the strikeout \rule with the original letter on a blue field. I had to do the endcaps specially, and some of the parameter lengths associated with the covering of "glue" might need tweaking.

I should point out that one of the virtues of this solution (and the censor package) is that the blue'ing should not change the underlying spacing of the text (except in the case of word-breaking hyphenation, which will not happen). That is to say, it should typeset the same, if the \marktext macro is removed. But one downside of this is that the endcaps could overlap surrounding text. Thus the \gapmarktext macro will set the endcaps directly, rather than lapping them to the ends of the textblock.

\documentclass{article}
\usepackage{censor}
\usepackage{stackengine}
\usepackage{xcolor}
\usepackage{scalerel}
\usepackage{bbding}

\makeatletter
\def\mystrut{\rule[-.22\baselineskip]{0pt}{.84\baselineskip}}
\setstackgap{L}{0pt}
\def\stacktype{L}
\def\useanchorwidth{T}

\periodrlap=0pt\relax
\afterperiodlap=0pt\relax
\lletterlap=0pt\relax
\rletterlap=0pt\relax
\afterspacelap=.85ex\relax

\renewcommand\censorrule[1]{
\protect\colorbox{cyan}{\mystrut\rule[\censorruledepth]{#1}{0pt}}}

\renewcommand\@cenword[1]{\colorbox{cyan}{\mystrut#1}}

\def\censordot{\colorbox{cyan}{\mystrut.}}

\newsavebox\HSL
\sbox\HSL{\textcolor{cyan}{\HalfCircleLeft}}
\newsavebox\HSR
\sbox\HSR{\textcolor{cyan}{\HalfCircleRight}}

\def\endleft{\hstretch{.5}{\scalerel*{\usebox{\HSL}}{\mystrut}}}
\def\endright{\hstretch{.5}{\scalerel*{\usebox{\HSR}}{\mystrut}}}

\newcommand\marktext[1]{%
\textcolor{cyan}{\llap{\smash{\endleft}}}%
\xblackout{#1}%
\textcolor{cyan}{\rlap{\smash{\endright}}}%
}

\newcommand\gapmarktext[1]{%
\textcolor{cyan}{\endleft}%
\xblackout{#1}%
\textcolor{cyan}{\endright}%
}

\makeatother
\fboxsep=0pt
\parindent 0in
\parskip 1em
\begin{document}

Path with placeholder\\
/foo/ \marktext{place holder} /bar/

\parbox{2.05in}
{Path that contains a placeholder with a line break: 
/foo/ \marktext{place holder} /bar/}

Note however, that auto-hypenation will NOT work with this approach,
which is why I made \marktext{place holder} with a space in the middle.

Also, if the marktext doesn't have a space on either side, an overlap
could occur as in this example: 
/foo/\marktext{placeholder}/bar

That can be remedied by using the gapmarktext macro instead:
/foo/\gapmarktext{placeholder}/bar

This shows linebreaking capability: aaa aaa aaa aaa aaa aaa aaa
\marktext{bbb bbb bbb bbb. bbb bbb bbb bbb bbb bbb}
ccc ccc ccc ccc ccc ccc

Can this \marktext{procedure go across paragraphs boundaries?

Why yes} it can.

But gaps can arise if glue is stretched too far.

\marktext{%
This tests marking a multiline block of text.  This tests marking a multiline block of text.
This tests marking a multiline block of text.  This tests marking a multiline block of text.
This tests marking a multiline block of text.}

\end{document}

enter image description here