[rkward/frameworks] /: Make fucnction argument hinting more robust against quotes.

Thomas Friedrichsmeier thomas.friedrichsmeier at ruhr-uni-bochum.de
Tue Oct 25 20:13:52 UTC 2016


Git commit 86fb0a7586f55c6d82a0c48331ef680a9a1d2f7a by Thomas Friedrichsmeier.
Committed on 25/10/2016 at 20:12.
Pushed by tfry into branch 'frameworks'.

Make fucnction argument hinting more robust against quotes.

Note that multiline quotes will still fool the - crude - parsing.

M  +1    -0    ChangeLog
M  +20   -13   rkward/misc/rkcommonfunctions.cpp
M  +4    -0    rkward/misc/rkcommonfunctions.h
M  +17   -14   rkward/windows/rkcommandeditorwindow.cpp

http://commits.kde.org/rkward/86fb0a7586f55c6d82a0c48331ef680a9a1d2f7a

diff --git a/ChangeLog b/ChangeLog
index 9be1bff..5276786 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+- Function argument hinting is less easily fooled by braces inside quotes
 - Preview status messages can now be closed
 - Show the message accompanying rk.show.files() or rk.edit.files() inside the main window, instead of a separate dialog
 - File browser gains "Rename" context menu action
diff --git a/rkward/misc/rkcommonfunctions.cpp b/rkward/misc/rkcommonfunctions.cpp
index 9382c5a..77e296f 100644
--- a/rkward/misc/rkcommonfunctions.cpp
+++ b/rkward/misc/rkcommonfunctions.cpp
@@ -113,6 +113,19 @@ namespace RKCommonFunctions {
 		return (context_line.mid (current_word_start, current_word_end - current_word_start));
 	}
 
+	int quoteEndPosition (const QChar& quote_char, const QString& haystack, int from) {
+		int line_end = haystack.length () - 1;
+		for (int i=from; i <= line_end; ++i) {
+			QChar c = haystack.at (i);
+			if (c == quote_char) return i;
+			if (c == '\\') {
+				++i;
+				continue;
+			}
+		}
+		return -1; // quote end not found
+	}
+
 	void getCurrentSymbolOffset (const QString &context_line, int cursor_pos, bool strict, int *start, int *end) {
 		*start = 0;
 
@@ -120,22 +133,16 @@ namespace RKCommonFunctions {
 		*end = line_end + 1;
 		if (cursor_pos > line_end) cursor_pos = line_end;
 
-		QChar quote_char;
 		for (int i=0; i <= line_end; ++i) {
 			QChar c = context_line.at (i);
-			if (!quote_char.isNull ()) {
-				if (c == '\\') ++i;
-				if (c == quote_char) quote_char = QChar ();
+			if (c == '\'' || c == '\"' || c == '`') {
+				i = quoteEndPosition (c, context_line, i+1);
+				if (i < 0) break;
 				continue;
-			} else {
-				if (c == '\'' || c == '\"' || c == '`') {
-					quote_char = c;
-					continue;
-				} else if (c.isLetterOrNumber () || c == '.' || c == '_') {
-					continue;
-				} else if (!strict) {
-					if (c == '$' || c == ':' || c == '[' || c == ']' || c == '@') continue;
-				}
+			} else if (c.isLetterOrNumber () || c == '.' || c == '_') {
+				continue;
+			} else if (!strict) {
+				if (c == '$' || c == ':' || c == '[' || c == ']' || c == '@') continue;
 			}
 
 			// if we did not hit a continue, yet, that means we are on a potential symbol boundary
diff --git a/rkward/misc/rkcommonfunctions.h b/rkward/misc/rkcommonfunctions.h
index f8c0608..23511ca 100644
--- a/rkward/misc/rkcommonfunctions.h
+++ b/rkward/misc/rkcommonfunctions.h
@@ -17,6 +17,8 @@
 #ifndef RKCOMMONFUNCTIONS_H
 #define RKCOMMONFUNCTIONS_H
 
+#include <QChar>
+
 class QStringList;
 class QString;
 class QDomNode;
@@ -41,6 +43,8 @@ namespace RKCommonFunctions {
 /** Get a suitable file name in the RKWard data directory */
 	QString getUseableRKWardSavefileName (const QString &prefix, const QString &postfix);
 
+/** given a context line, find the end of a quote started by quote_char. @returns -1 if not end of quote was found. */
+	int quoteEndPosition (const QChar& quote_char, const QString& haystack, int from = 0);
 
 /** given the context line, find what looks like an R symbol */
 	QString getCurrentSymbol (const QString &context_line, int cursor_pos, bool strict=true);
diff --git a/rkward/windows/rkcommandeditorwindow.cpp b/rkward/windows/rkcommandeditorwindow.cpp
index 0ce8c30..8223063 100644
--- a/rkward/windows/rkcommandeditorwindow.cpp
+++ b/rkward/windows/rkcommandeditorwindow.cpp
@@ -905,28 +905,31 @@ void RKFunctionArgHinter::tryArgHintNow () {
 
 	// find the active opening brace
 	int line_rev = -1;
-	int brace_level = 1;
-	int potential_symbol_end = -1;
+	QList<int> unclosed_braces;
 	QString full_context;
-	while (potential_symbol_end < 0) {
+	while (unclosed_braces.isEmpty ()) {
 		QString context_line = provider->provideContext (++line_rev);
 		if (context_line.isNull ()) break;
-
 		full_context.prepend (context_line);
-		int pos = context_line.length ();
-		while (--pos >= 0) {
-			QChar c = full_context.at (pos);
-			if (c == ')') ++brace_level;
-			else if (c == '(') {
-				--brace_level;
-				if (brace_level == 0) {
-					potential_symbol_end = pos - 1;
-					break;
-				}
+		for (int i = 0; i < context_line.length (); ++i) {
+			QChar c = context_line.at (i);
+			if (c == '"' || c == '\'' || c == '`') {  // NOTE: this algo does not produce good results on string constants spanning newlines.
+				i = RKCommonFunctions::quoteEndPosition (c, context_line, i + 1);
+				if (i < 0) break;
+				continue;
+			} else if (c == '\\') {
+				++i;
+				continue;
+			} else if (c == '(') {
+				unclosed_braces.append (i);
+			} else if (c == ')') {
+				if (!unclosed_braces.isEmpty()) unclosed_braces.pop_back ();
 			}
 		}
 	}
 
+	int potential_symbol_end = unclosed_braces.isEmpty () ? -1 : unclosed_braces.last () - 1;
+
 	// now find out where the symbol to the left of the opening brace ends
 	// there cannot be a line-break between the opening brace, and the symbol name (or can there?), so no need to fetch further context
 	while ((potential_symbol_end >= 0) && full_context.at (potential_symbol_end).isSpace ()) {



More information about the rkward-tracker mailing list