-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cleanup code and change to a more pythonic API #6
base: master
Are you sure you want to change the base?
Changes from 11 commits
6a598bd
820264c
664a7d2
cc5a2ae
93ec2bc
f8433de
1157b6d
daacf11
404b4fa
b8627b8
540b4bf
0179621
8f73c8c
f8b15eb
f741351
43b2688
aaac757
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,130 +17,142 @@ You should have received a copy of the GNU General Public License | |
along with Python-Ctags. If not, see <http://www.gnu.org/licenses/>. | ||
""" | ||
|
||
cdef extern from "string.h": | ||
char* strerror(int errnum) | ||
|
||
include "stdlib.pxi" | ||
include "readtags.pxi" | ||
|
||
|
||
cdef class TagEntry: | ||
cdef tagEntry c_entry | ||
|
||
def __cinit__(self): | ||
self.c_entry.fields.count = 0 | ||
self.c_entry.fields.list = NULL | ||
|
||
|
||
def __setitem__(self, key, item): | ||
if key == 'name': | ||
self.c_entry.name = item | ||
elif key == 'file': | ||
self.c_entry.file = item | ||
elif key == 'pattern': | ||
self.c_entry.address.pattern = item | ||
elif key == 'lineNumber': | ||
self.c_entry.address.lineNumber = item | ||
elif key == 'kind': | ||
self.c_entry.kind = item | ||
elif key == 'fileScope': | ||
self.c_entry.fileScope = item | ||
elif key == 'fields': | ||
# fields.list is allocated by readtags.c | ||
if self.c_entry.fields.count != len(item): | ||
return | ||
|
||
fields = item | ||
if self.c_entry.fields.list != NULL: | ||
free(self.c_entry.fields.list) | ||
self.c_entry.fields.list = NULL | ||
|
||
for k, v in fields.iteritems(): | ||
self.c_entry.fields.list.key = k | ||
self.c_entry.fields.list.value = v | ||
|
||
def __getitem__(self, key): | ||
cdef char* result | ||
if key == 'name': | ||
return self.c_entry.name | ||
elif key == 'file': | ||
return self.c_entry.file | ||
elif key == 'pattern': | ||
if self.c_entry.address.pattern == NULL: | ||
return None | ||
return self.c_entry.address.pattern | ||
elif key == 'lineNumber': | ||
return self.c_entry.address.lineNumber | ||
elif key == 'kind': | ||
if self.c_entry.kind == NULL: | ||
return None | ||
return self.c_entry.kind | ||
elif key == 'fileScope': | ||
return self.c_entry.fileScope | ||
else: | ||
# It will crash if we mix NULL/0/None | ||
# don't mix comparison of type | ||
result = ctagsField(&self.c_entry, key) | ||
if result == NULL: | ||
return None | ||
|
||
return result | ||
cdef create_tagEntry(const tagEntry* const c_entry): | ||
cdef dict ret = {} | ||
ret['name'] = c_entry.name | ||
ret['file'] = c_entry.file | ||
ret['fileScope'] = c_entry.fileScope | ||
if c_entry.address.pattern != NULL: | ||
ret['pattern'] = c_entry.address.pattern | ||
if c_entry.address.lineNumber: | ||
ret['lineNumber'] = c_entry.address.lineNumber | ||
if c_entry.kind != NULL: | ||
ret['kind'] = c_entry.kind | ||
for index in range(c_entry.fields.count): | ||
key = c_entry.fields.list[index].key | ||
ret[key.decode()] = c_entry.fields.list[index].value | ||
return ret | ||
|
||
cdef class CTags: | ||
cdef tagFile* file | ||
cdef tagFileInfo info | ||
cdef tagEntry c_entry | ||
cdef object current_id | ||
|
||
def __cinit__(self, filepath): | ||
self.open(filepath) | ||
self.file = ctagsOpen(filepath, &self.info) | ||
if not self.file: | ||
raise OSError(self.info.status.error_number, | ||
strerror(self.info.status.error_number), | ||
filepath) | ||
|
||
def __dealloc__(self): | ||
|
||
if self.file: | ||
ctagsClose(self.file) | ||
|
||
def __getitem__(self, key): | ||
if key == 'opened': | ||
return self.info.status.opened | ||
if key == 'error_number': | ||
return self.info.status.error_number | ||
ret = None | ||
if key == 'format': | ||
return self.info.file.format | ||
if key == 'sort': | ||
elif key == 'sort': | ||
return self.info.file.sort | ||
if key == 'author': | ||
if self.info.program.author == NULL: | ||
return '' | ||
return self.info.program.author | ||
if key == 'name': | ||
if self.info.program.name == NULL: | ||
return '' | ||
return self.info.program.name | ||
if key == 'url': | ||
if self.info.program.url == NULL: | ||
return '' | ||
return self.info.program.url | ||
if key == 'version': | ||
if self.info.program.version == NULL: | ||
return '' | ||
return self.info.program.version | ||
|
||
|
||
def open(self, filepath): | ||
self.file = ctagsOpen(filepath, &self.info) | ||
|
||
if not self.info.status.opened: | ||
raise Exception('Invalid tag file') | ||
else: | ||
if key == 'author': | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd do something like this to further clean up the code if key in ('author', 'name', 'url', 'version'):
ret = getattr(self.info.program, key) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure getattr works for c structure. Maybe cython is smart enough. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, Cython is not smart enough :) getattr doesn't work on c structure. |
||
ret = self.info.program.author | ||
elif key == 'name': | ||
ret = self.info.program.name | ||
elif key == 'url': | ||
ret = self.info.program.url | ||
elif key == 'version': | ||
ret = self.info.program.version | ||
if ret is None: | ||
raise KeyError(key) | ||
return ret | ||
|
||
def setSortType(self, tagSortType type): | ||
return ctagsSetSortType(self.file, type) | ||
|
||
def first(self, TagEntry entry): | ||
return ctagsFirst(self.file, &entry.c_entry) | ||
|
||
def find(self, TagEntry entry, char* name, int options): | ||
return ctagsFind(self.file, &entry.c_entry, name, options) | ||
|
||
def findNext(self, TagEntry entry): | ||
return ctagsFindNext(self.file, &entry.c_entry) | ||
|
||
def next(self, TagEntry entry): | ||
return ctagsNext(self.file, &entry.c_entry) | ||
success = ctagsSetSortType(self.file, type) | ||
if not success: | ||
raise RuntimeError() | ||
|
||
cdef first(self): | ||
success = ctagsFirst(self.file, &self.c_entry) | ||
if not success: | ||
raise RuntimeError() | ||
return create_tagEntry(&self.c_entry) | ||
|
||
cdef find(self, bytes name, int options): | ||
success = ctagsFind(self.file, &self.c_entry, name, options) | ||
if not success: | ||
raise RuntimeError() | ||
return create_tagEntry(&self.c_entry) | ||
|
||
cdef findNext(self): | ||
success = ctagsFindNext(self.file, &self.c_entry) | ||
if not success: | ||
raise RuntimeError() | ||
return create_tagEntry(&self.c_entry) | ||
|
||
cdef next(self): | ||
success = ctagsNext(self.file, &self.c_entry) | ||
if not success: | ||
raise RuntimeError() | ||
return create_tagEntry(&self.c_entry) | ||
|
||
def find_tags(self, bytes name, int options): | ||
""" Find tags corresponding to name in the tag file. | ||
@name : a bytes array to search to. | ||
@options : A option flags for the search. | ||
@return : A iterator on all tags corresponding to the search. | ||
|
||
WARNING: Only one iterator can run on a tag file. | ||
If you use another iterator (by calling all_tags or find_tags), | ||
any previous iterator will be invalidate and raise a RuntimeError. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. → invalidated |
||
""" | ||
try: | ||
first = self.find(name, options) | ||
self.current_id = first | ||
yield first | ||
except KeyError: | ||
raise StopIteration from None | ||
|
||
while True: | ||
if self.current_id is not first: | ||
raise RuntimeError("Only one search/list generator at a time") | ||
try: | ||
other = self.findNext() | ||
except RuntimeError: | ||
raise StopIteration from None | ||
else: | ||
yield other | ||
|
||
def all_tags(self): | ||
""" List all tags in the tag file. | ||
@return : A iterator on all tags in the file. | ||
|
||
WARNING: Only one iterator can run on a tag file. | ||
If you use another iterator (by calling all_tags or find_tags), | ||
any previous iterator will be invalidate and raise a RuntimeError. | ||
""" | ||
try: | ||
first = self.first() | ||
self.current_id = first | ||
yield first | ||
except KeyError: | ||
raise StopIteration from None | ||
|
||
while True: | ||
if self.current_id is not first: | ||
raise RuntimeError("Only one search/list generator at a time") | ||
try: | ||
other = self.next() | ||
except RuntimeError: | ||
raise StopIteration from None | ||
else: | ||
yield other | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to use Python-3-compatible syntax here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "except OSError as err" is python3 syntax.
Do you speak about the print function ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep
On 17 May 2016 at 17:42, Matthieu Gautier [email protected] wrote: