@@ -341,31 +341,51 @@ def resort_ctags(tag_file):
341341 If not exists, create an empty array and store in the
342342 dictionary with the file name as key
343343 Save the line to this list
344- Create a new ``[ tagfile]_sorted_by_file `` file
344+ Create a new ``tagfile`` file
345345 For each key in the sorted dictionary
346346 For each line in the list indicated by the key
347347 Split the line on tab character
348- Remove the prepending ``.\ `` from the ``file_name`` part of
348+ Remove the prepending ``.`` from the ``file_name`` part of
349349 the tag
350350 Join the line again and write the ``sorted_by_file`` file
351351
352352 :param tag_file: The location of the tagfile to be sorted
353353
354354 :returns: None
355355 """
356- keys = {}
356+ meta = []
357+ symbols = []
358+ tmp_file = tag_file + '.tmp'
357359
358360 with codecs .open (tag_file , encoding = 'utf-8' , errors = 'replace' ) as file_ :
359361 for line in file_ :
360- keys .setdefault (line .split ('\t ' )[FILENAME ], []).append (line )
362+ if line .startswith ('!_TAG' ):
363+ meta .append (line )
364+ continue
365+
366+ # read all valid symbol tags, which contain at least
367+ # symbol name and containing file and build a list of tuples
368+ split = line .split ('\t ' )
369+ if len (split ) > FILENAME :
370+ symbols .append ((split [FILENAME ], split ))
371+
372+ # sort inplace to save some RAM with large .tags files
373+ meta .sort ()
374+ symbols .sort ()
361375
362- with codecs .open (tag_file + '_sorted_by_file' , 'w' , encoding = 'utf-8' ,
376+ with codecs .open (tmp_file , 'w' , encoding = 'utf-8' ,
363377 errors = 'replace' ) as file_ :
364- for k in sorted (keys ):
365- for line in keys [k ]:
366- split = line .split ('\t ' )
367- split [FILENAME ] = split [FILENAME ].lstrip ('.\\ ' )
368- file_ .write ('\t ' .join (split ))
378+
379+ # write sourted metadata
380+ file_ .writelines (meta )
381+
382+ # followed by sorted list of symbols
383+ for _ , split in symbols :
384+ split [FILENAME ] = split [FILENAME ].lstrip ('.\\ ' )
385+ file_ .write ('\t ' .join (split ))
386+
387+ os .remove (tag_file )
388+ os .rename (tmp_file , tag_file )
369389
370390#
371391# Models
@@ -393,16 +413,26 @@ def __init__(self, line, column=0):
393413 self .column = column
394414
395415 def __lt__ (self , other ):
396- return self .line .split ('\t ' )[self .column ] < other
416+ try :
417+ return self .key < other
418+ except IndexError :
419+ return False
397420
398421 def __gt__ (self , other ):
399- return self .line .split ('\t ' )[self .column ] > other
422+ try :
423+ return self .key > other
424+ except IndexError :
425+ return False
400426
401427 def __getitem__ (self , index ):
402- return self .line .split ('\t ' )[index ]
428+ return self .line .split ('\t ' , self . column + 1 )[index ]
403429
404430 def __len__ (self ):
405- return len (self .line .split ('\t ' ))
431+ return self .line .count ('\t ' ) + 1
432+
433+ @property
434+ def key (self ):
435+ return self [self .column ]
406436
407437class TagFile (object ):
408438 """
@@ -443,6 +473,8 @@ def __getitem__(self, index):
443473 result = self .mapped .readline () # get a complete line
444474
445475 result = result .strip ()
476+ if not result :
477+ raise IndexError ("Invalid tag at index %d." % index )
446478
447479 return Tag (result , self .column )
448480
@@ -476,7 +508,7 @@ def open(self):
476508 """
477509 Open file.
478510 """
479- self .file_o = codecs .open (self .path , 'r+b' , encoding = 'ascii ' )
511+ self .file_o = codecs .open (self .path , 'r+b' , encoding = 'utf-8 ' )
480512 self .mapped = mmap .mmap (self .file_o .fileno (), 0 ,
481513 access = mmap .ACCESS_READ )
482514
@@ -500,20 +532,21 @@ def search(self, exact_match=True, *tags):
500532 if not tags :
501533 while self .mapped .tell () < self .mapped .size ():
502534 result = Tag (self .mapped .readline ().strip (), self .column )
503- yield (result )
535+ if result .line :
536+ yield result
504537 return
505538
506539 for key in tags :
507540 left_index = bisect .bisect_left (self , key )
508541 if exact_match :
509542 result = self [left_index ]
510543 while result .line and result [result .column ] == key :
511- yield ( result )
544+ yield result
512545 result = Tag (self .mapped .readline ().strip (), self .column )
513546 else :
514547 result = self [left_index ]
515548 while result .line and result [result .column ].startswith (key ):
516- yield ( result )
549+ yield result
517550 result = Tag (self .mapped .readline ().strip (), self .column )
518551
519552 def search_by_suffix (self , suffix ):
@@ -529,10 +562,9 @@ def search_by_suffix(self, suffix):
529562 :returns: matching tags
530563 """
531564 for line in self .file_o :
532- if line .split ('\t ' )[self .column ].endswith (suffix ):
533- yield Tag (line )
534- else :
535- continue
565+ tag = Tag (line , self .column )
566+ if tag .key .endswith (suffix ):
567+ yield tag
536568
537569 def tag_class (self ):
538570 """
0 commit comments