On Tue, Mar 14, 2017 at 01:01:23AM -0400, Scott Kostyshak wrote:

> I have a patch and it seems to work well. I want to clean it up before
> posting. I will post it again for review because even though it seems to
> work well, I wonder if there is a cleaner way of doing it. I will post
> a cleaned up version in a couple of days.

Attached are two patches. Are they what you had in mind?

Because I edit splitArg(), this could cause problems with other LFUNs.

Scott
From d49881c637e29b28536c9a37dceadb0a6bb21a00 Mon Sep 17 00:00:00 2001
From: Scott Kostyshak <skost...@lyx.org>
Date: Sat, 18 Mar 2017 09:44:47 -0400
Subject: [PATCH 1/2] Allow LFUNs to escape/unescape quotes

LFUNs can now use addArg() to add an argument in a way that nested
quotes and backslashes will be correctly handled. This argument can
then be correctly split by splitArg().

For a use case, see the next commit involving spaces in branch
names.

A new string helper function is created, nTrailing(), which returns
the number of trailing backslashes.
---
 src/FuncRequest.cpp      | 35 ++++++++++++++++++++++++++++++++++-
 src/FuncRequest.h        |  3 +++
 src/support/lstrings.cpp | 15 +++++++++++++++
 src/support/lstrings.h   |  3 +++
 4 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/src/FuncRequest.cpp b/src/FuncRequest.cpp
