]> git.lyx.org Git - features.git/blobdiff - src/xml.cpp
Use localized length strings also in space label/tooltip
[features.git] / src / xml.cpp
index 147eaddbb927583e227359d222a1613f424ac800..7ee8d9137a754749b08134bdc39dcfb29431113c 100644 (file)
 #include "BufferParams.h"
 #include "Counters.h"
 #include "Layout.h"
-#include "OutputParams.h"
 #include "Paragraph.h"
 #include "Text.h"
 #include "TextClass.h"
 
 #include "support/convert.h"
+#include "support/debug.h"
 #include "support/docstream.h"
 #include "support/lassert.h"
 #include "support/lstrings.h"
@@ -108,12 +108,9 @@ docstring StartTag::writeTag() const
 {
        docstring output = '<' + tag_;
        if (!attr_.empty()) {
-               docstring attributes = xml::escapeString(attr_, XMLStream::ESCAPE_NONE);
-               attributes.erase(attributes.begin(), std::find_if(attributes.begin(), attributes.end(),
-                                                          [](int c) {return !std::isspace(c);}));
-               if (!attributes.empty()) {
+               docstring attributes = xml::trimLeft(xml::escapeString(attr_, XMLStream::ESCAPE_NONE));
+               if (!attributes.empty())
                        output += ' ' + attributes;
-               }
        }
        output += ">";
        return output;
@@ -140,13 +137,13 @@ docstring EndTag::writeEndTag() const
 
 docstring CompTag::writeTag() const
 {
-       docstring output = '<' + from_utf8(tag_);
+       docstring output = '<' + tag_;
        if (!attr_.empty()) {
                // Erase the beginning of the attributes if it contains space characters: this function deals with that
                // automatically.
-               docstring attributes = escapeString(from_utf8(attr_), XMLStream::ESCAPE_NONE);
+               docstring attributes = escapeString(attr_, XMLStream::ESCAPE_NONE);
                attributes.erase(attributes.begin(), std::find_if(attributes.begin(), attributes.end(),
-                                                          [](int c) {return !std::isspace(c);}));
+                                                          [](char_type c) {return !isSpace(c);}));
                if (!attributes.empty()) {
                        output += ' ' + attributes;
                }
@@ -167,17 +164,27 @@ bool FontTag::operator==(StartTag const & tag) const
 } // namespace xml
 
 
-void XMLStream::writeError(std::string const &s) const
+void XMLStream::writeError(std::string const &s)
+{
+       LYXERR(Debug::OUTFILE, s);
+       *this << ESCAPE_NONE << from_utf8("<!-- Output Error: " + s + " -->");
+       *this << xml::CR();
+}
+
+
+void XMLStream::writeError(docstring const &s)
 {
-       LYXERR0(s);
-       os_ << from_utf8("<!-- Output Error: " + s + " -->\n");
+       LYXERR(Debug::OUTFILE, s);
+       *this << ESCAPE_NONE << from_utf8("<!-- Output Error: ");
+       *this << s;
+       *this << ESCAPE_NONE << from_utf8(" -->");
+       *this << xml::CR();
 }
 
 
-void XMLStream::writeError(docstring const &s) const
+XMLStream::TagPtr XMLStream::getLastStackTag()
 {
-       LYXERR0(s);
-       os_ << from_utf8("<!-- Output Error: ") << s << from_utf8(" -->\n");
+       return tag_stack_.back();
 }
 
 
@@ -198,9 +205,6 @@ bool XMLStream::closeFontTags()
                if (**curtag != xml::parsep_tag)
                        os_ << (*curtag)->writeEndTag();
                tag_stack_.pop_back();
-               // this shouldn't happen, since then the font tags
-               // weren't in any other tag.
-               LASSERT(!tag_stack_.empty(), return true);
                if (tag_stack_.empty())
                        return true;
                curtag = &tag_stack_.back();
