[Geany-Devel] Interested making a patch to add QML support

Tory Gaurnier torygaurnier at xxxxx
Tue Sep 24 23:18:14 UTC 2013


On 09/24/2013 01:10 PM, Tory Gaurnier wrote:
> Well, I've pretty much got it working, the highlighting is working, 
> and the Javascript functions show up in the symbol list, it's just not 
> showing the QML Objects, so once I get that fixed it'll be finished, 
> at least the first version, I'm sure I'll want to improve it in the 
> future.
Ok, so now I really am at a loss, my qml.c file works fine in Ctags, but 
in Geany it only adds the Javascript functions to the symbol list, I 
really can't figure it out. I've looked over everything, I've compared 
the differences from Ctags in Geany to the original Ctags, the only real 
change that makes a difference that I can see is the fact that the type 
for filePosition was changed to MIOPos. I'm pretty sure I've edited the 
different config files correctly, everythings working except for the QML 
Objects. Now when I'm running Geany I'm running in terminal and there 
are 0 errors being printed.

Here's my qml.c file:

#include "general.h"    /* always include first */
#include "entry.h"
#include "parse.h"      /* always include */
#include "read.h"       /* to define file fileReadLine() */

#include <string.h>     /* to declare strxxx() functions */

typedef struct {
     vString *id;
     vString *kind;
     vString *name;
     unsigned long line_num;
     MIOPos file_pos; // THIS IS THE ONLY THING I'VE CHANGED FROM THE 
CTAGS VERSION
     char *kind_name;
     char kind_letter;
} QMLObject;

typedef enum {
     QML_OBJECT,
     JS_FUNCTION,
     KIND_COUNT
} QMLKind;

static kindOption QMLKinds[KIND_COUNT] = {
     { TRUE,    'o',    "object",    "objects"    },
     { TRUE, 'f',    "function",    "functions"    }
};

const unsigned char* skipMultilineComment(const unsigned char *line) {
     boolean found = FALSE;

     while(*line != '\0') {
         if(strncmp(line, "*/", 2) == 0) {
             line += 2;
             found = TRUE;
             break;
         }

         line++;
     }

     if(found) line = NULL;

     return line;
}

void createQMLObjectTag(QMLObject *qml_obj, boolean *is_qml_object) {
     tagEntryInfo entry;

     // Added this line here to test, and it's printing fine, all values 
are there
     printf("%s - %d - %s - %c\n", qml_obj->name->buffer, 
(int)qml_obj->line_num, qml_obj->kind_name, qml_obj->kind_letter);

     initTagEntry(&entry, qml_obj->name->buffer);
     entry.lineNumber = qml_obj->line_num;
     entry.filePosition = qml_obj->file_pos;
     entry.kindName = qml_obj->kind_name;
     entry.kind = qml_obj->kind_letter;
     makeTagEntry(&entry); // WHY YOU NO MAKE TAG IN SYMBOL LIST!!!! >_<

     vStringClear(qml_obj->name);
     vStringDelete(qml_obj->name);

     *is_qml_object = FALSE;
}

vString* getName(const unsigned char **str_ptr) {
     vString *name = vStringNew();
     const unsigned char *str = *str_ptr;

     while(isalnum(*str) || *str == '_') {
         vStringPut(name, *str);
         str++;
     }

     *str_ptr = str;
     vStringTerminate(name);
     return name;
}

vString *getId(const unsigned char *str, vString *name) {
     vString *id = vStringNew();

     while(strstr(str, "id:") != NULL) {
         if(strncmp(str, "id:", 3) == 0) {
             str += 3;
             while(isspace(*str)) str++;
             id = getName(&str);
             vStringCatS(name, " ");
             vStringCat(name, id);
         }

         else str++;
     }

     vStringClear(id);
     vStringDelete(id);
     return name;
}

static void findQMLTags(void) {
     vString *js_name;
     QMLObject *qml_obj = malloc(sizeof(QMLObject));
     const unsigned char *line;
     boolean is_multiline_comment = FALSE;
     boolean is_qml_object = FALSE;

     while((line = fileReadLine()) != NULL) {
         // If in middle of multiline comment, skip through till end
         if(is_multiline_comment) {
             if((line = skipMultilineComment(line)) == NULL) continue;
             else is_multiline_comment = FALSE;
         }

         // Skip whitespace and comments
         while(isspace(*line)) line++;
         if(strncmp(line, "//", 2) == 0) continue;
         if(strncmp(line, "/*", 2) == 0) {
             is_multiline_comment = TRUE;
             if((line = skipMultilineComment(line)) == NULL) continue;
             else is_multiline_comment = FALSE;
         }

         // If in middle of QML Object { } check for ID and '}'
         if(is_qml_object && (strstr(line, "id:") != NULL || 
strchr(line, '}') != NULL)) {
             if(strstr(line, "id:") != NULL)
                 qml_obj->name = getId(line, qml_obj->name);

             else createQMLObjectTag(qml_obj, &is_qml_object);
         }

         // If '{' in line, but '(' not in line, then there might be a 
QML Object
         if(strchr(line, '{') != NULL && strchr(line, '(') == NULL) {
             int i = 0;
             while(isspace(*line)) line++; // Increment ptr past any 
whitespace before 'Object {'
             // Search past whole word of 'Object'
             while(!isspace(line[i])) {
                 if(line[i] == '{' || line[i] == ':') break;
                 i++;
             }

             while(isspace(line[i])) i++; // Search past any space 
between 'Object' and '{'

             // If '{' is after potential Object name and any 
whitespace, prepare tag to be added
             if(line[i] == '{') {
                 qml_obj->name = getName(&line);
                 qml_obj->line_num = File.lineNumber;
                 qml_obj->file_pos = File.filePosition;
                 qml_obj->kind_name = (char*)QMLKinds[QML_OBJECT].name;
                 qml_obj->kind_letter = QMLKinds[QML_OBJECT].letter;
                 qml_obj->kind = QML_OBJECT;
                 is_qml_object = TRUE;

                 // If ID is on same line
                 if(strstr(line, "id:") != NULL) {
                     while(strncmp(line, "id:", 3) != 0) line++;
                     qml_obj->name = getId(line, qml_obj->name);
                 }

                 // If single line Object
                 if(strchr(line, '}') != NULL)
                     createQMLObjectTag(qml_obj, &is_qml_object);
             }
         }

         // If line contains a function
         // Using while to prepare for unlikely event that "function" 
appears more than once in line
         while(strstr(line, "function") != NULL) {
             while(strncmp(line, "function", 8) != 0) line++;

             // If whitespace is after "function"
             if(isspace(line[8])) {
                 line += 8; // Skip past "function"

                 while(isspace(*line)) line++;

                 vString *name = getName(&line);

                 while(isspace(*line)) line++;

                 // If '(' is after "function" and whitespace, then add 
tag as JS_FUNCTION
                 if(*line == '(') makeSimpleTag(name, QMLKinds, 
JS_FUNCTION);
                 vStringClear(name);
                 vStringDelete(name);

                 break;
             }

             else line++;
         }
     }
}

extern parserDefinition *QMLParser(void) {
     parserDefinition* def = parserNew("QML");
     static const char *const extensions [] = { "qml", NULL };

     def->kinds = QMLKinds;
     def->kindCount = KIND_COUNT(QMLKinds);
     def->extensions = extensions;
     def->parser = findQMLTags;
     def->regex = FALSE;

     return def;
}


More information about the Devel mailing list