Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 490 lines (411 sloc) 17.297 kB
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
1 import threading
5c0d422 @mvoidex Migrated to Sublime Text 3
mvoidex authored
2 import sublime
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
3
5c0d422 @mvoidex Migrated to Sublime Text 3
mvoidex authored
4 if int(sublime.version()) < 3000:
5 from sublime_haskell_common import *
b91dcb0 @mvoidex Added util module
mvoidex authored
6 from haskell_docs import haskell_docs
5c0d422 @mvoidex Migrated to Sublime Text 3
mvoidex authored
7 else:
8 from SublimeHaskell.sublime_haskell_common import *
b91dcb0 @mvoidex Added util module
mvoidex authored
9 from SublimeHaskell.haskell_docs import haskell_docs
5c0d422 @mvoidex Migrated to Sublime Text 3
mvoidex authored
10 from functools import reduce
151b426 @mvoidex Switched to symbols module
mvoidex authored
11
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
12 class Location(object):
13 """
14 Location in file at line
15 """
0c03f61 @nh2 Don't inspect modules if they haven't been changed since last time
nh2 authored
16 def __init__(self, filename, line, column, project = None):
151b426 @mvoidex Switched to symbols module
mvoidex authored
17 if not project:
18 project = get_cabal_project_dir_of_file(filename)
19 self.project = project
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
20 self.filename = filename
21 self.line = line
151b426 @mvoidex Switched to symbols module
mvoidex authored
22 self.column = column
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
23
f2509f2 @mvoidex Added position() back
mvoidex authored
24 def position(self):
25 """ Returns filename:line:column """
26 return ':'.join([self.filename, str(self.line), str(self.column)])
27
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
28 class Symbol(object):
29 """
30 Haskell symbol: module, function, data, class etc.
31 """
151b426 @mvoidex Switched to symbols module
mvoidex authored
32 def __init__(self, symbol_type, name, docs = None, location = None, module = None):
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
33 self.what = symbol_type
34 self.name = name
35 self.module = module
36 self.docs = docs
37 self.location = location
38
870cf1a @mvoidex Using hdocs
mvoidex authored
39 self.tags = {}
40
88d7a1c @mvoidex Fixed setting declaration locations
mvoidex authored
41 def update_location(self, module_loc):
42 """
43 JSON contains only line + column
44 This function used to merge module location, which contains all other info with line + column
45 """
52eaa6d @GhostBarik fixed 'object has no attribute by_source/by_cabal' issues
GhostBarik authored
46 self.location = module_loc
88d7a1c @mvoidex Fixed setting declaration locations
mvoidex authored
47
870cf1a @mvoidex Using hdocs
mvoidex authored
48 def full_name(self):
49 return self.module.name + '.' + self.name
50
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
51 class Import(object):
52 """
53 Haskell import of module
54 """
151b426 @mvoidex Switched to symbols module
mvoidex authored
55 def __init__(self, module_name, is_qualified = False, import_as = None):
56 self.module = module_name
57 self.is_qualified = is_qualified
58 self.import_as = import_as
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
59
60057ce @mvoidex Added cache for modules info
mvoidex authored
60 def dump(self):
61 return self.__dict__
62
bcc01b2 @mvoidex Cache projects
mvoidex authored
63 def module_location(filename):
64 return Location(filename, 1, 1)
65
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
66 class Module(Symbol):
67 """
68 Haskell module symbol
69 """
0c03f61 @nh2 Don't inspect modules if they haven't been changed since last time
nh2 authored
70 def __init__(self, module_name, exports = [], imports = {}, declarations = {}, location = None, cabal = None, last_inspection_time = 0):
bcc01b2 @mvoidex Cache projects
mvoidex authored
71 super(Module, self).__init__('module', module_name, None, location)
151b426 @mvoidex Switched to symbols module
mvoidex authored
72 # List of strings
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
73 self.exports = exports
151b426 @mvoidex Switched to symbols module
mvoidex authored
74 # Dictionary from module name to Import object
75 self.imports = imports.copy()
76 # Dictionary from name to Symbol
77 self.declarations = declarations.copy()
88d7a1c @mvoidex Fixed setting declaration locations
mvoidex authored
78 for d in self.declarations.values():
79 d.update_location(self.location)
60057ce @mvoidex Added cache for modules info
mvoidex authored
80
81 for decl in self.declarations.values():
82 decl.module = self
83
151b426 @mvoidex Switched to symbols module
mvoidex authored
84 # Cabal path or 'cabal'
85 self.cabal = cabal
86
0c03f61 @nh2 Don't inspect modules if they haven't been changed since last time
nh2 authored
87 # Time as from time.time()
88 self.last_inspection_time = last_inspection_time
89
151b426 @mvoidex Switched to symbols module
mvoidex authored
90 def add_declaration(self, new_declaration):
91 if not new_declaration.module:
92 new_declaration.module = self
88d7a1c @mvoidex Fixed setting declaration locations
mvoidex authored
93 new_declaration.update_location(self.location)
151b426 @mvoidex Switched to symbols module
mvoidex authored
94 if new_declaration.module != self:
95 raise RuntimeError("Adding declaration to other module")
96 self.declarations[new_declaration.name] = new_declaration
97
98 def unalias(self, module_alias):
99 """
100 Unalias module import if any
101 Returns list of unaliased modules
102 """
6258adc @mvoidex Minor fix
mvoidex authored
103 return [i.module for i in self.imports.items() if i.import_as == module_alias]
151b426 @mvoidex Switched to symbols module
mvoidex authored
104
105 class Declaration(Symbol):
106 def __init__(self, name, decl_type = 'declaration', docs = None, location = None, module = None):
107 super(Declaration, self).__init__(decl_type, name, docs, location, module)
108
109 def suggest(self):
110 """ Returns suggestion for this declaration """
111 return (self.name, self.name)
112
113 def brief(self):
114 return self.name
115
116 def qualified_name(self):
117 return '.'.join([self.module.name, self.name])
118
119 def detailed(self):
120 """ Detailed info for use in Symbol Info command """
121 info = [
122 self.brief(),
123 '',
124 self.module.name]
125
126 if self.docs:
127 info.extend(['', self.docs])
128
52eaa6d @GhostBarik fixed 'object has no attribute by_source/by_cabal' issues
GhostBarik authored
129 if self.location:
7738e32 @mvoidex Added source location in detailed info
mvoidex authored
130 info.append('')
131 if self.location.project:
132 info.append('Defined in {0} at {1}'.format(self.location.project, self.location.position()))
133 else:
134 info.append('Defined at {0}'.format(self.location.position()))
52eaa6d @GhostBarik fixed 'object has no attribute by_source/by_cabal' issues
GhostBarik authored
135
136 if self.module and self.module.cabal:
35a9293 @mvoidex Fixed location bug
mvoidex authored
137 info.append('')
52eaa6d @GhostBarik fixed 'object has no attribute by_source/by_cabal' issues
GhostBarik authored
138 info.append('Installed in {0}'.format(self.module.cabal))
7738e32 @mvoidex Added source location in detailed info
mvoidex authored
139
151b426 @mvoidex Switched to symbols module
mvoidex authored
140 return '\n'.join(info)
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
141
151b426 @mvoidex Switched to symbols module
mvoidex authored
142 class Function(Declaration):
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
143 """
151b426 @mvoidex Switched to symbols module
mvoidex authored
144 Haskell function declaration
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
145 """
151b426 @mvoidex Switched to symbols module
mvoidex authored
146 def __init__(self, name, function_type, docs = None, location = None, module = None):
147 super(Function, self).__init__(name, 'function', docs, location, module)
5557f8c @mvoidex Getting types of function without signatures with 'ghc-mod info'
mvoidex authored
148 self.type = function_type
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
149
151b426 @mvoidex Switched to symbols module
mvoidex authored
150 def suggest(self):
e4c1a46 @mvoidex Unicode brief and snippets
mvoidex authored
151 return (u'{0}\t{1}'.format(self.name, self.type), self.name)
151b426 @mvoidex Switched to symbols module
mvoidex authored
152
153 def brief(self):
e4c1a46 @mvoidex Unicode brief and snippets
mvoidex authored
154 return u'{0} :: {1}'.format(self.name, self.type if self.type else u'?')
151b426 @mvoidex Switched to symbols module
mvoidex authored
155
156 class TypeBase(Declaration):
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
157 """
151b426 @mvoidex Switched to symbols module
mvoidex authored
158 Haskell type, data or class
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
159 """
ccf1493 @mvoidex Grabbing definitions for type/newtype/data
mvoidex authored
160 def __init__(self, name, decl_type, context, args, definition = None, docs = None, location = None, module = None):
151b426 @mvoidex Switched to symbols module
mvoidex authored
161 super(TypeBase, self).__init__(name, decl_type, docs, location, module)
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
162 self.context = context
163 self.args = args
ccf1493 @mvoidex Grabbing definitions for type/newtype/data
mvoidex authored
164 self.definition = definition
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
165
151b426 @mvoidex Switched to symbols module
mvoidex authored
166 def suggest(self):
746074b @mvoidex Removed snippet_replace, #54
mvoidex authored
167 return (u'{0}\t{1}'.format(self.name, ' '.join(self.args)), self.name)
151b426 @mvoidex Switched to symbols module
mvoidex authored
168
169 def brief(self):
a06b1c2 @mvoidex ModuleInspector support documentation and collects more info about de…
mvoidex authored
170 brief_parts = [self.what]
b9886d3 @mvoidex Collecting more info in ModuleInspector
mvoidex authored
171 if self.context:
172 if len(self.context) == 1:
e4c1a46 @mvoidex Unicode brief and snippets
mvoidex authored
173 brief_parts.append(u'{0} =>'.format(self.context[0]))
b9886d3 @mvoidex Collecting more info in ModuleInspector
mvoidex authored
174 else:
e4c1a46 @mvoidex Unicode brief and snippets
mvoidex authored
175 brief_parts.append(u'({0}) =>'.format(', '.join(self.context)))
b9886d3 @mvoidex Collecting more info in ModuleInspector
mvoidex authored
176 brief_parts.append(self.name)
177 if self.args:
e4c1a46 @mvoidex Unicode brief and snippets
mvoidex authored
178 brief_parts.append(u' '.join(self.args))
ccf1493 @mvoidex Grabbing definitions for type/newtype/data
mvoidex authored
179 if self.definition:
e4c1a46 @mvoidex Unicode brief and snippets
mvoidex authored
180 brief_parts.append(u' = {0}'.format(self.definition))
181 return u' '.join(brief_parts)
151b426 @mvoidex Switched to symbols module
mvoidex authored
182
183 class Type(TypeBase):
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
184 """
151b426 @mvoidex Switched to symbols module
mvoidex authored
185 Haskell type synonym
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
186 """
ccf1493 @mvoidex Grabbing definitions for type/newtype/data
mvoidex authored
187 def __init__(self, name, context, args, definition = None, docs = None, location = None, module = None):
188 super(Type, self).__init__(name, 'type', context, args, definition, docs, location, module)
151b426 @mvoidex Switched to symbols module
mvoidex authored
189
914e7a0 @mvoidex Newtype support in ModuleDeclaration, using forked ghc-mod for detail…
mvoidex authored
190 class Newtype(TypeBase):
191 """
192 Haskell newtype synonym
193 """
ccf1493 @mvoidex Grabbing definitions for type/newtype/data
mvoidex authored
194 def __init__(self, name, context, args, definition = None, docs = None, location = None, module = None):
195 super(Newtype, self).__init__(name, 'newtype', context, args, definition, docs, location, module)
914e7a0 @mvoidex Newtype support in ModuleDeclaration, using forked ghc-mod for detail…
mvoidex authored
196
151b426 @mvoidex Switched to symbols module
mvoidex authored
197 class Data(TypeBase):
198 """
199 Haskell data declaration
200 """
ccf1493 @mvoidex Grabbing definitions for type/newtype/data
mvoidex authored
201 def __init__(self, name, context, args, definition = None, docs = None, location = None, module = None):
202 super(Data, self).__init__(name, 'data', context, args, definition, docs, location, module)
151b426 @mvoidex Switched to symbols module
mvoidex authored
203
d7fd1e1 @mvoidex Fixed error
mvoidex authored
204 class Class(TypeBase):
151b426 @mvoidex Switched to symbols module
mvoidex authored
205 """
206 Haskell class declaration
207 """
208 def __init__(self, name, context, args, docs = None, location = None, module = None):
ccf1493 @mvoidex Grabbing definitions for type/newtype/data
mvoidex authored
209 super(Class, self).__init__(name, 'class', context, args, None, docs, location, module)
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
210
211 def update_with(l, r, default_value, f):
212 """
213 unionWith for Python, but modifying first dictionary instead of returning result
214 """
215 for k, v in r.items():
216 if k not in l:
151b426 @mvoidex Switched to symbols module
mvoidex authored
217 l[k] = default_value[:]
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
218 l[k] = f(l[k], v)
219 return l
220
151b426 @mvoidex Switched to symbols module
mvoidex authored
221 def same_module(l, r):
222 """
223 Returns true if l is same module as r, which is when module name is equal
224 and modules defined in one file, in same cabal-dev sandbox or in cabal
225 """
226 same_cabal = l.cabal and r.cabal and (l.cabal == r.cabal)
52eaa6d @GhostBarik fixed 'object has no attribute by_source/by_cabal' issues
GhostBarik authored
227 same_filename = l.location and r.location and (l.location.filename == r.location.filename)
151b426 @mvoidex Switched to symbols module
mvoidex authored
228 nowhere = (not l.cabal) and (not l.location) and (not r.cabal) and (not r.location)
229 return l.name == r.name and (same_cabal or same_filename or nowhere)
230
231 def same_declaration(l, r):
232 """
233 Returns true if l is same declaration as r
234 """
235 same_mod = l.module and r.module and same_module(l.module, r.module)
236 nowhere = (not l.module) and (not r.module)
237 return l.name == r.name and (same_mod or nowhere)
238
239 class Database(object):
240 """
241 Database contains storages and indexes to allow fast access to module and symbol info in several storages
242 Every info must be added to storages through methods of this class
243 """
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
244 def __init__(self):
245 # Info is stored in several ways:
246
151b426 @mvoidex Switched to symbols module
mvoidex authored
247 # Dictionary from 'cabal' or cabal-dev path to modules dictionary, where
248 # modules dictionary is dictionary from module name to Module
249 # Every module is unique in such dictionary
de560b0 @mvoidex Using LockedObject
mvoidex authored
250 self.cabal_modules = LockedObject({})
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
251
151b426 @mvoidex Switched to symbols module
mvoidex authored
252 # Dictionary from filename to Module defined in this file
de560b0 @mvoidex Using LockedObject
mvoidex authored
253 self.files = LockedObject({})
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
254
151b426 @mvoidex Switched to symbols module
mvoidex authored
255 # Indexes: dictionary from module name to list of Modules
de560b0 @mvoidex Using LockedObject
mvoidex authored
256 self.modules = LockedObject({})
151b426 @mvoidex Switched to symbols module
mvoidex authored
257
258 # Indexes: dictionary from symbol name to list of Symbols to support Go To Definition
de560b0 @mvoidex Using LockedObject
mvoidex authored
259 self.symbols = LockedObject({})
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
260
151b426 @mvoidex Switched to symbols module
mvoidex authored
261 def get_cabal_modules(self, cabal = None):
262 if not cabal:
263 cabal = current_cabal()
de560b0 @mvoidex Using LockedObject
mvoidex authored
264 with self.cabal_modules as cabal_modules:
265 if cabal not in cabal_modules:
266 cabal_modules[cabal] = {}
f716abe @mvoidex Fixed #38
mvoidex authored
267 return LockedObject(self.cabal_modules.object[cabal], self.cabal_modules.object_lock)
151b426 @mvoidex Switched to symbols module
mvoidex authored
268
bcc01b2 @mvoidex Cache projects
mvoidex authored
269 def get_project_modules(self, project_name):
de560b0 @mvoidex Using LockedObject
mvoidex authored
270 with self.files as files:
271 return dict((f, m) for f, m in files.items() if m.location.project == project_name)
bcc01b2 @mvoidex Cache projects
mvoidex authored
272
151b426 @mvoidex Switched to symbols module
mvoidex authored
273 def add_indexes_for_module(self, new_module):
274 def append_return(l, r):
275 l.append(r)
276 return l
277
de560b0 @mvoidex Using LockedObject
mvoidex authored
278 with self.modules as modules:
279 if new_module.name not in modules:
280 modules[new_module.name] = []
281 modules[new_module.name].append(new_module)
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
282
de560b0 @mvoidex Using LockedObject
mvoidex authored
283 with self.symbols as decl_symbols:
284 update_with(decl_symbols, new_module.declarations, [], append_return)
151b426 @mvoidex Switched to symbols module
mvoidex authored
285
286 def remove_indexes_for_module(self, old_module):
287 def remove_return(l, r):
288 return [x for x in l if not same_declaration(x, r)]
289
de560b0 @mvoidex Using LockedObject
mvoidex authored
290 with self.modules as modules:
291 if old_module.name in modules:
292 modules[old_module.name] = [m for m in modules[old_module.name] if not same_module(old_module, m)]
8fe25fc @mvoidex Prepare to change symbols info storage
mvoidex authored
293
de560b0 @mvoidex Using LockedObject
mvoidex authored
294 with self.symbols as decl_symbols:
295 update_with(decl_symbols, old_module.declarations, [], remove_return)
151b426 @mvoidex Switched to symbols module
mvoidex authored
296
297 def add_indexes_for_declaration(self, new_declaration):
de560b0 @mvoidex Using LockedObject
mvoidex authored
298 with self.symbols as decl_symbols:
299 if new_declaration.name not in decl_symbols:
300 decl_symbols[new_declaration.name] = []
301 decl_symbols[new_declaration.name].append(new_declaration)
151b426 @mvoidex Switched to symbols module
mvoidex authored
302
303 def remove_indexes_for_declaration(self, old_declaration):
de560b0 @mvoidex Using LockedObject
mvoidex authored
304 with self.symbols as decl_symbols:
305 if old_declaration.name in decl_symbols:
306 decl_symbols[old_declaration.name] = [d for d in decl_symbols[old_declaration.name] if not same_declaration(d, old_declaration)]
151b426 @mvoidex Switched to symbols module
mvoidex authored
307
308 def add_module(self, new_module, cabal = None):
309 """
310 Adds module and updates indexes
311 """
312 if not cabal:
f716abe @mvoidex Fixed #38
mvoidex authored
313 if new_module.cabal:
314 cabal = new_module.cabal
315 else:
316 cabal = current_cabal()
317 new_module.cabal = cabal
151b426 @mvoidex Switched to symbols module
mvoidex authored
318
de560b0 @mvoidex Using LockedObject
mvoidex authored
319 with self.cabal_modules as cabal_modules:
320 if cabal not in cabal_modules:
321 cabal_modules[cabal] = {}
322 if new_module.name in cabal_modules[cabal]:
b98336d @mvoidex Logging cache loading time, fixed symbols.Database.add_module
mvoidex authored
323 old_module = cabal_modules[cabal][new_module.name]
151b426 @mvoidex Switched to symbols module
mvoidex authored
324 self.remove_indexes_for_module(old_module)
b98336d @mvoidex Logging cache loading time, fixed symbols.Database.add_module
mvoidex authored
325 del cabal_modules[cabal][new_module.name]
de560b0 @mvoidex Using LockedObject
mvoidex authored
326 if new_module.name not in cabal_modules[cabal]:
327 cabal_modules[cabal][new_module.name] = new_module
151b426 @mvoidex Switched to symbols module
mvoidex authored
328 self.add_indexes_for_module(new_module)
329
330 def add_file(self, filename, file_module):
331 """
332 Adds module defined in file and updates indexes
333 """
de560b0 @mvoidex Using LockedObject
mvoidex authored
334 with self.files as files:
335 if filename in files:
336 old_module = files[filename]
151b426 @mvoidex Switched to symbols module
mvoidex authored
337 self.remove_indexes_for_module(old_module)
de560b0 @mvoidex Using LockedObject
mvoidex authored
338 del files[filename]
339 if filename not in files:
340 files[filename] = file_module
151b426 @mvoidex Switched to symbols module
mvoidex authored
341 self.add_indexes_for_module(file_module)
342
343 def add_declaration(self, new_declaration, module):
344 """
345 Adds declaration to module
346 """
347 def add_decl_to_module():
348 if new_declaration.name in module.declarations:
349 self.remove_indexes_for_declaration(module.declarations[new_declaration.name])
350 module.add_declaration(new_declaration)
351 self.add_indexes_for_declaration(new_declaration)
352
353 if module.location:
de560b0 @mvoidex Using LockedObject
mvoidex authored
354 with self.files as files:
355 if module.location.filename not in files:
151b426 @mvoidex Switched to symbols module
mvoidex authored
356 raise RuntimeError("Can't add declaration: no file {0}".format(module.location.filename))
357 add_decl_to_module()
358 elif module.cabal:
0267807 @mvoidex Fixed typo
mvoidex authored
359 if module.name not in self.cabal_modules.object[module.cabal]:
151b426 @mvoidex Switched to symbols module
mvoidex authored
360 raise RuntimeError("Can't add declaration: no module {0}".format(module.name))
361 add_decl_to_module()
362 else:
363 raise RuntimeError("Can't add declaration: no module {0}".format(module.name))
364
365
366
367 def is_within_project(module, project):
368 """
369 Returns whether module defined within project specified
370 """
371 if module.location:
372 return module.location.project == project
373 return False
374
375 def is_within_cabal(module, cabal = None):
376 """
377 Returns whether module loaded from cabal specified
378 If cabal is None, used current cabal
379 """
380 if not cabal:
381 cabal = current_cabal()
382 return module.cabal == cabal
383
384 def is_by_sources(module):
385 """
386 Returns whether module defined by sources
387 """
388 return module.location is not None
389
390 def flatten(lsts):
5c0d422 @mvoidex Migrated to Sublime Text 3
mvoidex authored
391 return reduce(lambda l, r: list(l) + list(r), lsts)
151b426 @mvoidex Switched to symbols module
mvoidex authored
392
393 def get_source_modules(modules, filename = None):
394 """
395 For list of modules with same name returns modules, which is defined by sources
396 Prefer module in same project as filename if specified
397 """
6258adc @mvoidex Minor fix
mvoidex authored
398 project = get_cabal_project_dir_of_file(filename) if filename else None
399
151b426 @mvoidex Switched to symbols module
mvoidex authored
400 candidates = flatten([
401 filter(lambda m: is_within_project(m, project), modules),
402 filter(is_by_sources, modules)])
403
404 if candidates:
405 return candidates[0]
406 return None
407
408 def get_visible_module(modules, filename = None, cabal = None):
409 """
410 For list of modules with same name returns module, which is
411 1. Defined in same project as filename
412 2. Defined in cabal
413 3. None
414 """
415 project = get_cabal_project_dir_of_file(filename) if filename else None
416
417 candidates = flatten([
418 filter(lambda m: is_within_project(m, project), modules),
419 filter(lambda m: is_within_cabal(m, cabal), modules)])
420
421 if candidates:
422 return candidates[0]
423 return None
424
425 def get_preferred_module(modules, filename = None, cabal = None):
426 """
427 For list of modules with same name returns module, which is
428 1. Defined in same project as filename
429 2. Defined in cabal
430 3. Defined by sources
431 4. Other modules
432 Returns None if modules is empty
433 """
434 if filename:
435 project = get_cabal_project_dir_of_file(filename)
436
437 candidates = flatten([
438 filter(lambda m: is_within_project(m, project), modules),
439 filter(lambda m: is_within_cabal(m, cabal), modules),
440 filter(is_by_sources, modules),
441 modules])
442
443 if candidates:
444 return candidates[0]
445 return None
446
447 def declarations_modules(decls, select_module = None):
448 """
449 Reduce list of declarations to dictionary (module_name => select_module(list of modules))
450 """
451 def add_module_to_dict(d, decl):
452 if decl.module.name not in d:
453 d[decl.module.name] = []
454 d[decl.module.name].append(decl.module)
455 return d
456
457 if not select_module:
458 select_module = lambda l: l
459
460 result = reduce(add_module_to_dict, decls, {})
461 return dict((k, select_module(ms)) for k, ms in result.items() if select_module(ms) is not None)
462
463 def is_imported_module(in_module, m, qualified_name = None):
464 """
465 Returns whether 'm' is imported from 'in_module'
466 If 'qualified_name' specified, 'm' must be 'qualified_name' or imported as 'qualified_name'
467 """
468 if qualified_name:
469 if m.name in in_module.imports:
470 cur_import = in_module.imports[m.name]
471 return cur_import.module == qualified_name or cur_import.import_as == qualified_name
472 return False
473 else:
474 if m.name in in_module.imports:
475 return (not in_module.imports[m.name].is_qualified)
476 # Return True also on Prelude
477 return m.name == 'Prelude'
478
479 def is_this_module(this_module, m):
480 """
481 Returns whether 'm' is the same as 'this_module'
482 """
483 # Same source
484 if this_module.location and m.location and this_module.location.filename == m.location.filename:
485 return True
486 # Same name and cabal
487 if this_module.cabal and m.cabal and this_module.cabal == m.cabal and this_module.name == m.name:
488 return True
489 return False
Something went wrong with that request. Please try again.