35ec4efe784a5c1cfdfd9710211452eb00d21bb0
[stack/conf/vim.git] / addons / TagHighlight / plugin / TagHighlight / module / utilities.py
1 #!/usr/bin/env python
2 # Tag Highlighter:
3 #   Author:  A. S. Budden <abudden _at_ gmail _dot_ com>
4 # Copyright: Copyright (C) 2009-2012 A. S. Budden
5 #            Permission is hereby granted to use and distribute this code,
6 #            with or without modifications, provided that this copyright
7 #            notice is copied with it. Like anything else that's free,
8 #            the TagHighlight plugin is provided *as is* and comes with no
9 #            warranty of any kind, either expressed or implied. By using
10 #            this plugin, you agree that in no event will the copyright
11 #            holder be liable for any damages resulting from the use
12 #            of this software.
13
14 # ---------------------------------------------------------------------
15 from __future__ import print_function
16 import time
17 import re
18
19 # Used for timing a function; from http://www.daniweb.com/code/snippet368.html
20 # decorator: put @print_timing before a function to time it.
21 def print_timing(func):
22     def wrapper(*arg):
23         t1 = time.time()
24         res = func(*arg)
25         t2 = time.time()
26         print('{name} took {time:0.3f} ms'.format(name=func.__name__, time=(t2-t1)*1000.0))
27         return res
28     return wrapper
29
30 class TagHighlightOptionDict(dict):
31     """Customised version of a dictionary that allows access by attribute."""
32     def __getattr__(self, name):
33         return self[name]
34
35     def __getitem__(self, name):
36         if name not in self:
37             from .options import AllOptions
38             for option in AllOptions.keys():
39                 if option == name:
40                     return AllOptions[option]['Default']
41         return super(TagHighlightOptionDict, self).__getitem__(name)
42
43     def __setattr__(self, name, value):
44         self[name] = value
45
46 class SetDict(dict):
47     """Customised version of a dictionary that auto-creates non-existent keys as sets."""
48     def __getitem__(self, key):
49         if key not in self:
50             self[key] = set()
51         return super(SetDict, self).__getitem__(key)
52
53     def __setitem__(self, key, value):
54         if isinstance(value, set):
55             super(SetDict, self).__setitem__(key, value)
56         else:
57             super(SetDict, self).__setitem__(key, set([value]))
58
59 class DictDict(dict):
60     """Customised version of a dictionary that auto-creates non-existent keys as SetDicts."""
61     def __getitem__(self, key):
62         if key not in self:
63             self[key] = SetDict()
64         return super(DictDict, self).__getitem__(key)
65
66     def __setitem__(self, key, value):
67         if isinstance(value, SetDict):
68             super(DictDict, self).__setitem__(key, value)
69         else:
70             raise NotImplementedError
71
72 def GenerateValidKeywordRange(iskeyword):
73     # Generally obeys Vim's iskeyword setting, but
74     # only allows characters in ascii range
75     ValidKeywordSets = iskeyword.split(',')
76     rangeMatcher = re.compile('^(?P<from>(?:\d+|\S))-(?P<to>(?:\d+|\S))$')
77     falseRangeMatcher = re.compile('^^(?P<from>(?:\d+|\S))-(?P<to>(?:\d+|\S))$')
78     validList = []
79     for valid in ValidKeywordSets:
80         m = rangeMatcher.match(valid)
81         fm = falseRangeMatcher.match(valid)
82         if valid == '@':
83             for ch in [chr(i) for i in range(0,128)]:
84                 if ch.isalpha():
85                     validList.append(ch)
86         elif m is not None:
87             # We have a range of ascii values
88             if m.group('from').isdigit():
89                 rangeFrom = int(m.group('from'))
90             else:
91                 rangeFrom = ord(m.group('from'))
92
93             if m.group('to').isdigit():
94                 rangeTo = int(m.group('to'))
95             else:
96                 rangeTo = ord(m.group('to'))
97
98             validRange = list(range(rangeFrom, rangeTo+1))
99             # Restrict to ASCII
100             validRange = [i for i in validRange if i < 128]
101             for ch in [chr(i) for i in validRange]:
102                 validList.append(ch)
103
104         elif fm is not None:
105             # We have a range of ascii values: remove them!
106             if fm.group('from').isdigit():
107                 rangeFrom = int(fm.group('from'))
108             else:
109                 rangeFrom = ord(fm.group('from'))
110
111             if fm.group('to').isdigit():
112                 rangeTo = int(fm.group('to'))
113             else:
114                 rangeTo = ord(fm.group('to'))
115
116             validRange = range(rangeFrom, rangeTo+1)
117             for ch in [chr(i) for i in validRange]:
118                 for i in range(validList.count(ch)):
119                     validList.remove(ch)
120
121         elif len(valid) == 1:
122             # Just a char
123             if ord(valid) < 128:
124                 validList.append(valid)
125
126         else:
127             raise ValueError('Unrecognised iskeyword part: ' + valid)
128
129     return validList
130
131
132 def IsValidKeyword(keyword, iskeyword):
133     for char in keyword:
134         if not char in iskeyword:
135             return False
136     return True
137
138 def rglob(path, pattern):
139     # Tweaked version of the stackoverflow answer:
140     # http://stackoverflow.com/questions/2186525/use-a-glob-to-find-files-recursively-in-python#2186565
141     import os, fnmatch
142     matches = []
143     for root, dirnames, filenames in os.walk(path):
144         matches += [os.path.join(root, i) for i in fnmatch.filter(filenames, pattern)]
145     return matches
146
147 if __name__ == "__main__":
148     import pprint
149     test_obj = SetDict()
150     # Should be able to add an item to the list
151     pprint.pprint(test_obj)
152     test_obj['MyIndex'].add('Hello')
153     test_obj['SetList'] = ['This', 'Is', 'A', 'List']
154     test_obj['SetString'] = 'This is a string'
155     # These should all be lists:
156     pprint.pprint(test_obj)