From kde-commits Tue Oct 25 20:13:52 2016 From: Thomas Friedrichsmeier Date: Tue, 25 Oct 2016 20:13:52 +0000 To: kde-commits Subject: [rkward/frameworks] /: Make fucnction argument hinting more robust against quotes. Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=147742644027335 Git commit 86fb0a7586f55c6d82a0c48331ef680a9a1d2f7a by Thomas Friedrichsmei= er. 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/rkcommonfuncti= ons.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, i= nt from) { + int line_end =3D haystack.length () - 1; + for (int i=3Dfrom; i <=3D line_end; ++i) { + QChar c =3D haystack.at (i); + if (c =3D=3D quote_char) return i; + if (c =3D=3D '\\') { + ++i; + continue; + } + } + return -1; // quote end not found + } + void getCurrentSymbolOffset (const QString &context_line, int cursor_pos,= bool strict, int *start, int *end) { *start =3D 0; = @@ -120,22 +133,16 @@ namespace RKCommonFunctions { *end =3D line_end + 1; if (cursor_pos > line_end) cursor_pos =3D line_end; = - QChar quote_char; for (int i=3D0; i <=3D line_end; ++i) { QChar c =3D context_line.at (i); - if (!quote_char.isNull ()) { - if (c =3D=3D '\\') ++i; - if (c =3D=3D quote_char) quote_char =3D QChar (); + if (c =3D=3D '\'' || c =3D=3D '\"' || c =3D=3D '`') { + i =3D quoteEndPosition (c, context_line, i+1); + if (i < 0) break; continue; - } else { - if (c =3D=3D '\'' || c =3D=3D '\"' || c =3D=3D '`') { - quote_char =3D c; - continue; - } else if (c.isLetterOrNumber () || c =3D=3D '.' || c =3D=3D '_') { - continue; - } else if (!strict) { - if (c =3D=3D '$' || c =3D=3D ':' || c =3D=3D '[' || c =3D=3D ']' || c= =3D=3D '@') continue; - } + } else if (c.isLetterOrNumber () || c =3D=3D '.' || c =3D=3D '_') { + continue; + } else if (!strict) { + if (c =3D=3D '$' || c =3D=3D ':' || c =3D=3D '[' || c =3D=3D ']' || c = =3D=3D '@') 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/rkcommonfunction= s.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 + 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 QStrin= g &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, i= nt from =3D 0); = /** given the context line, find what looks like an R symbol */ QString getCurrentSymbol (const QString &context_line, int cursor_pos, bo= ol strict=3Dtrue); diff --git a/rkward/windows/rkcommandeditorwindow.cpp b/rkward/windows/rkco= mmandeditorwindow.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 =3D -1; - int brace_level =3D 1; - int potential_symbol_end =3D -1; + QList unclosed_braces; QString full_context; - while (potential_symbol_end < 0) { + while (unclosed_braces.isEmpty ()) { QString context_line =3D provider->provideContext (++line_rev); if (context_line.isNull ()) break; - full_context.prepend (context_line); - int pos =3D context_line.length (); - while (--pos >=3D 0) { - QChar c =3D full_context.at (pos); - if (c =3D=3D ')') ++brace_level; - else if (c =3D=3D '(') { - --brace_level; - if (brace_level =3D=3D 0) { - potential_symbol_end =3D pos - 1; - break; - } + for (int i =3D 0; i < context_line.length (); ++i) { + QChar c =3D context_line.at (i); + if (c =3D=3D '"' || c =3D=3D '\'' || c =3D=3D '`') { // NOTE: this alg= o does not produce good results on string constants spanning newlines. + i =3D RKCommonFunctions::quoteEndPosition (c, context_line, i + 1); + if (i < 0) break; + continue; + } else if (c =3D=3D '\\') { + ++i; + continue; + } else if (c =3D=3D '(') { + unclosed_braces.append (i); + } else if (c =3D=3D ')') { + if (!unclosed_braces.isEmpty()) unclosed_braces.pop_back (); } } } = + int potential_symbol_end =3D unclosed_braces.isEmpty () ? -1 : unclosed_b= races.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 >=3D 0) && full_context.at (potential_symbol= _end).isSpace ()) {