From 4323ff91c9b816ece83668650c348d3abb3b99c7 Mon Sep 17 00:00:00 2001 From: hansonw Date: Tue, 23 Feb 2016 01:38:47 -0500 Subject: [PATCH] Add support for tag extension fields --- README.md | 11 +++++-- spec/ctags-fields-spec.coffee | 54 +++++++++++++++++++++++++++++++++++ spec/fixtures/fields-tags | 10 +++++++ src/tag-finder.cc | 15 +--------- src/tag-reader.cc | 18 +----------- src/tag.h | 37 ++++++++++++++++++++++++ 6 files changed, 111 insertions(+), 34 deletions(-) create mode 100644 spec/ctags-fields-spec.coffee create mode 100644 spec/fixtures/fields-tags diff --git a/README.md b/README.md index b1d8f71..2498b8a 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,14 @@ Get all tags matching the tag specified from the tags file at the path. (default: `false`) * `callback` - The function to call when complete with an error as the first - argument and an array containing objects that have `name` and - `file` keys and optionally a `pattern` key if the tag file - specified contains tag patterns. + argument and an array containing tag objects. Each tag object contains: + + * `name` - name of the tag + * `file` - location of the tag + * `kind` - kind of the tag (see `ctags --list-kinds`) + * `lineNumber` - line number of the tag in `file` (defaults to 0 if not provided) + * `pattern` (optional) - pattern to search for in `file` (only if provided in tag file) + * `fields` (optional) - object with string values; extra fields for the tag (only if provided in tag file) #### Example diff --git a/spec/ctags-fields-spec.coffee b/spec/ctags-fields-spec.coffee new file mode 100644 index 0000000..29a12c8 --- /dev/null +++ b/spec/ctags-fields-spec.coffee @@ -0,0 +1,54 @@ +path = require 'path' +ctags = require '../lib/ctags' + +describe 'ctags', -> + tagsFile = null + + beforeEach -> + tagsFile = path.join(__dirname, 'fixtures', 'fields-tags') + + describe '.createReadStream(tagsFileWithFields)', -> + it 'returns a stream that emits data and end events', -> + stream = ctags.createReadStream(tagsFile) + + tags = [] + stream.on 'data', (chunk) -> tags = tags.concat(chunk) + + endHandler = jasmine.createSpy('endHandler') + stream.on('end', endHandler) + + waitsFor -> + endHandler.callCount is 1 + + runs -> + expect(tags.length).toBe 4 + + expect(tags[0].file).toBe 'tagged.js' + expect(tags[0].name).toBe 'callMeMaybe' + expect(tags[0].pattern).toBe '/^function callMeMaybe() {$/' + expect(tags[0].kind).toBe 'f' + expect(tags[0].fields).toEqual + class: 'TestClass' + extra: 'test' + + expect(tags[1].file).toBe 'tagged-duplicate.js' + expect(tags[1].name).toBe 'duplicate' + expect(tags[1].pattern).toBe '/^function duplicate() {$/' + expect(tags[1].kind).toBe 'f' + expect(tags[1].fields).toEqual + test: 'spaces are fine' + test2: 'more spaces' + + expect(tags[2].file).toBe 'tagged.js' + expect(tags[2].name).toBe 'duplicate' + expect(tags[2].pattern).toBe '/^function duplicate() {$/' + expect(tags[2].kind).toBe 'f' + expect(tags[2].fields).toEqual + 'field name': '1' + + expect(tags[3].file).toBe 'tagged.js' + expect(tags[3].name).toBe 'thisIsCrazy' + expect(tags[3].pattern).toBe '/^var thisIsCrazy = true;$/' + expect(tags[3].kind).toBe 'v' + expect(tags[3].fields).toEqual + emptyField: '' diff --git a/spec/fixtures/fields-tags b/spec/fixtures/fields-tags new file mode 100644 index 0000000..b68316c --- /dev/null +++ b/spec/fixtures/fields-tags @@ -0,0 +1,10 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.8 // +callMeMaybe tagged.js /^function callMeMaybe() {$/;" f class:TestClass extra:test +duplicate tagged-duplicate.js /^function duplicate() {$/;" f test:spaces are fine test2:more spaces +duplicate tagged.js /^function duplicate() {$/;" f field name:1 +thisIsCrazy tagged.js /^var thisIsCrazy = true;$/;" v emptyField: diff --git a/src/tag-finder.cc b/src/tag-finder.cc index 5d13f1a..d1c32be 100644 --- a/src/tag-finder.cc +++ b/src/tag-finder.cc @@ -14,20 +14,7 @@ void TagFinder::HandleOKCallback() { Local array = Nan::New(matches.size()); for (size_t i = 0; i < matches.size(); i++) { - Local tagObject = Nan::New(); - tagObject->Set(Nan::New("name").ToLocalChecked(), - Nan::New(matches[i].name.data()).ToLocalChecked()); - tagObject->Set(Nan::New("file").ToLocalChecked(), - Nan::New(matches[i].file.data()).ToLocalChecked()); - tagObject->Set(Nan::New("kind").ToLocalChecked(), - Nan::New(matches[i].kind.data()).ToLocalChecked()); - tagObject->Set(Nan::New("lineNumber").ToLocalChecked(), - Nan::New((int32_t)matches[i].lineNumber)); - if (matches[i].pattern.length() > 0) - tagObject->Set( - Nan::New("pattern").ToLocalChecked(), - Nan::New(matches[i].pattern.data()).ToLocalChecked()); - array->Set(i, tagObject); + array->Set(i, matches[i].toV8Object()); } Local argv[] = { Nan::Null(), array }; diff --git a/src/tag-reader.cc b/src/tag-reader.cc index c7f88c1..6ceb602 100644 --- a/src/tag-reader.cc +++ b/src/tag-reader.cc @@ -17,23 +17,7 @@ void TagReader::HandleOKCallback() { Local array = Nan::New(tags.size()); for (size_t i = 0; i < tags.size(); i++) { - Local tagObject = Nan::New(); - tagObject->Set( - Nan::New("name").ToLocalChecked(), - Nan::New(tags[i].name.data()).ToLocalChecked()); - tagObject->Set( - Nan::New("file").ToLocalChecked(), - Nan::New(tags[i].file.data()).ToLocalChecked()); - tagObject->Set( - Nan::New("kind").ToLocalChecked(), - Nan::New(tags[i].kind.data()).ToLocalChecked()); - tagObject->Set(Nan::New("lineNumber").ToLocalChecked(), - Nan::New((int32_t)tags[i].lineNumber)); - if (tags[i].pattern.length() > 0) - tagObject->Set( - Nan::New("pattern").ToLocalChecked(), - Nan::New(tags[i].pattern.data()).ToLocalChecked()); - array->Set(i, tagObject); + array->Set(i, tags[i].toV8Object()); } Local argv[] = { Nan::Null(), array }; diff --git a/src/tag.h b/src/tag.h index 3a54f8f..3e94083 100644 --- a/src/tag.h +++ b/src/tag.h @@ -2,7 +2,11 @@ #define SRC_TAG_H_ #include +#include +#include +#include "nan.h" #include "readtags.h" +#include "v8.h" class Tag { public: @@ -12,6 +16,38 @@ class Tag { kind = entry.kind != NULL ? entry.kind : ""; pattern = entry.address.pattern != NULL ? entry.address.pattern : ""; lineNumber = entry.address.lineNumber; + for (size_t i = 0; i < entry.fields.count; i++) { + fields.push_back(std::make_pair( + std::string(entry.fields.list[i].key), + std::string(entry.fields.list[i].value) + )); + } + } + + v8::Local toV8Object() { + using namespace v8; + + Local tagObject = Nan::New(); + tagObject->Set(Nan::New("name").ToLocalChecked(), + Nan::New(name.data()).ToLocalChecked()); + tagObject->Set(Nan::New("file").ToLocalChecked(), + Nan::New(file.data()).ToLocalChecked()); + tagObject->Set(Nan::New("kind").ToLocalChecked(), + Nan::New(kind.data()).ToLocalChecked()); + tagObject->Set(Nan::New("lineNumber").ToLocalChecked(), + Nan::New((int32_t)lineNumber)); + if (pattern.length() > 0) + tagObject->Set(Nan::New("pattern").ToLocalChecked(), + Nan::New(pattern.data()).ToLocalChecked()); + if (fields.size() > 0) { + Local fieldsObj = Nan::New(); + for (size_t j = 0; j < fields.size(); j++) { + fieldsObj->Set(Nan::New(fields[j].first).ToLocalChecked(), + Nan::New(fields[j].second).ToLocalChecked()); + } + tagObject->Set(Nan::New("fields").ToLocalChecked(), fieldsObj); + } + return tagObject; } std::string name; @@ -19,6 +55,7 @@ class Tag { std::string kind; std::string pattern; unsigned long lineNumber; + std::vector > fields; }; #endif // SRC_TAG_H_