diff --git a/Tmain/ptag-in-optlib-parser.d/stdout-expected.txt b/Tmain/ptag-in-optlib-parser.d/stdout-expected.txt index 41719bce88..932f3c16b3 100644 --- a/Tmain/ptag-in-optlib-parser.d/stdout-expected.txt +++ b/Tmain/ptag-in-optlib-parser.d/stdout-expected.txt @@ -8,8 +8,9 @@ !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ !_TAG_KIND_DESCRIPTION!Sh a,alias /aliases/ !_TAG_KIND_DESCRIPTION!Sh f,function /functions/ -!_TAG_KIND_DESCRIPTION!Sh h,heredoc /label for here document/ +!_TAG_KIND_DESCRIPTION!Sh h,heredoc /labels for here document/ !_TAG_KIND_DESCRIPTION!Sh s,script /script files/ +!_TAG_KIND_DESCRIPTION!Sh v,variable /variables assigment (experimental)/ !_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/ !_TAG_OUTPUT_FILESEP slash /slash or backslash/ !_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ diff --git a/Units/parser-sh.r/sh-comments.d/expected.tags b/Units/parser-sh.r/sh-comments.d/expected.tags index 0cb132b138..48532f69de 100644 --- a/Units/parser-sh.r/sh-comments.d/expected.tags +++ b/Units/parser-sh.r/sh-comments.d/expected.tags @@ -2,3 +2,7 @@ afterpound1 input.sh /^foo="#"; afterpound1() {}$/;" f afterpound2 input.sh /^foo="#\\""; afterpound2() {}$/;" f afterpound3 input.sh /^foo='#'; afterpound3() {}$/;" f afterpound4 input.sh /^foo='#'''; afterpound4() {}$/;" f +foo input.sh /^foo="#"; afterpound1() {}$/;" v +foo input.sh /^foo="#\\""; afterpound2() {}$/;" v +foo input.sh /^foo='#'''; afterpound4() {}$/;" v +foo input.sh /^foo='#'; afterpound3() {}$/;" v diff --git a/Units/parser-sh.r/sh-quotes.d/expected.tags b/Units/parser-sh.r/sh-quotes.d/expected.tags index 0cb132b138..1c71b53595 100644 --- a/Units/parser-sh.r/sh-quotes.d/expected.tags +++ b/Units/parser-sh.r/sh-quotes.d/expected.tags @@ -2,3 +2,8 @@ afterpound1 input.sh /^foo="#"; afterpound1() {}$/;" f afterpound2 input.sh /^foo="#\\""; afterpound2() {}$/;" f afterpound3 input.sh /^foo='#'; afterpound3() {}$/;" f afterpound4 input.sh /^foo='#'''; afterpound4() {}$/;" f +foo input.sh /^foo="#"; afterpound1() {}$/;" v +foo input.sh /^foo="#\\""; afterpound2() {}$/;" v +foo input.sh /^foo="nofunction()"$/;" v +foo input.sh /^foo='#'''; afterpound4() {}$/;" v +foo input.sh /^foo='#'; afterpound3() {}$/;" v diff --git a/parsers/sh.c b/parsers/sh.c index df25ad9673..d8c4634ebf 100644 --- a/parsers/sh.c +++ b/parsers/sh.c @@ -38,6 +38,7 @@ typedef enum { K_FUNCTION, K_SCRIPT, K_HEREDOCLABEL, + K_VARIABLE, } shKind; typedef enum { @@ -86,8 +87,10 @@ static roleDefinition ZshFunctionRoles [] = { .referenceOnly = false, FUNCTION_ROLES_SPEC }, \ { true, 's', "script", "script files", \ .referenceOnly = true, ATTACH_ROLES (SCRIPT_ROLES) }, \ - { true, 'h', "heredoc", "label for here document", \ - .referenceOnly = false, ATTACH_ROLES (HEREDOC_ROLES) } + { true, 'h', "heredoc", "labels for here document", \ + .referenceOnly = false, ATTACH_ROLES (HEREDOC_ROLES) }, \ + { true, 'v', "variable", "variables assigment (experimental)" } + static kindDefinition ShKinds [] = { SH_KINDS_COMMON(ShScriptRoles, ShHeredocRoles,), @@ -456,6 +459,53 @@ static size_t handleZshKeyword (int keyword, return vStringLength(token); } +static bool doesLineCotinue(const unsigned char *start, const unsigned char *cp) +{ + cp--; + if (start >= cp) + return false; + + if (*cp != '\\') + return false; + + while (start < cp) + { + if (*cp == ';' || *cp == '|' || *cp == '&') + return false; + else if (isspace(*cp)) + cp--; + else + return true; + } + return false; +} + +static bool handleVariableAssignment (vString *input) +{ + const char *base = vStringValue (input); + const char *cp = base; + + while (*cp != '\0') + { + if (*cp == '=') + { + size_t len = cp - base; + if (len > 0) + { + vStringTruncate (input, len); + return true; + } + break; + } + else if ( ((cp == base)? + isIdentChar0: isIdentChar) ((unsigned char)*cp) ) + cp++; + else + break; + } + return false; +} + typedef bool (* checkCharFunc) (int); static void findShTagsCommon (size_t (* keyword_handler) (int, vString *, @@ -474,6 +524,7 @@ static void findShTagsCommon (size_t (* keyword_handler) (int, struct hereDocParsingState hstate; hdocStateInit (&hstate); + bool cont_line = false; while ((line = readLineFromInputFile ()) != NULL) { const unsigned char* cp = line; @@ -499,10 +550,12 @@ static void findShTagsCommon (size_t (* keyword_handler) (int, vStringDelete (hereDocDelimiter); hereDocDelimiter = NULL; } + cont_line = false; continue; } hdocStateClear (&hstate); + bool beginning_of_line = !cont_line; while (*cp != '\0') { subparser *sub = NULL; @@ -640,6 +693,7 @@ static void findShTagsCommon (size_t (* keyword_handler) (int, cp += d; else if (*cp != '\0') ++cp; + beginning_of_line = false; continue; } @@ -653,8 +707,9 @@ static void findShTagsCommon (size_t (* keyword_handler) (int, while (isspace ((int) *cp)) ++cp; - if ((found_kind != K_SCRIPT) - && *cp == '(') + if (found_kind == K_SCRIPT) + ; /* Do NOTHING */ + else if (*cp == '(') { ++cp; while (isspace ((int) *cp)) @@ -680,6 +735,10 @@ static void findShTagsCommon (size_t (* keyword_handler) (int, ++cp; } } + else if (beginning_of_line + && found_kind == K_NOTHING + && handleVariableAssignment (name)) + found_kind = K_VARIABLE; if (found_kind != K_NOTHING) { @@ -696,7 +755,11 @@ static void findShTagsCommon (size_t (* keyword_handler) (int, else if (!hereDocDelimiter) hdocStateUpdateArgs (&hstate, name); vStringClear (name); + beginning_of_line = false; } + if (*cp == '#') + cont_line = false; + cont_line = doesLineCotinue (line, cp); } hdocStateFini (&hstate); vStringDelete (name);