summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-10-31 12:01:41 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-10-31 12:01:41 +0200
commitc37f07f5134104dae6d5bbc18a3d133b023ff792 (patch)
treef03d5ab23c042e67b12c4b9c4e370f25146abb88
parent4726db4a00c349550723d7cd4b8b4180661620cb (diff)
downloadcli-c37f07f5134104dae6d5bbc18a3d133b023ff792.tar.gz
cli-c37f07f5134104dae6d5bbc18a3d133b023ff792.tar.xz
cli-c37f07f5134104dae6d5bbc18a3d133b023ff792.zip
Add support for \h paragraph
-rw-r--r--cli/context.cxx101
1 files changed, 84 insertions, 17 deletions
diff --git a/cli/context.cxx b/cli/context.cxx
index 8de23ab..c462a5e 100644
--- a/cli/context.cxx
+++ b/cli/context.cxx
@@ -4,6 +4,7 @@
// license : MIT; see accompanying LICENSE file
#include <stack>
+#include <cstring> // strncmp()
#include <iostream>
#include "context.hxx"
@@ -489,6 +490,11 @@ format_line (output_type ot, string& r, const char* s, size_t n)
r += '}';
break;
}
+ case '|':
+ {
+ r += '|';
+ break;
+ }
default:
{
cerr << "error: unknown escape sequence '\\" << c << "' in "
@@ -606,6 +612,13 @@ format_line (output_type ot, string& r, const char* s, size_t n)
}
}
+ if (escape)
+ {
+ cerr << "error: unterminated escape sequence in documentation "
+ << "paragraph '" << string (s, 0, n) << "'" << endl;
+ throw generation_failed ();
+ }
+
if (!blocks.empty ())
{
unsigned char b (blocks.top ());
@@ -621,6 +634,29 @@ format_line (output_type ot, string& r, const char* s, size_t n)
}
}
+// Return true if this line ends the paragraph, that is, ends with an
+// unescaped '|'.
+//
+static bool
+end_para (const char* l, size_t n)
+{
+ if (l[n - 1] != '|')
+ return false;
+
+ if (n == 1 || l[n - 2] != '\\')
+ return true;
+
+ // To determine whether this is an escape sequence we have to find
+ // first non-backslash character and then figure out who escapes who.
+ //
+ size_t i (n - 2);
+ for (; i != 0 && l[i - 1] == '\\'; --i) ;
+
+ // If we have an even number of backslashes, the it is unescaped.
+ //
+ return (n - i - 1) % 2 == 0;
+}
+
string context::
format (output_type ot, string const& s, bool para)
{
@@ -632,33 +668,64 @@ format (output_type ot, string const& s, bool para)
{
bool first (b == 0), last (e == string::npos);
- if (first) // Before first line.
- {
- if (ot == ot_html && para)
- r += "<p>";
- }
- else // Between lines.
+ const char* l (s.c_str () + b);
+ size_t n ((last ? s.size () : e) - b);
+
+ // Some paragraph blocks are only valid if we are required to start
+ // a new paragraph (para is true).
+ //
+ if (n >= 3 && strncmp (l, "\\h|", 3) == 0)
{
- if (ot == ot_html && para)
- r += "</p>";
+ if (!para)
+ {
+ cerr << "error: invalid context '" << s << "' for paragraph '"
+ << string (l, 0, n) << "'" << endl;
+ throw generation_failed ();
+ }
- r += '\n';
+ if (!end_para (l, n))
+ {
+ cerr << "error: '|' expected at the end of paragraph '"
+ << string (l, 0, n) << "'" << endl;
+ throw generation_failed ();
+ }
- if (ot == ot_html)
+ if (n == 4)
{
- r += "<p>";
- para = true;
+ cerr << "error: empty paragraph '" << string (l, 0, n) << "'" << endl;
+ throw generation_failed ();
}
- }
- format_line (ot, r, s.c_str () + b, (last ? s.size () : e) - b);
+ if (ot == ot_html)
+ r += "<h1>";
+
+ format_line (ot, r, l + 3, n - 4);
- if (last) // After last line.
+ if (ot == ot_html)
+ r += "</h1>";
+ }
+ else // Normal text.
{
- if (ot == ot_html && para)
- r += "</p>";
+ if (para || !first) // Start a paragraph?
+ {
+ if (ot == ot_html)
+ r += "<p>";
+ }
+
+ format_line (ot, r, l, n);
+
+ if (para || !first) // End a paragraph?
+ {
+ if (ot == ot_html)
+ r += "</p>";
+ }
}
+ // Separate paragraphs with newline.
+ //
+ if (!last)
+ r += '\n';
+
// Get next line.
//
b = e;