[geany/geany] a5d5ae: Add Clojure ctags parser
Jiří Techet
git-noreply at geany.org
Thu May 12 23:28:16 UTC 2022
Branch: refs/heads/master
Author: Jiří Techet <techet at gmail.com>
Committer: Jiří Techet <techet at gmail.com>
Date: Thu, 12 May 2022 23:28:16 UTC
Commit: a5d5ae3d87f7760ac83d17991faad63644a5aa9d
https://github.com/geany/geany/commit/a5d5ae3d87f7760ac83d17991faad63644a5aa9d
Log Message:
-----------
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 at 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).
More information about the Commits
mailing list