[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