index 224ba27..670a18e 100644
--- a/src/FuncRequest.cpp
+++ b/src/FuncRequest.cpp
@@ -88,9 +88,30 @@ void splitArg(vector<string> & args, string const & str,
                string s;
                is >> c;
                if (is) {
-                       if (c == '"')
+                       if (c == '"') {
                                // get quote delimited argument
                                getline(is, s, '"');
+
+                               // Allow for escaped double quotes.
+                               // If lastch is a backslash and if it is part of
+                               // an odd number of trailing backslashes, then
+                               // lastch is escaping the double quote, so we
+                               // put the double quote back.
+                               unsigned int ntb = nTrailing(s);
+                               char lastch = *s.rbegin();
+                               while (lastch == '\\' && ntb % 2) {
+                                       s.pop_back();
+                                       s.append("\"");
+                                       string s2;
+                                       getline(is, s2, '"');
+                                       s.append(s2);
+                                       lastch = *s.rbegin();
+                                       ntb = nTrailing(s);
+                               }
+
+                               // unescape backslashes
+                               s = subst(s, "\\\\", "\\");
+                       }
                        else {
                                // get whitespace delimited argument
                                is.putback(c);
@@ -119,6 +140,18 @@ string FuncRequest::getLongArg(unsigned int i) const
 }
 
 
+void FuncRequest::addArg(docstring const & str)
+{
+       if (!argument_.empty())
+               argument_ += ' ';
+       // first escape backslashes
+       docstring strQuoted = subst(str, from_ascii("\\"), from_ascii("\\\\"));
+       // then escape double quotes
+       strQuoted = subst(strQuoted, from_ascii("\""), from_ascii("\\\""));
+       argument_ += '"' + strQuoted + '"';
+}
+
+
 bool operator==(FuncRequest const & lhs, FuncRequest const & rhs)
 {
        return lhs.action() == rhs.action() && lhs.argument() == rhs.argument();
diff --git a/src/FuncRequest.h b/src/FuncRequest.h
index a5822f4..0b4321b 100644
--- a/src/FuncRequest.h
+++ b/src/FuncRequest.h
@@ -85,6 +85,9 @@ public:
        /// argument parsing, extract argument i as std::string,
        /// eating all characters up to the end of the command line
        std::string getLongArg(unsigned int i) const;
+       /// Adds an argument, escaping double quotes and backslashes, which
+       /// are correctly parsed by splitArg()
+       void addArg(docstring const &);
 
        /// 
        static FuncRequest const unknown;
diff --git a/src/support/lstrings.cpp b/src/support/lstrings.cpp
index 8ffab19..744c888 100644
--- a/src/support/lstrings.cpp
+++ b/src/support/lstrings.cpp
@@ -1066,6 +1066,21 @@ docstring const ltrim(docstring const & a, char const * 
p)
        return a.substr(l, docstring::npos);
 }
 
+unsigned int nTrailing(string const & str, char const * c) {
+       string::const_reverse_iterator sit = str.rbegin();
+       int n = 0;
+       char ch;
+       while (sit != str.rend()) {
+               ch = *sit;
+               if (ch == *c)
+                       n += 1;
+               else
+                       break;
+               ++sit;
+       }
+       return n;
+}
+
 namespace {
 
 template<typename String, typename Char> inline
diff --git a/src/support/lstrings.h b/src/support/lstrings.h
index 36ba09f..c5eee10 100644
--- a/src/support/lstrings.h
+++ b/src/support/lstrings.h
@@ -241,6 +241,9 @@ docstring const rtrim(docstring const & a, char const * p = 
" ");
 std::string const ltrim(std::string const & a, char const * p = " ");
 docstring const ltrim(docstring const & a, char const * p = " ");
 
+// Returns the number of (consecutive) trailing c in a string.
+unsigned int nTrailing(std::string const & str, char const * c = "\\");
+
 /** Splits the string given in the first argument at the first occurence 
     of the third argument, delim.
     What precedes delim is returned in the second argument, piece; this
-- 
2.7.4

From 223845648e694be9b78c6527df456a40f494a1d2 Mon Sep 17 00:00:00 2001
From: Scott Kostyshak <skost...@lyx.org>
Date: Sat, 18 Mar 2017 09:49:42 -0400
Subject: [PATCH 2/2] Allow branch names to contain spaces

The functions addArg() and splitArg() are used to automatically take
care of any embedded spaces.

Also, use Lexer for reading and writing branch names.
---
 src/Buffer.cpp                       |  6 ++++--
 src/frontends/qt4/GuiApplication.cpp |  4 ++--
 src/frontends/qt4/GuiDocument.cpp    | 12 ++++++++----
 src/insets/InsetBranch.cpp           |  5 +++--
 4 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index a20b4da..42e3c82 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -2797,10 +2797,12 @@ void Buffer::dispatch(FuncRequest const & func, 
DispatchResult & dr)
                        } else {
                                undo().recordUndoBufferParams(CursorData());
                                branch_list.add(branch_name);
+                               FuncRequest fr(LFUN_SET_COLOR);
                                branch = branch_list.find(branch_name);
+                               fr.addArg(branch_name);
                                string const x11hexname = 
X11hexname(branch->color());
-                               docstring const str = branch_name + ' ' + 
from_ascii(x11hexname);
-                               lyx::dispatch(FuncRequest(LFUN_SET_COLOR, str));
+                               fr.addArg(from_ascii(x11hexname));
+                               lyx::dispatch(fr);
                                dr.setError(false);
                                dr.screenUpdate(Update::Force);
                        }
diff --git a/src/frontends/qt4/GuiApplication.cpp 
b/src/frontends/qt4/GuiApplication.cpp
index 05b7a25..85d0ea6 100644
--- a/src/frontends/qt4/GuiApplication.cpp
+++ b/src/frontends/qt4/GuiApplication.cpp
@@ -1736,8 +1736,8 @@ void GuiApplication::dispatch(FuncRequest const & cmd, 
DispatchResult & dr)
        }
 
        case LFUN_SET_COLOR: {
-               string lyx_name;
-               string const x11_name = split(to_utf8(cmd.argument()), 
lyx_name, ' ');
+               string lyx_name = cmd.getArg(0);
+               string x11_name = cmd.getArg(1);
                if (lyx_name.empty() || x11_name.empty()) {
                        if (current_view_)
                                current_view_->message(
diff --git a/src/frontends/qt4/GuiDocument.cpp 
b/src/frontends/qt4/GuiDocument.cpp
index 2293ce3..25594cd 100644
--- a/src/frontends/qt4/GuiDocument.cpp
+++ b/src/frontends/qt4/GuiDocument.cpp
@@ -4129,8 +4129,10 @@ void GuiDocument::dispatchParams()
                        Branch const * branch = branchlist.find(current_branch);
                        string const x11hexname = X11hexname(branch->color());
                        // display the new color
-                       docstring const str = current_branch + ' ' + 
from_ascii(x11hexname);
-                       dispatch(FuncRequest(LFUN_SET_COLOR, str));
+                       FuncRequest fr(LFUN_SET_COLOR);
+                       fr.addArg(current_branch);
+                       fr.addArg(from_ascii(x11hexname));
+                       dispatch(fr);
                }
 
                // Open insets of selected branches, close deselected ones
@@ -4152,8 +4154,10 @@ void GuiDocument::dispatchParams()
                        Index const * index = 
indiceslist.findShortcut(current_index);
                        string const x11hexname = X11hexname(index->color());
                        // display the new color
-                       docstring const str = current_index + ' ' + 
from_ascii(x11hexname);
-                       dispatch(FuncRequest(LFUN_SET_COLOR, str));
+                       FuncRequest fr(LFUN_SET_COLOR);
+                       fr.addArg(current_index);
+                       fr.addArg(from_ascii(x11hexname));
+                       dispatch(fr);
                }
        }
        // FIXME LFUN
diff --git a/src/insets/InsetBranch.cpp b/src/insets/InsetBranch.cpp
index 3cde061..4a31706 100644
--- a/src/insets/InsetBranch.cpp
+++ b/src/insets/InsetBranch.cpp
@@ -394,7 +394,7 @@ void InsetBranch::updateBuffer(ParIterator const & it, 
UpdateType utype)
 
 void InsetBranchParams::write(ostream & os) const
 {
-       os << to_utf8(branch) 
+       os << Lexer::quoteString(to_utf8(branch))
           << '\n' 
           << "inverted " 
           << inverted;
@@ -403,7 +403,8 @@ void InsetBranchParams::write(ostream & os) const
 
 void InsetBranchParams::read(Lexer & lex)
 {
-       lex >> branch;
+       lex.next(true);
+       branch = lex.getDocString();
        lex >> "inverted" >> inverted;
 }
 
-- 
2.7.4

Attachment: signature.asc
Description: PGP signature

Reply via email to