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

Tory Gaurnier torygaurnier at xxxxx
Wed Sep 25 18:55:40 UTC 2013


On 09/24/2013 04:18 PM, Tory Gaurnier wrote:
> 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;
> }

Still can't figure it out, to test I even put printf("MAKING TAG: %s - 
%d - %s - %c\n", tag->name, (int)tag->lineNumber, tag->kindName, 
tag->kind); in entry.c's makeTagEntry function, and it prints just as 
you'd expect, it prints the info for QML objects and JS functions, but 
only the JS functions show in the symbol list, I've tried tracing it 
back further but can't even figure it out. But, I mean, if makeTagEntry 
is getting all the data, it should be adding to symbol list right???

This is getting very frustrating, I've looked over my code a million 
times and I can't find anything that would be keeping this from working, 
it works fine in CTags, but not in Geany, makeSimpleTag works fine, but 
when I try to manually use makeTagEntry, nothing happens, even though 
makeSimpleTag is doing the exact same thing...


More information about the Devel mailing list