summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-11-09 16:02:04 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-11-09 16:02:04 +0200
commit20d84ff8ad4b443da0cc1ff067fb92ebc3d436a5 (patch)
tree12dbc2bab8f099f3a158028eba460fc6f453a756 /cli
parent4bd33d0eb078b23d1c9ec181f07159e9141bea69 (diff)
Implement support pre-formatted fragments
For example: / x y z / Other text.
Diffstat (limited to 'cli')
-rw-r--r--cli/context.cxx48
-rw-r--r--cli/html.cxx48
-rw-r--r--cli/parser.cxx98
3 files changed, 164 insertions, 30 deletions
diff --git a/cli/context.cxx b/cli/context.cxx
index c462a5e..165ecc2 100644
--- a/cli/context.cxx
+++ b/cli/context.cxx
@@ -662,19 +662,45 @@ format (output_type ot, string const& s, bool para)
{
string r;
- // Iterate over lines (paragraphs).
+ // Iterate over lines (paragraphs) or pre-formatted sections.
//
- for (size_t b (0), e (s.find ('\n')); b != e;)
+ for (size_t b (0), e; ; b = e + 1)
{
- bool first (b == 0), last (e == string::npos);
+ bool pre (s[b] == 0x02);
+ bool first (b == 0), last;
+
+ if (pre)
+ {
+ e = s.find (0x03, ++b);
+ assert (e != string::npos);
+ last = (e + 1 == s.size ());
+ }
+ else
+ {
+ e = s.find ('\n', b);
+ last = (e == string::npos);
+ }
const char* l (s.c_str () + b);
- size_t n ((last ? s.size () : e) - b);
+ size_t n ((e != string::npos ? e : s.size ()) - b);
+
+ if (pre)
+ {
+ ++e; // Skip newline that follows 0x03.
+
+ if (ot == ot_html)
+ r += "<pre>";
+ r.append (l, n);
+
+ if (ot == ot_html)
+ r += "</pre>";
+ }
+ //
// 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)
+ else if (n >= 3 && strncmp (l, "\\h|", 3) == 0)
{
if (!para)
{
@@ -721,16 +747,12 @@ format (output_type ot, string const& s, bool para)
}
}
- // Separate paragraphs with newline.
- //
- if (!last)
- r += '\n';
+ if (last)
+ break;
- // Get next line.
+ // Separate paragraphs with newline.
//
- b = e;
- if (!last)
- e = s.find ('\n', ++b);
+ r += "\n\n";
}
return r;
diff --git a/cli/html.cxx b/cli/html.cxx
index 1f84fdd..e91fdd7 100644
--- a/cli/html.cxx
+++ b/cli/html.cxx
@@ -53,26 +53,66 @@ namespace
size_t b (0), e (0), i (0);
+ bool nl (true); // True if last written to os character is a newline.
+
for (size_t n (d.size ()); i < n; ++i)
{
+ // First handle <pre>.
+ //
+ if (d.compare (i, 5, "<pre>") == 0)
+ {
+ // Write what might have already accumulated.
+ //
+ if (b != i)
+ {
+ if (nl)
+ os << ind;
+
+ os << string (d, b, i - b);
+ nl = false;
+ }
+
+ // Output everything until (and including) closing </pre> as is.
+ //
+ e = d.find ("</pre>", i + 5);
+ assert (e != string::npos);
+ e += 6; // Now points past '>'.
+
+ if (nl)
+ os << ind;
+
+ os << string (d, i, e - i);
+
+ b = e;
+ i = e - 1; // For ++i in loop header.
+ nl = false;
+ continue;
+ }
+
if (d[i] == ' ' || d[i] == '\n')
e = i;
if (d[i] == '\n' || (i - b >= lim && e != b))
{
- os << (b != 0 ? "\n" : "") << ind << string (d, b, e - b);
+ if (nl && b != e)
+ os << ind;
- if (d[i] == '\n')
- os << endl;
+ os << string (d, b, e - b) << endl;
b = e = e + 1;
+ nl = true;
}
}
// Write the last line.
//
if (b != i)
- os << (b != 0 ? "\n" : "") << ind << string (d, b, i - b);
+ {
+ if (nl)
+ os << ind;
+
+ os << string (d, b, i - b);
+ }
}
struct doc: traversal::doc, context
diff --git a/cli/parser.cxx b/cli/parser.cxx
index c7695bc..faac290 100644
--- a/cli/parser.cxx
+++ b/cli/parser.cxx
@@ -948,7 +948,7 @@ doc_string (const char* l, size_t n)
{
// Get rid of '"'.
//
- string t1, t2;
+ string t1, t2, t3;
char p ('\0');
for (size_t i (0); i < n; ++i)
@@ -967,13 +967,17 @@ doc_string (const char* l, size_t n)
t1 += l[i];
}
- // Get rid of leading and trailing spaces in each line.
+ // Get rid of leading and trailing spaces in each line. Also handle
+ // pre-formatted fragments.
//
if (t1.size () != 0)
{
bool more (true);
size_t b (0), e, p;
+ bool pre (false);
+ size_t m; // Number of leading spaces to remove in pre.
+
while (more)
{
p = e = t1.find ('\n', b);
@@ -984,15 +988,35 @@ doc_string (const char* l, size_t n)
more = false;
}
- while (b < e && (t1[b] == 0x20 || t1[b] == 0x0D || t1[b] == 0x09))
- ++b;
+ // In the pre mode we only remove up to m leading whitespaces.
+ //
+ {
+ size_t i (0);
+ while (b < e &&
+ (t1[b] == 0x20 || t1[b] == 0x0D || t1[b] == 0x09) &&
+ (!pre || i != m))
+ {
+ ++b;
+ ++i;
+ }
- --e;
+ if (!pre)
+ m = i;
+ }
+ --e;
while (e > b && (t1[e] == 0x20 || t1[e] == 0x0D || t1[e] == 0x09))
--e;
- if (b <= e)
+ if (b == e && t1[b] == '\\')
+ {
+ // Use Start of Text (0x02) and End of Text (0x03) special
+ // characters as pre-formatted fragment markers.
+ //
+ pre = !pre;
+ t2 += (pre ? 0x02 : 0x03);
+ }
+ else if (b <= e)
t2.append (t1, b, e - b + 1);
if (more)
@@ -1001,27 +1025,75 @@ doc_string (const char* l, size_t n)
b = p + 1;
}
}
+
+ if (pre)
+ {
+ cerr << *path_ << ": error: missing pre-formatted fragment end marker "
+ << "in documentation string '" << t1 << "'" << endl;
+ throw error ();
+ }
}
- // Replace every single newlines with single space and all
- // multiple new lines (paragraph marker) with a single newline.
+ // Replace every single newlines with single space and all multiple new
+ // lines (paragraph marker) with a single newline, unless we are in a
+ // pre-formatted fragment.
//
- t1.clear ();
+ bool pre (false);
for (size_t i (0), n (t2.size ()); i < n; ++i)
{
- if (t2[i] == '\n')
+ char c (t2[i]);
+
+ if (c == '\n' && !pre)
{
size_t j (i);
for (; i + 1 < n && t2[i + 1] == '\n'; ++i) ;
if (j != 0 && i + 1 != n) // Strip leading and trailing newlines.
- t1 += i != j ? '\n' : ' ';
+ t3 += i != j ? '\n' : ' ';
}
else
- t1 += t2[i];
+ {
+ if (c == (pre ? 0x03 : 0x02))
+ {
+ pre = !pre;
+
+ // Kill "inner" newlines (after opening and before closing '/'
+ // markers). Also check for "outer" newlines so that we always
+ // have paragraph separation.
+ //
+ size_t k (t3.size ());
+ if (pre)
+ {
+ if (k != 0 && t3[k - 1] != '\n') // Outer.
+ {
+ cerr << *path_ << ": error: missing empty line before pre-"
+ << "formatted fragment start marker in documentation "
+ << "string '" << t1 << "'" << endl;
+ throw error ();
+ }
+
+ ++i; // Skip inner.
+ }
+ else
+ {
+ if (t3[k - 1] == '\n') // Could be the same as opnening if empty.
+ t3.resize (k - 1); // Pop inner.
+
+ if (i + 2 < n && (t2[i + 1] != '\n' || t2[i + 2] != '\n')) // Outer.
+ {
+ cerr << *path_ << ": error: missing empty line after pre-"
+ << "formatted fragment end marker in documentation "
+ << "string '" << t1 << "'" << endl;
+ throw error ();
+ }
+ }
+ }
+
+ t3 += c;
+ }
}
- return t1;
+ return t3;
}