Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: GitHub noreply@github.com Date: Thu, 12 May 2022 23:34:21 UTC Commit: 7bd665d4e63fceda587d16e221b719b60df9b5c2 https://github.com/geany/geany/commit/7bd665d4e63fceda587d16e221b719b60df9b5...
Log Message: ----------- Merge pull request #3162 from techee/clojure_parser
Add Clojure ctags parser
Modified Paths: -------------- ctags/Makefile.am ctags/parsers/clojure.c data/filedefs/filetypes.Clojure.conf meson.build src/tagmanager/tm_parser.c src/tagmanager/tm_parser.h src/tagmanager/tm_parsers.h tests/ctags/Makefile.am tests/ctags/simple.clj tests/ctags/simple.clj.tags tests/meson.build
Modified: ctags/Makefile.am 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -50,6 +50,7 @@ parsers = \ parsers/basic.c \ parsers/bibtex.c \ parsers/geany_c.c \ + parsers/clojure.c \ parsers/cobol.c \ parsers/iniconf.c \ parsers/iniconf.h \
Modified: ctags/parsers/clojure.c 195 lines changed, 195 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2015, Miloslav Nenadál nenadalm@gmail.com + * + * This source code is released for free distribution under the terms of the + * GNU General Public License version 2 or (at your option) any later version. + * + * This module contains code for generating tags for the Clojure language. + */ + +#include "general.h" + +#include <string.h> + +#include "parse.h" +#include "read.h" +#include "routines.h" +#include "vstring.h" +#include "entry.h" + +typedef enum { + K_FUNCTION, + K_NAMESPACE +} clojureKind; + +static kindDefinition ClojureKinds[] = { + {true, 'f', "function", "functions"}, + {true, 'n', "namespace", "namespaces"} +}; + +static int isNamespace (const char *strp) +{ + return strncmp (++strp, "ns", 2) == 0 && isspace (strp[2]); +} + +static int isCoreNamespace (const char *strp) +{ + return strncmp (++strp, "clojure.core/ns", 15) == 0 && isspace (strp[15]); +} + +static int isFunction (const char *strp) +{ + return (strncmp (++strp, "defn", 4) == 0 && isspace (strp[4])); +} + +static int isCoreFunction (const char *strp) +{ + return (strncmp (++strp, "clojure.core/defn", 17) == 0 && isspace (strp[17])); +} + +static int isQuote (const char *strp) +{ + return strncmp (++strp, "quote", 5) == 0 && isspace (strp[5]); +} + +static void functionName (vString * const name, const char *dbp) +{ + const char *p; + + if (*dbp == ''') + dbp++; + else if (*dbp == '(' && isQuote (dbp)) + { + dbp += 7; + while (isspace (*dbp)) + dbp++; + } + + for (p = dbp; *p != '\0' && *p != '(' && !isspace ((int) *p) && *p != ')'; + p++) + vStringPut (name, *p); +} + +const char* skipMetadata (const char *dbp) +{ + while (1) + { + if (*dbp == '^') + { + dbp++; + if (*dbp == '{') + { + /* skipping an arraymap */ + for (; *dbp != '\0' && *dbp != '}'; dbp++) + ; + } + else + { + /* skip a keyword or a symbol */ + for (; *dbp != '\0' && !isspace((unsigned char)*dbp); dbp++) + ; + } + + if (*dbp == '\0') + break; + + dbp++; + while (isspace ((unsigned char)*dbp)) + dbp++; + } + else + break; + } + + return dbp; +} + +static int makeNamespaceTag (vString * const name, const char *dbp) +{ + dbp = skipMetadata (dbp); + functionName (name, dbp); + if (vStringLength (name) > 0 && ClojureKinds[K_NAMESPACE].enabled) + { + tagEntryInfo e; + initTagEntry (&e, vStringValue (name), K_NAMESPACE); + e.lineNumber = getInputLineNumber (); + e.filePosition = getInputFilePosition (); + + return makeTagEntry (&e); + } + else + return CORK_NIL; +} + +static void makeFunctionTag (vString * const name, const char *dbp, int scope_index) +{ + dbp = skipMetadata (dbp); + functionName (name, dbp); + if (vStringLength (name) > 0 && ClojureKinds[K_FUNCTION].enabled) + { + tagEntryInfo e; + initTagEntry (&e, vStringValue (name), K_FUNCTION); + e.lineNumber = getInputLineNumber (); + e.filePosition = getInputFilePosition (); + + e.extensionFields.scopeIndex = scope_index; + makeTagEntry (&e); + } +} + +static void skipToSymbol (const char **p) +{ + while (**p != '\0' && !isspace ((int) **p)) + *p = *p + 1; + while (isspace ((int) **p)) + *p = *p + 1; +} + +static void findClojureTags (void) +{ + vString *name = vStringNew (); + const char *p; + int scope_index = CORK_NIL; + + while ((p = (char *)readLineFromInputFile ()) != NULL) + { + vStringClear (name); + + while (isspace (*p)) + p++; + + if (*p == '(') + { + if (isNamespace (p) || isCoreNamespace (p)) + { + skipToSymbol (&p); + scope_index = makeNamespaceTag (name, p); + } + else if (isFunction (p) || isCoreFunction (p)) + { + skipToSymbol (&p); + makeFunctionTag (name, p, scope_index); + } + } + } + vStringDelete (name); +} + +extern parserDefinition *ClojureParser (void) +{ + static const char *const extensions[] = { + "clj", "cljs", "cljc", NULL + }; + static const char *const aliases[] = { + NULL + }; + + parserDefinition *def = parserNew ("Clojure"); + def->kindTable = ClojureKinds; + def->kindCount = ARRAY_SIZE (ClojureKinds); + def->extensions = extensions; + def->aliases = aliases; + def->parser = findClojureTags; + def->useCork = CORK_QUEUE; + return def; +}
Modified: data/filedefs/filetypes.Clojure.conf 2 lines changed, 2 insertions(+), 0 deletions(-) =================================================================== @@ -9,6 +9,8 @@ keywords=* *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* * # default extension used when saving files extension=clj lexer_filetype=Lisp +tag_parser=Clojure + # the following characters are these which a "word" can contains, see documentation #wordchars=_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
Modified: meson.build 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -593,6 +593,7 @@ ctags = static_library('ctags', 'ctags/parsers/asm.c', 'ctags/parsers/basic.c', 'ctags/parsers/bibtex.c', + 'ctags/parsers/clojure.c', 'ctags/parsers/cobol.c', 'ctags/parsers/cpreprocessor.c', 'ctags/parsers/cpreprocessor.h',
Modified: src/tagmanager/tm_parser.c 11 lines changed, 11 insertions(+), 0 deletions(-) =================================================================== @@ -978,6 +978,15 @@ static TMParserMapGroup group_GDSCRIPT[] = { {_("Other"), TM_ICON_OTHER, tm_tag_other_t}, };
+static TMParserMapEntry map_CLOJURE[] = { + {'f', tm_tag_function_t}, // function + {'n', tm_tag_namespace_t}, // namespace +}; +static TMParserMapGroup group_CLOJURE[] = { + {_("Namespaces"), TM_ICON_NAMESPACE, tm_tag_namespace_t}, + {_("Functions"), TM_ICON_METHOD, tm_tag_function_t}, +}; + typedef struct { TMParserMapEntry *entries; @@ -1045,6 +1054,7 @@ static TMParserMap parser_map[] = { MAP_ENTRY(JULIA), MAP_ENTRY(CPREPROCESSOR), MAP_ENTRY(TCLOO), + MAP_ENTRY(CLOJURE), }; /* make sure the parser map is consistent and complete */ G_STATIC_ASSERT(G_N_ELEMENTS(parser_map) == TM_PARSER_COUNT); @@ -1557,6 +1567,7 @@ gboolean tm_parser_has_full_scope(TMParserType lang) /* These make use of the scope, but don't include nested hierarchy * (either as a parser limitation or a language semantic) */ case TM_PARSER_ASCIIDOC: + case TM_PARSER_CLOJURE: case TM_PARSER_CONF: case TM_PARSER_ERLANG: case TM_PARSER_F77:
Modified: src/tagmanager/tm_parser.h 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -113,6 +113,7 @@ enum TM_PARSER_BIBTEX, TM_PARSER_CPREPROCESSOR, TM_PARSER_TCLOO, + TM_PARSER_CLOJURE, TM_PARSER_COUNT };
Modified: src/tagmanager/tm_parsers.h 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -68,6 +68,7 @@ JuliaParser, \ BibtexParser, \ CPreProParser, \ - TclOOParser + TclOOParser, \ + ClojureParser
#endif
Modified: tests/ctags/Makefile.am 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -288,6 +288,7 @@ test_sources = \ simple.abc \ simple.asciidoc \ simple.bas \ + simple.clj \ simple.conf \ simple.d \ simple.diff \
Modified: tests/ctags/simple.clj 15 lines changed, 15 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,15 @@ +(ns app.controller) + + (defn empty-fn []) + +(defn function-with-body [] + (println "body")) + +(clojure.core/defn core-function-with-body [] + (println "core")) + +'(defn quoted-function []) +(quote quoted-function2 []) + +(clojure.core/ns another.name) +(defn x [])
Modified: tests/ctags/simple.clj.tags 7 lines changed, 7 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,7 @@ +# format=tagmanager +another.name�256�0 +app.controller�256�0 +core-function-with-body�16�app.controller�0 +empty-fn�16�app.controller�0 +function-with-body�16�app.controller�0 +x�16�another.name�0
Modified: tests/meson.build 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -284,6 +284,7 @@ ctags_tests = files([ 'ctags/simple.abc.tags', 'ctags/simple.asciidoc.tags', 'ctags/simple.bas.tags', + 'ctags/simple.clj.tags', 'ctags/simple.conf.tags', 'ctags/simple.d.tags', 'ctags/simple.diff.tags',
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).