9

I want to highlight the structure of a formatting language that uses tags somewhat related to HTML, but with different capabilities regarding the closing tags. I'm thinking of something like this:

mockup

What options do I have to draw the brackets that explain the structure without the help of additional graphics software?

(I'm using pdflatex...)

1

2 Answers 2

6

Updated

A TikZ solution.

The implementation relies on a pair of commands \open and \close for the HTML syntax (and \openvar, \closevar for the other syntax). The commands are defined as follows:

\newcommand\open[1]{
    \tikz[remember picture,baseline=(open#1.base)]{\node(open#1){<#1>};}
}

\newcommand\close[3][red]{
    \tikz[remember picture,baseline=(close#2.base)]{
        \node(close#2){</#2>};
        \draw[#1,overlay](open#2)to[ncbar=#3](close#2);
    }
}

The -var version of the commands for the second syntax are similarly defined.

The \open command takes one argument, i.e. the name of the open tag. The \close command takes 3 arguments:

  1. the first optional argument sets the color of the "bracket" connected the open and close tags (with default set to red);
  2. the second argument is the name of the close tag;
  3. the third argument determines the height of the "bracket". Note that the bracket is implemented by the ncbar style, provided by Jake's answer here.

Full code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

% ncbar style - https://tex.stackexchange.com/a/55069/18228
\tikzset{
    ncbar angle/.initial=90,
    ncbar/.style={
        to path=(\tikztostart)
        -- ($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
        -- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
        -- (\tikztotarget)
    },
    ncbar/.default=0.5cm,
}

\tikzset{every node/.style={inner sep=0pt, outer sep=0pt}} % remove unnecessary space

% HTML syntax
\newcommand\open[1]{
    \tikz[remember picture,baseline=(open#1.base)]{\node(open#1){<#1>};}
}
\newcommand\close[3][red]{
    \tikz[remember picture,baseline=(close#2.base)]{
        \node(close#2){</#2>};
        \draw[#1,overlay](open#2)to[ncbar=#3](close#2);
    }
}

% second 'unknown' syntax
\newcommand\openvar[1]{
    \tikz[remember picture,baseline=(open#1.base)]{\node(open#1){<\uppercase{#1}>};}
}
\newcommand\closevar[3][red]{
    \tikz[remember picture,baseline=(close#2.base)]{
        \node(close#2){</>};
        \draw[#1,overlay](open#2)to[ncbar=#3](close#2);
    }
}

\begin{document}

\ttfamily

\open{b} nur fett \open{i} fett kursiv \close[green]{b}{.5cm} nur kursiv \close{i}{.7cm}

\bigskip\bigskip

\openvar{b} nur Fett \openvar{i} fett kursiv \closevar{i}{.5cm}\closevar[green]{b}{.7cm}\openvar{i} nur kursiv \closevar{i}{.5cm}

\end{document}

enter image description here


Update 2

A slightly more efficient way of defining the \close command, which has only two arguments:

\newcommand\close[2][red]{
    \tikz[remember picture,baseline=(close#2.base)]{
        \node(close#2){</#2>};
        \draw[ncbar,#1,overlay](open#2)to(close#2);
    }
}

Now it only takes two arguments:

  1. The first, optional argument controls the line style of the "bracket". The default is currently set to red, and maybe changed to [red,thick] to produce a red and thick line if the optional argument is not given.

    • Note also that the ncbar option is now given to the \draw operation, so by default, the height of the bracket is .5cm. If a bracket of height .7cm needs to be drawn, just use \close[ncbar=.7cm,<other options>]{<tag name>}.
  2. The second argument is the same as before: the name of the close tag.

With \closevar similarly modified, the above two examples can be implemented as

\open{b} nur fett \open{i} fett kursiv \close[green]{b} nur kursiv \close[red,ncbar=.7cm]{i}

and

\openvar{b} nur Fett \openvar{i} fett kursiv \closevar{i}\closevar[green,ncbar=.7cm]{b}\openvar{i} nur kursiv \closevar{i}
6
  • 2
    Related comment: I like your easy naming scheme of the nodes, but how do you implement the second example?
    – Daniel
    Oct 14, 2013 at 18:56
  • 1
    @Daniel. That's quite easy: change the defined commands: to \newcommand\open[2][]{ \tikz[remember picture,baseline=(open#2#1.base)]{\node(open#2#1){<#2>};} } (and similar for the other one). You should then be able to place the nodes using \open{i} (which makes the openi node) or \open[A]{i} which makes an openiA node. You can use the second syntax to point out ambiguities as in the second example, i.e. \open[A]{b} \open[B]{b} \close[B]{b} \close[A]{b}. Perhaps it would even possible to use LaTeX counters to do the grouping for you.
    – Egon
    Oct 14, 2013 at 20:26
  • Awesome, thanks a lot. I just need one more pointer: For printing, I need to use slightly thicker lines of the same color, but with different line styles - I'm sorry I didn't think about this when preparing the example. I noticed the red and green in your coding, but I don't understand how this is actually used by the commands. There's some magic going on that appears to be beyond my current knowledge - what do I need to read to catch up?
    – vwegert
    Oct 15, 2013 at 20:28
  • @vwegert: You're welcome. Notice that the first argument of the \close command controls the options to the \draw operation. Thus, if you want add more styles to the line, you can add more options to the first argument, and separate them using commas. For example, \close[green,dashed,very thick]{b}{.5cm} will connect the pair of b tags with a green, dashed, and very thick line; \close[red,ultra thick,<->]{i}{.7cm} will connect the pair of i tags with a red, "ultra thick" line with arrow tips on both ends.
    – Herr K.
    Oct 16, 2013 at 0:36
  • @vwegert: To learn about other options available to the \draw operation, the TikZ/PGF Manual is a well-written and authoritative source (though it's quite long). This question on TeX.SX also contains links to other (shorter) summaries of the commands used in TikZ
    – Herr K.
    Oct 16, 2013 at 0:42
9

With PSTricks just for fun. Compile it with latex-dvips-ps2pdf or xelatex (slower).

\documentclass[preview,border=24pt]{standalone}
\usepackage[T1]{fontenc}
\usepackage{pst-node}

\begin{document}
\tt
\Rnode{A}{<tag>} contents \Rnode{B}{</tag>}
\ncbar[angle=90,arm=12pt,linecolor=red]{A}{B}
\end{document}

enter image description here

PDFLaTeX version

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{auto-pst-pdf}
\usepackage{pst-node}


\begin{document}
This is a language:
\begin{postscript}
\tt
\Rnode{A}{<tag>} contents \Rnode{B}{</tag>}
\ncbar[angle=90,arm=12pt,linecolor=red,nodesep=6pt]{A}{B}
\end{postscript}
\end{document}

enter image description here

5
  • Maybe one should add something like \rule{0pt}{\dimexpr1em+12pt\relax}? Otherwise the \ncbar will protrude in other content. Oct 14, 2013 at 18:27
  • @Marienplatz: Cool, but for now I'm not really prepared to switch (back?) to XeLaTeX or DVI, coming from pdflatex...
    – vwegert
    Oct 14, 2013 at 18:29
  • Unrelated comment: \tt is not a LaTeX command, \ttfamily is correct. (\tt isn't even defined in the LaTeX kernel, it is provided by the class for compatibility reasons, try the same with memoir...)
    – cgnieder
    Oct 14, 2013 at 18:55
  • @cgnieder: by the way: memoir has an option oldfontcommands
    – user2478
    Oct 14, 2013 at 20:42
  • @Herbert I know :) I think it's still a good example...
    – cgnieder
    Oct 14, 2013 at 20:45

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.