[geany/geany] 8a6fbd: Add PowerShell tag parser
Enrico Tröger
git-noreply at xxxxx
Sun Jun 28 13:46:23 UTC 2015
Branch: refs/heads/master
Author: Enrico Tröger <enrico.troeger at uvena.de>
Committer: Enrico Tröger <enrico.troeger at uvena.de>
Date: Sun, 28 Jun 2015 13:46:23 UTC
Commit: 8a6fbd978691fa324bd5c5ff171bcd508e3b466c
https://github.com/geany/geany/commit/8a6fbd978691fa324bd5c5ff171bcd508e3b466c
Log Message:
-----------
Add PowerShell tag parser
Modified Paths:
--------------
src/filetypes.c
src/symbols.c
tagmanager/ctags/Makefile.am
tagmanager/ctags/makefile.win32
tagmanager/ctags/parsers.h
tagmanager/ctags/powershell.c
tagmanager/src/tm_parser.h
tests/ctags/Makefile.am
tests/ctags/simple.ps1
tests/ctags/simple.ps1.tags
wscript
Modified: src/filetypes.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -188,7 +188,7 @@ static void init_builtin_filetypes(void)
FT_INIT( ASCIIDOC, ASCIIDOC, "Asciidoc", NULL, SOURCE_FILE, MARKUP );
FT_INIT( ABAQUS, ABAQUS, "Abaqus", NULL, SOURCE_FILE, SCRIPT );
FT_INIT( BATCH, NONE, "Batch", NULL, SCRIPT, SCRIPT );
- FT_INIT( POWERSHELL, NONE, "PowerShell", NULL, SOURCE_FILE, SCRIPT );
+ FT_INIT( POWERSHELL, POWERSHELL, "PowerShell", NULL, SOURCE_FILE, SCRIPT );
FT_INIT( RUST, RUST, "Rust", NULL, SOURCE_FILE, COMPILED );
FT_INIT( COFFEESCRIPT, NONE, "CoffeeScript", NULL, SOURCE_FILE, SCRIPT );
FT_INIT( GO, GO, "Go", NULL, SOURCE_FILE, COMPILED );
Modified: src/symbols.c
3 lines changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -286,7 +286,7 @@ GString *symbols_find_typenames_as_string(gint lang, gboolean global)
* type.
* @param ft_id File type identifier.
* @return The context separator string.
- *
+ *
* Returns non-printing sequence "\x03" ie ETX (end of text) for filetypes
* without a context separator.
*
@@ -302,6 +302,7 @@ const gchar *symbols_get_context_separator(gint ft_id)
case GEANY_FILETYPES_GLSL: /* for structs */
/*case GEANY_FILETYPES_RUBY:*/ /* not sure what to use atm*/
case GEANY_FILETYPES_PHP:
+ case GEANY_FILETYPES_POWERSHELL:
case GEANY_FILETYPES_RUST:
case GEANY_FILETYPES_ZEPHIR:
return "::";
Modified: tagmanager/ctags/Makefile.am
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -43,6 +43,7 @@ parsers = \
pascal.c \
perl.c \
php.c \
+ powershell.c \
python.c \
r.c \
rest.c \
Modified: tagmanager/ctags/makefile.win32
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -45,7 +45,7 @@ clean:
-$(RM) deps.mak *.o $(COMPLIB)
$(COMPLIB): abaqus.o abc.o args.o c.o cobol.o erlang.o fortran.o make.o conf.o pascal.o perl.o php.o diff.o vhdl.o verilog.o lua.o js.o json.o \
-actionscript.o nsis.o objc.o \
+actionscript.o nsis.o objc.o powershell.c \
haskell.o haxe.o html.o python.o lregex.o asciidoc.o rest.o sh.o ctags.o entry.o get.o keyword.o nestlevel.o \
options.o \
parse.o basic.o read.o sort.o strlist.o latex.o markdown.o matlab.o docbook.o tcl.o ruby.o rust.o asm.o sql.o txt2tags.o css.o \
Modified: tagmanager/ctags/parsers.h
3 lines changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -65,7 +65,8 @@
RustParser, \
GoParser, \
JsonParser, \
- ZephirParser
+ ZephirParser, \
+ PowerShellParser
#endif /* _PARSERS_H */
Modified: tagmanager/ctags/powershell.c
628 lines changed, 628 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,628 @@
+/*
+* Copyright (c) 2015, Enrico Tröger <enrico.troeger at uvena.de>
+*
+* Loosely based on the PHP tags parser since the syntax is somewhat similar
+* regarding variable and function definitions.
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* This module contains code for generating tags for Windows PowerShell scripts.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+#include "main.h"
+#include "parse.h"
+#include "read.h"
+#include "vstring.h"
+#include "keyword.h"
+#include "entry.h"
+#include <string.h>
+
+#define SCOPE_SEPARATOR "::"
+
+
+#define ARRAY_LENGTH(array) (sizeof array / sizeof array[0])
+
+#define ACCESS_UNDEFINED NULL
+static const char *const accessTypes[] = {
+ ACCESS_UNDEFINED,
+ "global",
+ "local",
+ "script",
+ "private"
+};
+
+typedef enum {
+ K_FUNCTION,
+ K_VARIABLE,
+ COUNT_KIND
+} powerShellKind;
+
+static kindOption PowerShellKinds[COUNT_KIND] = {
+ { TRUE, 'f', "function", "functions" },
+ { TRUE, 'v', "variable", "variables" }
+};
+
+
+typedef enum eTokenType {
+ TOKEN_UNDEFINED,
+ TOKEN_EOF,
+ TOKEN_CLOSE_PAREN,
+ TOKEN_SEMICOLON,
+ TOKEN_COLON,
+ TOKEN_COMMA,
+ TOKEN_KEYWORD,
+ TOKEN_OPEN_PAREN,
+ TOKEN_OPERATOR,
+ TOKEN_IDENTIFIER,
+ TOKEN_STRING,
+ TOKEN_PERIOD,
+ TOKEN_OPEN_CURLY,
+ TOKEN_CLOSE_CURLY,
+ TOKEN_EQUAL_SIGN,
+ TOKEN_OPEN_SQUARE,
+ TOKEN_CLOSE_SQUARE,
+ TOKEN_VARIABLE
+} tokenType;
+
+typedef struct {
+ tokenType type;
+ vString * string;
+ vString * scope;
+ unsigned long lineNumber;
+ MIOPos filePosition;
+ int parentKind; /* -1 if none */
+} tokenInfo;
+
+
+static const char *findValidAccessType (const char *const access)
+{
+ unsigned int i;
+ if (access == ACCESS_UNDEFINED)
+ return ACCESS_UNDEFINED; /* early out to save the for-loop if possible */
+ for (i = 0; i < ARRAY_LENGTH(accessTypes); i++)
+ {
+ if (accessTypes[i] == ACCESS_UNDEFINED)
+ continue;
+ if (strcasecmp (access, accessTypes[i]) == 0)
+ return accessTypes[i];
+ i++;
+ }
+ return ACCESS_UNDEFINED;
+}
+
+static void initPowerShellEntry (tagEntryInfo *const e, const tokenInfo *const token,
+ const powerShellKind kind, const char *const access)
+{
+ initTagEntry (e, vStringValue (token->string));
+
+ e->lineNumber = token->lineNumber;
+ e->filePosition = token->filePosition;
+ e->kindName = PowerShellKinds[kind].name;
+ e->kind = (char) PowerShellKinds[kind].letter;
+
+ if (access != NULL)
+ e->extensionFields.access = access;
+ if (vStringLength (token->scope) > 0)
+ {
+ int parentKind = token->parentKind;
+ Assert (parentKind >= 0);
+
+ e->extensionFields.scope[0] = PowerShellKinds[parentKind].name;
+ e->extensionFields.scope[1] = vStringValue (token->scope);
+ }
+}
+
+static void makeSimplePowerShellTag (const tokenInfo *const token, const powerShellKind kind,
+ const char *const access)
+{
+ if (PowerShellKinds[kind].enabled)
+ {
+ tagEntryInfo e;
+
+ initPowerShellEntry (&e, token, kind, access);
+ makeTagEntry (&e);
+ }
+}
+
+static void makeFunctionTag (const tokenInfo *const token, const vString *const arglist,
+ const char *const access)
+{
+ if (PowerShellKinds[K_FUNCTION].enabled)
+ {
+ tagEntryInfo e;
+
+ initPowerShellEntry (&e, token, K_FUNCTION, access);
+
+ if (arglist)
+ e.extensionFields.arglist = vStringValue (arglist);
+
+ makeTagEntry (&e);
+ }
+}
+
+static tokenInfo *newToken (void)
+{
+ tokenInfo *const token = xMalloc (1, tokenInfo);
+
+ token->type = TOKEN_UNDEFINED;
+ token->string = vStringNew ();
+ token->scope = vStringNew ();
+ token->lineNumber = getSourceLineNumber ();
+ token->filePosition = getInputFilePosition ();
+ token->parentKind = -1;
+
+ return token;
+}
+
+static void deleteToken (tokenInfo *const token)
+{
+ vStringDelete (token->string);
+ vStringDelete (token->scope);
+ eFree (token);
+}
+
+static void copyToken (tokenInfo *const dest, const tokenInfo *const src,
+ boolean scope)
+{
+ dest->lineNumber = src->lineNumber;
+ dest->filePosition = src->filePosition;
+ dest->type = src->type;
+ vStringCopy (dest->string, src->string);
+ dest->parentKind = src->parentKind;
+ if (scope)
+ vStringCopy (dest->scope, src->scope);
+}
+
+static void addToScope (tokenInfo *const token, const vString *const extra)
+{
+ if (vStringLength (token->scope) > 0)
+ vStringCatS (token->scope, SCOPE_SEPARATOR);
+ vStringCatS (token->scope, vStringValue (extra));
+ vStringTerminate (token->scope);
+}
+
+static boolean isIdentChar (const int c)
+{
+ return (isalnum (c) || c == ':' || c == '_' || c == '-' || c >= 0x80);
+}
+
+static int skipToCharacter (const int c)
+{
+ int d;
+ do
+ {
+ d = fileGetc ();
+ } while (d != EOF && d != c);
+ return d;
+}
+
+static void parseString (vString *const string, const int delimiter)
+{
+ while (TRUE)
+ {
+ int c = fileGetc ();
+
+ if (c == '\\' && (c = fileGetc ()) != EOF)
+ vStringPut (string, (char) c);
+ else if (c == EOF || c == delimiter)
+ break;
+ else
+ vStringPut (string, (char) c);
+ }
+ vStringTerminate (string);
+}
+
+static void parseIdentifier (vString *const string, const int firstChar)
+{
+ int c = firstChar;
+ do
+ {
+ vStringPut (string, (char) c);
+ c = fileGetc ();
+ } while (isIdentChar (c));
+ fileUngetc (c);
+ vStringTerminate (string);
+}
+
+static boolean isTokenFunction (vString *const name)
+{
+ return (strcasecmp (vStringValue (name), "function") == 0 ||
+ strcasecmp (vStringValue (name), "filter") == 0);
+}
+
+static boolean isSpace (int c)
+{
+ return (c == '\t' || c == ' ' || c == '\v' ||
+ c == '\n' || c == '\r' || c == '\f');
+}
+
+static int skipWhitespaces (int c)
+{
+ while (isSpace (c))
+ c = fileGetc ();
+ return c;
+}
+
+static int skipSingleComment (void)
+{
+ int c;
+ do
+ {
+ c = fileGetc ();
+ if (c == '\r')
+ {
+ int next = fileGetc ();
+ if (next != '\n')
+ fileUngetc (next);
+ else
+ c = next;
+ }
+ } while (c != EOF && c != '\n' && c != '\r');
+ return c;
+}
+
+static void readToken (tokenInfo *const token)
+{
+ int c;
+
+ token->type = TOKEN_UNDEFINED;
+ vStringClear (token->string);
+
+getNextChar:
+
+ c = fileGetc ();
+ c = skipWhitespaces (c);
+
+ token->lineNumber = getSourceLineNumber ();
+ token->filePosition = getInputFilePosition ();
+
+ switch (c)
+ {
+ case EOF: token->type = TOKEN_EOF; break;
+ case '(': token->type = TOKEN_OPEN_PAREN; break;
+ case ')': token->type = TOKEN_CLOSE_PAREN; break;
+ case ';': token->type = TOKEN_SEMICOLON; break;
+ case ',': token->type = TOKEN_COMMA; break;
+ case '.': token->type = TOKEN_PERIOD; break;
+ case ':': token->type = TOKEN_COLON; break;
+ case '{': token->type = TOKEN_OPEN_CURLY; break;
+ case '}': token->type = TOKEN_CLOSE_CURLY; break;
+ case '[': token->type = TOKEN_OPEN_SQUARE; break;
+ case ']': token->type = TOKEN_CLOSE_SQUARE; break;
+ case '=': token->type = TOKEN_EQUAL_SIGN; break;
+
+ case '\'':
+ case '"':
+ token->type = TOKEN_STRING;
+ parseString (token->string, c);
+ token->lineNumber = getSourceLineNumber ();
+ token->filePosition = getInputFilePosition ();
+ break;
+
+ case '<':
+ {
+ int d = fileGetc ();
+ if (d == '#')
+ {
+ /* <# ... #> multiline comment */
+ do
+ {
+ c = skipToCharacter ('#');
+ if (c != EOF)
+ {
+ c = fileGetc ();
+ if (c == '>')
+ break;
+ else
+ fileUngetc (c);
+ }
+ } while (c != EOF);
+ goto getNextChar;
+ }
+ else
+ {
+ fileUngetc (d);
+ token->type = TOKEN_UNDEFINED;
+ }
+ break;
+ }
+
+ case '#': /* comment */
+ skipSingleComment ();
+ goto getNextChar;
+ break;
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ {
+ int d = fileGetc ();
+ if (d != '=')
+ fileUngetc (d);
+ token->type = TOKEN_OPERATOR;
+ break;
+ }
+
+ case '$': /* variable start */
+ {
+ int d = fileGetc ();
+ if (! isIdentChar (d))
+ {
+ fileUngetc (d);
+ token->type = TOKEN_UNDEFINED;
+ }
+ else
+ {
+ parseIdentifier (token->string, d);
+ token->type = TOKEN_VARIABLE;
+ }
+ break;
+ }
+
+ default:
+ if (! isIdentChar (c))
+ token->type = TOKEN_UNDEFINED;
+ else
+ {
+ parseIdentifier (token->string, c);
+ if (isTokenFunction (token->string))
+ token->type = TOKEN_KEYWORD;
+ else
+ token->type = TOKEN_IDENTIFIER;
+ }
+ break;
+ }
+}
+
+static void enterScope (tokenInfo *const parentToken,
+ const vString *const extraScope,
+ const int parentKind);
+
+/* strip a possible PowerShell scope specification and convert it to accessType */
+static const char *parsePowerShellScope (tokenInfo *const token)
+{
+ const char *access = ACCESS_UNDEFINED;
+ const char *const tokenName = vStringValue (token->string);
+ const char *powershellScopeEnd;
+
+ powershellScopeEnd = strchr (tokenName, ':');
+ if (powershellScopeEnd)
+ {
+ size_t powershellScopeLen;
+ vString * powershellScope = vStringNew ();
+
+ powershellScopeLen = (size_t)(powershellScopeEnd - tokenName);
+ /* extract the scope */
+ vStringNCopyS (powershellScope, tokenName, powershellScopeLen);
+ vStringTerminate (powershellScope);
+ /* cut the resulting scope string from the identifier */
+ memmove (token->string->buffer,
+ /* +1 to skip the leading colon */
+ token->string->buffer + powershellScopeLen + 1,
+ /* +1 for the skipped leading colon and - 1 to include the trailing \0 byte */
+ token->string->length + 1 - powershellScopeLen - 1);
+ token->string->length -= powershellScopeLen + 1;
+
+ access = findValidAccessType (vStringValue (powershellScope));
+
+ vStringDelete (powershellScope);
+ }
+ return access;
+}
+
+
+/* parse a function
+ *
+ * function myfunc($foo, $bar) {}
+ */
+static boolean parseFunction (tokenInfo *const token)
+{
+ boolean readNext = TRUE;
+ tokenInfo *nameFree = NULL;
+ const char *access;
+
+ readToken (token);
+
+ if (token->type != TOKEN_IDENTIFIER)
+ return FALSE;
+
+ access = parsePowerShellScope (token);
+
+ nameFree = newToken ();
+ copyToken (nameFree, token, TRUE);
+ readToken (token);
+
+ if (token->type == TOKEN_OPEN_PAREN)
+ {
+ vString *arglist = vStringNew ();
+ int depth = 1;
+
+ vStringPut (arglist, '(');
+ do
+ {
+ readToken (token);
+
+ switch (token->type)
+ {
+ case TOKEN_OPEN_PAREN: depth++; break;
+ case TOKEN_CLOSE_PAREN: depth--; break;
+ default: break;
+ }
+ /* display part */
+ switch (token->type)
+ {
+ case TOKEN_CLOSE_CURLY: vStringPut (arglist, '}'); break;
+ case TOKEN_CLOSE_PAREN: vStringPut (arglist, ')'); break;
+ case TOKEN_CLOSE_SQUARE: vStringPut (arglist, ']'); break;
+ case TOKEN_COLON: vStringPut (arglist, ':'); break;
+ case TOKEN_COMMA: vStringCatS (arglist, ", "); break;
+ case TOKEN_EQUAL_SIGN: vStringCatS (arglist, " = "); break;
+ case TOKEN_OPEN_CURLY: vStringPut (arglist, '{'); break;
+ case TOKEN_OPEN_PAREN: vStringPut (arglist, '('); break;
+ case TOKEN_OPEN_SQUARE: vStringPut (arglist, '['); break;
+ case TOKEN_PERIOD: vStringPut (arglist, '.'); break;
+ case TOKEN_SEMICOLON: vStringPut (arglist, ';'); break;
+ case TOKEN_STRING: vStringCatS (arglist, "'...'"); break;
+
+ case TOKEN_IDENTIFIER:
+ case TOKEN_KEYWORD:
+ case TOKEN_VARIABLE:
+ {
+ switch (vStringLast (arglist))
+ {
+ case 0:
+ case ' ':
+ case '{':
+ case '(':
+ case '[':
+ case '.':
+ /* no need for a space between those and the identifier */
+ break;
+
+ default:
+ vStringPut (arglist, ' ');
+ break;
+ }
+ if (token->type == TOKEN_VARIABLE)
+ vStringPut (arglist, '$');
+ vStringCat (arglist, token->string);
+ break;
+ }
+
+ default: break;
+ }
+ }
+ while (token->type != TOKEN_EOF && depth > 0);
+
+ vStringTerminate (arglist);
+
+ makeFunctionTag (nameFree, arglist, access);
+ vStringDelete (arglist);
+
+ readToken (token);
+ }
+ else if (token->type == TOKEN_OPEN_CURLY)
+ { /* filters doesn't need to have an arglist */
+ makeFunctionTag (nameFree, NULL, access);
+ }
+
+ if (token->type == TOKEN_OPEN_CURLY)
+ enterScope (token, nameFree->string, K_FUNCTION);
+ else
+ readNext = FALSE;
+
+ if (nameFree)
+ deleteToken (nameFree);
+
+ return readNext;
+}
+
+/* parses declarations of the form
+ * $var = VALUE
+ */
+static boolean parseVariable (tokenInfo *const token)
+{
+ tokenInfo *name;
+ boolean readNext = TRUE;
+ const char *access;
+
+ name = newToken ();
+ copyToken (name, token, TRUE);
+
+ readToken (token);
+ if (token->type == TOKEN_EQUAL_SIGN)
+ {
+ if (token->parentKind != K_FUNCTION)
+ { /* ignore local variables (i.e. within a function) */
+ access = parsePowerShellScope (name);
+ makeSimplePowerShellTag (name, K_VARIABLE, access);
+ readNext = TRUE;
+ }
+ }
+ else
+ readNext = FALSE;
+
+ deleteToken (name);
+
+ return readNext;
+}
+
+static void enterScope (tokenInfo *const parentToken,
+ const vString *const extraScope,
+ const int parentKind)
+{
+ tokenInfo *token = newToken ();
+ int origParentKind = parentToken->parentKind;
+
+ copyToken (token, parentToken, TRUE);
+
+ if (extraScope)
+ {
+ addToScope (token, extraScope);
+ token->parentKind = parentKind;
+ }
+
+ readToken (token);
+ while (token->type != TOKEN_EOF &&
+ token->type != TOKEN_CLOSE_CURLY)
+ {
+ boolean readNext = TRUE;
+
+ switch (token->type)
+ {
+ case TOKEN_OPEN_CURLY:
+ enterScope (token, NULL, -1);
+ break;
+
+ case TOKEN_KEYWORD:
+ readNext = parseFunction (token);
+ break;
+
+ case TOKEN_VARIABLE:
+ readNext = parseVariable (token);
+ break;
+
+ default: break;
+ }
+
+ if (readNext)
+ readToken (token);
+ }
+
+ copyToken (parentToken, token, FALSE);
+ parentToken->parentKind = origParentKind;
+ deleteToken (token);
+}
+
+static void findPowerShellTags (void)
+{
+ tokenInfo *const token = newToken ();
+
+ do
+ {
+ enterScope (token, NULL, -1);
+ }
+ while (token->type != TOKEN_EOF); /* keep going even with unmatched braces */
+
+ deleteToken (token);
+}
+
+extern parserDefinition* PowerShellParser (void)
+{
+ static const char *const extensions [] = { "ps1", "psm1", NULL };
+ parserDefinition* def = parserNew ("PowerShell");
+ def->kinds = PowerShellKinds;
+ def->kindCount = KIND_COUNT (PowerShellKinds);
+ def->extensions = extensions;
+ def->parser = findPowerShellTags;
+ return def;
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
Modified: tagmanager/src/tm_parser.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -72,6 +72,7 @@ typedef enum
TM_PARSER_GO,
TM_PARSER_JSON,
TM_PARSER_ZEPHIR,
+ TM_PARSER_POWERSHELL,
TM_PARSER_COUNT
} TMParserType;
Modified: tests/ctags/Makefile.am
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -260,6 +260,7 @@ test_sources = \
simple.mak \
simple.php \
simple.pl \
+ simple.ps1 \
simple.py \
simple.rb \
simple.sh \
Modified: tests/ctags/simple.ps1
112 lines changed, 112 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,112 @@
+# pseudo #!/PowerShell :)
+#
+# test file for the CTags/Geany PowerShell tag parser
+# based on real world code but simplified for automated tests
+
+<#
+multiline comment including a function and variable, both should be ignored:
+
+$IgnoreThisVaribale = "Stop"
+
+function IgnoreThisFunction($arg1) {
+ Write-Host "dummy"
+}
+#>
+
+# immediately stop the script if an errors occurs
+$ErrorActionPreference = "Stop"
+
+# a global scoped variable
+$Global:Settings = $null
+
+# a local scoped variable
+$Local:ALocalVar = $null
+
+# a usual variable
+$BasePath = split-path -parent $Global:MyInvocation.InvocationName
+
+
+FUNCTION Read-Configuration-File() {
+ $Hostname = [System.Environment]::MachineName
+ $ConfigurationFileName = $BasePath + "\script-${Hostname}.conf"
+ LogMessage "Read configuration '${ConfigurationFileName}'"
+
+ $ConfigFileContent = Get-Content -raw $ConfigurationFileName
+ $Global:Settings = Convertfrom-Stringdata $ConfigFileContent
+}
+
+Function LogMessageOK()
+{
+ $x = [Console]::WindowWidth - 6
+ $y = [Console]::CursorTop
+ Try {
+ [Console]::setcursorposition($x, $y)
+ } Catch [system.exception] {
+ # intentionally left empty for redirect of outputs to file
+ }
+
+ Write-Host -foregroundcolor "green" "[ok]"
+}
+
+function LogMessage() {
+ param(
+ [Parameter(Mandatory=$false)][switch] $NoNewLine,
+ [Parameter(Mandatory=$true)][string] $Message
+ )
+ $Date = Get-Date -UFormat "%Y-%m-%d %T: "
+ Write-Host -foregroundcolor "yellow" -NoNewLine $Date
+
+ if ($NoNewLine) {
+ Write-Host -foregroundcolor "green" -NoNewLine $Message
+ } else {
+ Write-Host -foregroundcolor "green" $Message
+ }
+}
+
+function global:A-Global-Scope-Function() {
+ Write-Host "dummy"
+}
+
+filter Script:MyFilter {
+ filter-something
+}
+
+Filter Private:MyPrivateFilter {
+ filter-something
+}
+
+function LoadTemplate($template) {
+ # woah, this is real magic,
+ # see http://stackoverflow.com/questions/10754582/string-interpolation-of-hashtable-values-in-powershell
+
+ # Set all unbound variables (@args) in the local context
+ while ($args)
+ {
+ ($key, $val, $args) = $args
+ Set-Variable -Name $key.SubString(1, $key.Length-2) -Value $val
+ }
+ $ExecutionContext.InvokeCommand.ExpandString($template)
+}
+
+function TopLevelFunction() {
+ function SecondLevelNestedFunction() {
+ function ThirdLevelNestedFunction() {
+ doSomething()
+ }
+
+ ThirdLevelNestedFunction
+ }
+
+ SecondLevelNestedFunction
+}
+
+function Main() {
+ Read-Configuration-File
+ LogMessage $("Working on Environment '{0}'" -f $Settings["EnvironmentName"])
+
+ LogMessage "do something ..."
+ Stripped-Down-Code
+ LogMessageOK
+}
+
+Main
Modified: tests/ctags/simple.ps1.tags
16 lines changed, 16 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,16 @@
+# format=tagmanager
+A-Global-Scope-Function�16�()�0
+ALocalVar�16384�0
+BasePath�16384�0
+ErrorActionPreference�16384�0
+LoadTemplate�16�($template)�0
+LogMessage�16�()�0
+LogMessageOK�16�()�0
+Main�16�()�0
+MyFilter�16�0
+MyPrivateFilter�16�0
+Read-Configuration-File�16�()�0
+SecondLevelNestedFunction�16�()�TopLevelFunction�0
+Settings�16384�0
+ThirdLevelNestedFunction�16�()�TopLevelFunction::SecondLevelNestedFunction�0
+TopLevelFunction�16�()�0
Modified: wscript
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -106,6 +106,7 @@ ctags_sources = set([
'tagmanager/ctags/r.c',
'tagmanager/ctags/perl.c',
'tagmanager/ctags/php.c',
+ 'tagmanager/ctags/powershell.c',
'tagmanager/ctags/python.c',
'tagmanager/ctags/read.c',
'tagmanager/ctags/rest.c',
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
More information about the Commits
mailing list