Dear Reviewer of this pull request. The suggested pull request improves the outline facilitities for R using geany. First it is now possible also to use the = sign as the assignment operator for functions, secondly I added support for R6Class(es), environments (new.env) and a generic RxClass which can be used as well for outline creation. The latter allows for instance to write workaround code like RxClass = proto # and then obj=RxClass() th Best regards, Detlef Groth You can view, comment on, or merge this pull request online at:
https://github.com/geany/geany/pull/2376
-- Commit Summary --
* R outline improved for environments and R6 classes, = sign added as well
-- File Changes --
M ctags/parsers/r.c (73) M src/symbols.c (4) M src/tagmanager/tm_parser.c (1)
-- Patch Links --
https://github.com/geany/geany/pull/2376.patch https://github.com/geany/geany/pull/2376.diff
Please push the changes upstream to Universal Ctags, we are trying to not diverge from those, otherwise updating to there improvements is difficult.
we are trying to not diverge from those
Too late:
```diff --- r-geany.c 2019-10-21 16:54:35.032407824 -0700 +++ r-upstream.c 2019-10-21 16:53:25.426404697 -0700 @@ -19,10 +19,10 @@
#include "debug.h" #include "entry.h" +#include "parse.h" #include "read.h" +#include "selectors.h" #include "vstring.h" -#include "routines.h" -
#define SKIPSPACE(ch) while (isspace((int)*ch)) \ ch++ @@ -31,22 +31,27 @@ K_FUNCTION, K_LIBRARY, K_SOURCE, + K_GLOBALVAR, + K_FUNCVAR, KIND_COUNT } rKind;
-static kindDefinition RKinds [KIND_COUNT] = { +static kindDefinition RKinds[KIND_COUNT] = { {true, 'f', "function", "functions"}, {true, 'l', "library", "libraries"}, {true, 's', "source", "sources"}, + {true, 'g', "globalVar", "global variables"}, + {true, 'v', "functionVar", "function variables"}, };
static void makeRTag (const vString * const name, rKind kind) { tagEntryInfo e; - initTagEntry(&e, vStringValue(name), kind);
Assert (kind < KIND_COUNT);
+ initTagEntry (&e, vStringValue (name), kind); + makeTagEntry (&e); }
@@ -66,93 +71,124 @@ { /* iterate to the end of line or to a comment */ ikind = -1; - switch (*cp) { - case 'l': - case 's': - if (strncasecmp((const char*)cp, "library", (size_t)7) == 0) { - /* load a library: library(tools) */ - cp += 7; - SKIPSPACE(cp); - if (*cp == '(') - ikind = K_LIBRARY; - else - cp -= 7; - } else if (strncasecmp((const char*)cp, "source", (size_t)6) == 0) { - /* load a source file: source("myfile.r") */ - cp += 6; - SKIPSPACE(cp); - if (*cp == '(') - ikind = K_SOURCE; - else - cp -= 6; - } - if (ikind != -1) { + switch (*cp) + { + case 'l': + case 's': + if (strncasecmp ((const char *) cp, "library", (size_t) 7) == 0) + { + /* load a library: library(tools) */ + cp += 7; + SKIPSPACE (cp); + if (*cp == '(') + ikind = K_LIBRARY; + else + cp -= 7; + } + else if (strncasecmp ((const char *) cp, "source", + (size_t) 6) == 0) + { + /* load a source file: source("myfile.r") */ + cp += 6; + SKIPSPACE (cp); + if (*cp == '(') + ikind = K_SOURCE; + else + cp -= 6; + } + if (ikind != -1) + { + cp++; + + vStringClear (name); + while ((!isspace ((int) *cp)) && *cp != '\0' && *cp != ')') + { + vStringPut (name, (int) *cp); cp++; + } + + /* if the string really exists, make a tag of it */ + if (vStringLength (name) > 0) + makeRTag (name, ikind); + + /* prepare for the next iteration */ + vStringClear (name); + } + else + { + vStringPut (name, (int) *cp); + cp++; + } + break; + case '<': + cp++; + if (*cp == '-') + { + /* assignment: ident <- someval */ + cp++; + SKIPSPACE (cp);
- vStringClear(name); - while ((!isspace((int)*cp)) && *cp != '\0' && *cp != ')') { - vStringPut(name, (int)*cp); - cp++; + if (*cp == '\0') + { + /* not in this line, read next */ + /* sometimes functions are declared this way: + * ident <- + * function(...) + * { + * ... + * } + * I don't know if there is a reason to write the function keyword + * in a new line + */ + if ((line = readLineFromInputFile ()) != NULL) + { + cp = (const unsigned char *) line; + SKIPSPACE (cp); } + else + break; + }
+ if (strncasecmp ((const char *) cp, "function", + (size_t) 8) == 0) + { + /* it's a function: ident <- function(args) */ + cp += 8; /* if the string really exists, make a tag of it */ - if (vStringLength(name) > 0) - makeRTag(name, ikind); + if (vStringLength (name) > 0) + makeRTag (name, K_FUNCTION);
/* prepare for the next iteration */ - vStringClear(name); - } else { - vStringPut(name, (int)*cp); - cp++; + vStringClear (name); + break; } - break; - case '<': - cp++; - if (*cp == '-') { - /* assignment: ident <- someval */ - cp++; - SKIPSPACE(cp); - - if (*cp == '\0') { - /* not in this line, read next */ - /* sometimes functions are declared this way: - ident <- - function(...) - { - ... - } - I don't know if there is a reason to write the function keyword - in a new line - */ - if ((line = readLineFromInputFile()) != NULL) { - cp = (const unsigned char*)line; - SKIPSPACE(cp); - } + else + { + /* it's a variable: ident <- value */ + /* if the string really exists, make a tag of it */ + if (vStringLength (name) > 0) + { + if (line[0] == ' ' || line[0] == '\t') + makeRTag (name, K_FUNCVAR); + else + makeRTag (name, K_GLOBALVAR); }
- if (strncasecmp((const char*)cp, "function", (size_t)8) == 0) { - /* it's a function: ident <- function(args) */ - cp += 8; - /* if the string really exists, make a tag of it */ - if (vStringLength(name) > 0) - makeRTag(name, K_FUNCTION); - - /* prepare for the next iteration */ - vStringClear(name); - break; - } + /* prepare for the next iteration */ + vStringClear (name); + break; } - /* fall through */ - case ' ': - case '\x009': - /* skip whitespace */ - cp++; - break; - default: - /* collect all characters that could be a part of an identifier */ - vStringPut(name, (int)*cp); - cp++; - break; + } + case ' ': + case '\x009': + /* skip whitespace */ + cp++; + break; + default: + /* collect all characters that could be a part of an identifier */ + vStringPut (name, (int) *cp); + cp++; + break; } } } @@ -163,14 +199,17 @@
extern parserDefinition *RParser (void) { - /* *.r: R files + /* *.r;*.R: R files * *.s;*.q: S files */ - static const char *const extensions [] = { "r", "s", "q", NULL }; + static const char *const extensions[] = { "r", "R", "s", "q", NULL }; parserDefinition *const def = parserNew ("R"); - def->kindTable = RKinds; - def->kindCount = ARRAY_SIZE (RKinds); + static selectLanguage selectors[] = { selectByArrowOfR, + NULL }; def->extensions = extensions; - def->parser = createRTags; + def->kindTable = RKinds; + def->kindCount = KIND_COUNT; + def->parser = createRTags; + def->selectLanguage = selectors; return def; } ```
That just shows there is a difference.
Its not unexpected that upstream has diverged from __us__ since it takes forever to get changes incorporated in Geany since nobody (including me) will review and test them.
Or to put it another way, we should not make changes to Geany ctags parsers that are not made in upstream, changes in upstream are to be expected and we want to be able to import them simply, which won't happen if we also have changes.
changes in upstream are to be expected and we want to be able to import them simply
Yeah, but should backporting/integrating/vetting all the upstream changes back into Geany be something a contributor working off our fork (necessarily, since they're hacking on Geany) should be responsible for? It would be different if we kept our fork up-to-date.
Well its up to them of course, but making it harder will probably mean things go slower for everybody, not just them.
So basically I have to fork universal-ctags/ctags put my extensions in and make a pull request there if I would like to have support for the = sign and R6Class syntax in geany at some point later?
@mittelmark you don't __have__ to, but as I said ctags stuff is not happening very fast ATM because the main reviewer is overloaded (mostly by real life, not just Geany).
If the change applies cleanly to Geany's parser after its accepted upstream it might move quicker here since it doesn't need the overloaded ctags expert to review it, and somebody else might do so and merge it. The changes to the symbols mapping don't apply to upstream of course so they would need a local review, but its much smaller that way.
@mittelmark, I'm rewriting R parser in token oriented way in the upstream. https://github.com/universal-ctags/ctags/pull/2452
The support for assignment operators is improved. It includes '->'. The class supports come later. However, if test cases are given, I would like to merge your change.
u-ctags now supports R6Class(x) ( and setClass() ). See https://github.com/universal-ctags/ctags/pull/2671.
github-comments@lists.geany.org