@@ -290,6 +294,7 @@ void XMLStream::clearTagDeque()
 
 XMLStream &XMLStream::operator<<(docstring const &d)
 {
+       is_last_tag_cr_ = false;
        clearTagDeque();
        os_ << xml::escapeString(d, escape_);
        escape_ = ESCAPE_ALL;
@@ -299,6 +304,7 @@ XMLStream &XMLStream::operator<<(docstring const &d)
 
 XMLStream &XMLStream::operator<<(const char *s)
 {
+       is_last_tag_cr_ = false;
        clearTagDeque();
        docstring const d = from_ascii(s);
        os_ << xml::escapeString(d, escape_);
@@ -309,6 +315,7 @@ XMLStream &XMLStream::operator<<(const char *s)
 
 XMLStream &XMLStream::operator<<(char_type c)
 {
+       is_last_tag_cr_ = false;
        clearTagDeque();
        os_ << xml::escapeChar(c, escape_);
        escape_ = ESCAPE_ALL;
@@ -318,6 +325,7 @@ XMLStream &XMLStream::operator<<(char_type c)
 
 XMLStream &XMLStream::operator<<(char c)
 {
+       is_last_tag_cr_ = false;
        clearTagDeque();
        os_ << xml::escapeChar(c, escape_);
        escape_ = ESCAPE_ALL;
@@ -327,6 +335,7 @@ XMLStream &XMLStream::operator<<(char c)
 
 XMLStream &XMLStream::operator<<(int i)
 {
+       is_last_tag_cr_ = false;
        clearTagDeque();
        os_ << i;
        escape_ = ESCAPE_ALL;
@@ -336,6 +345,7 @@ XMLStream &XMLStream::operator<<(int i)
 
 XMLStream &XMLStream::operator<<(EscapeSettings e)
 {
+       // Don't update is_last_tag_cr_ here, as this does not output anything.
        escape_ = e;
        return *this;
 }
@@ -343,6 +353,7 @@ XMLStream &XMLStream::operator<<(EscapeSettings e)
 
 XMLStream &XMLStream::operator<<(xml::StartTag const &tag)
 {
+       is_last_tag_cr_ = false;
        if (tag.tag_.empty())
                return *this;
        pending_tags_.push_back(makeTagPtr(tag));
@@ -354,6 +365,7 @@ XMLStream &XMLStream::operator<<(xml::StartTag const &tag)
 
 XMLStream &XMLStream::operator<<(xml::ParTag const &tag)
 {
+       is_last_tag_cr_ = false;
        if (tag.tag_.empty())
                return *this;
        pending_tags_.push_back(makeTagPtr(tag));
@@ -363,6 +375,7 @@ XMLStream &XMLStream::operator<<(xml::ParTag const &tag)
 
 XMLStream &XMLStream::operator<<(xml::CompTag const &tag)
 {
+       is_last_tag_cr_ = false;
        if (tag.tag_.empty())
                return *this;
        clearTagDeque();
@@ -373,6 +386,7 @@ XMLStream &XMLStream::operator<<(xml::CompTag const &tag)
 
 XMLStream &XMLStream::operator<<(xml::FontTag const &tag)
 {
+       is_last_tag_cr_ = false;
        if (tag.tag_.empty())
                return *this;
        pending_tags_.push_back(makeTagPtr(tag));
@@ -382,6 +396,7 @@ XMLStream &XMLStream::operator<<(xml::FontTag const &tag)
 
 XMLStream &XMLStream::operator<<(xml::CR const &)
 {
+       is_last_tag_cr_ = true;
        clearTagDeque();
        os_ << from_ascii("\n");
        return *this;
@@ -434,6 +449,8 @@ bool XMLStream::isTagPending(xml::StartTag const &stag, int maxdepth) const
 // best to make things work.
 XMLStream &XMLStream::operator<<(xml::EndTag const &etag)
 {
+       is_last_tag_cr_ = false;
+
        if (etag.tag_.empty())
                return *this;
 
@@ -460,7 +477,8 @@ XMLStream &XMLStream::operator<<(xml::EndTag const &etag)
                                                   + "' when other tags were pending. Last pending tag is `"
                                                   + to_utf8(pending_tags_.back()->writeTag())
                                                   + "'. Tag discarded.");
-                               pending_tags_.erase(dit);
+                               if (!pending_tags_.empty())
+                                       pending_tags_.erase(dit);
                                return *this;
                        }
                }
@@ -581,6 +599,28 @@ docstring xml::uniqueID(docstring const & label)
 }
 
 
+bool xml::isNotOnlySpace(docstring const & str)
+{
+       for (auto const & c: str) {
+               if (c != ' ' && c != '\t' && c != '\n' && c != '\v' && c != '\f' && c != '\r')
+               return true;
+       }
+       return false;
+}
+
+
+docstring xml::trimLeft(docstring const & str)
+{
+       size_t i = 0;
+       for (auto const & c: str) {
+               if (c != ' ' && c != '\t' && c != '\n' && c != '\v' && c != '\f' && c != '\r')
+                       return str.substr(i, docstring::npos);
+               i++;
+       }
+       return str;
+}
+
+
 docstring xml::cleanID(docstring const & orig)
 {
        // The standard xml:id only allows letters, digits, '-' and '.' in a name.
@@ -628,7 +668,8 @@ docstring xml::cleanID(docstring const & orig)
        // as both of them would be transformed as "a.b". With this procedure, one will become "a.b" and the other "a.b-1".
        if (mangle && mangledNames.find(content) != mangledNames.end()) {
                int & mangleID = tMangleID.localData();
-               content += "-" + convert<docstring>(mangleID);
+               if (mangleID > 0)
+                       content += "-" + convert<docstring>(mangleID);
                mangleID += 1;
        }
 
@@ -645,9 +686,9 @@ void xml::openTag(odocstream & os, string const & name, string const & attribute
     string param = subst(attribute, "<", "\"");
     param = subst(param, ">", "\"");
 
-    // Note: we ignore the name if it empty or if it is a comment "<!-- -->" or
+    // Note: we ignore the name if it is empty or if it is a comment "<!-- -->" or
     // if the name is *dummy*.
-    // We ignore dummy because dummy is not a valid docbook element and it is
+    // We ignore dummy because dummy is not a valid DocBook element and it is
     // the internal name given to single paragraphs in the latex output.
     // This allow us to simplify the code a lot and is a reasonable compromise.
     if (!name.empty() && name != "!-- --" && name != "dummy") {
@@ -712,4 +753,146 @@ void xml::closeTag(odocstream & os, Paragraph const & par)
 }
 
 
+void openInlineTag(XMLStream & xs, const docstring & tag, const docstring & attr)
+{
+       xs << xml::StartTag(tag, attr);
+}
+
+
+void closeInlineTag(XMLStream & xs, const docstring & tag)
+{
+       xs << xml::EndTag(tag);
+}
+
+
+void openParTag(XMLStream & xs, const docstring & tag, const docstring & attr)
+{
+       if (!xs.isLastTagCR())
+               xs << xml::CR();
+       xs << xml::StartTag(tag, attr);
+}
+
+
+void closeParTag(XMLStream & xs, const docstring & tag)
+{
+       xs << xml::EndTag(tag);
+       xs << xml::CR();
+}
+
+
+void openBlockTag(XMLStream & xs, const docstring & tag, const docstring & attr)
+{
+       if (!xs.isLastTagCR())
+               xs << xml::CR();
+       xs << xml::StartTag(tag, attr);
+       xs << xml::CR();
+}
+
+
+void closeBlockTag(XMLStream & xs, const docstring & tag)
+{
+       if (!xs.isLastTagCR())
+               xs << xml::CR();
+       xs << xml::EndTag(tag);
+       xs << xml::CR();
+}
+
+
+void xml::openTag(XMLStream & xs, const docstring & tag, const docstring & attr, const std::string & tagtype)
+{
+       if (tag.empty() || tag == "NONE") // Common check to be performed elsewhere, if it was not here.
+               return;
+
+       if (tag == "para" || tagtype == "paragraph") // Special case for <para>: always considered as a paragraph.
+               openParTag(xs, tag, attr);
+       else if (tagtype == "block")
+               openBlockTag(xs, tag, attr);
+       else if (tagtype == "inline")
+               openInlineTag(xs, tag, attr);
+       else if (tagtype == "none")
+               xs << xml::StartTag(tag, attr);
+       else
+               xs.writeError("Unrecognised tag type '" + tagtype + "' for '" + to_utf8(tag) + " " + to_utf8(attr) + "'");
+}
+
+
+void xml::openTag(XMLStream & xs, const std::string & tag, const std::string & attr, const std::string & tagtype)
+{
+       xml::openTag(xs, from_utf8(tag), from_utf8(attr), tagtype);
+}
+
+
+void xml::openTag(XMLStream & xs, const docstring & tag, const std::string & attr, const std::string & tagtype)
+{
+       xml::openTag(xs, tag, from_utf8(attr), tagtype);
+}
+
+
+void xml::openTag(XMLStream & xs, const std::string & tag, const docstring & attr, const std::string & tagtype)
+{
+       xml::openTag(xs, from_utf8(tag), attr, tagtype);
+}
+
+
+void xml::closeTag(XMLStream & xs, const docstring & tag, const std::string & tagtype)
+{
+       if (tag.empty() || tag == "NONE" || tag == "IGNORE")
+               return;
+
+       if (tag == "para" || tagtype == "paragraph") // Special case for <para>: always considered as a paragraph.
+               closeParTag(xs, tag);
+       else if (tagtype == "block")
+               closeBlockTag(xs, tag);
+       else if (tagtype == "inline")
+               closeInlineTag(xs, tag);
+       else if (tagtype == "none")
+               xs << xml::EndTag(tag);
+       else
+               xs.writeError("Unrecognised tag type '" + tagtype + "' for '" + to_utf8(tag) + "'");
+}
+
+
+void xml::closeTag(XMLStream & xs, const std::string & tag, const std::string & tagtype)
+{
+       xml::closeTag(xs, from_utf8(tag), tagtype);
+}
+
+
+void xml::compTag(XMLStream & xs, const docstring & tag, const docstring & attr, const std::string & tagtype)
+{
+       if (tag.empty() || tag == from_ascii("NONE"))
+               return;
+
+       // Special case for <para>: always considered as a paragraph.
+       if (tag == from_ascii("para") || tagtype == "paragraph" || tagtype == "block") {
+               if (!xs.isLastTagCR())
+                       xs << xml::CR();
+               xs << xml::CompTag(tag, attr);
+               xs << xml::CR();
+       } else if (tagtype == "inline") {
+               xs << xml::CompTag(tag, attr);
+       } else {
+               xs.writeError("Unrecognised tag type '" + tagtype + "' for '" + to_utf8(tag) + "'");
+       }
+}
+
+
+void xml::compTag(XMLStream & xs, const std::string & tag, const std::string & attr, const std::string & tagtype)
+{
+       xml::compTag(xs, from_utf8(tag), from_utf8(attr), tagtype);
+}
+
+
+void xml::compTag(XMLStream & xs, const docstring & tag, const std::string & attr, const std::string & tagtype)
+{
+       xml::compTag(xs, tag, from_utf8(attr), tagtype);
+}
+
+
+void xml::compTag(XMLStream & xs, const std::string & tag, const docstring & attr, const std::string & tagtype)
+{
+       xml::compTag(xs, from_utf8(tag), attr, tagtype);
+}
+
+
 } // namespace lyx