def do_inspect(self, done_inspect): current_file_name = self.view.file_name() BackendManager.active_backend().set_file_contents( file=current_file_name, contents=self.view.substr(sublime.Region(0, self.view.size())), ) done_inspect.set()
def on_done(self, fname): self.results = ghc_eval_x(BackendManager.active_backend().ghc_eval(["({0}) ({1})".format(fname, a) for a in self.args])) ghc_eval_expr = ["({0}) ({1})".format(fname, json.dumps(a)) for a in self.args] self.string_results = ghc_eval_x(BackendManager.active_backend().ghc_eval(ghc_eval_expr)) self.view.run_command('sublime_haskell_eval_replace', {'results': ghc_eval_merge_results(self.results, self.string_results)})
def scan_contents(self): current_file_name = self.view.file_name() view_contents = { current_file_name: self.view.substr(sublime.Region(0, self.view.size())) } status_msg = Common.status_message_process( "Scanning {0}".format(current_file_name)) status_msg.start() def scan_resp(_resp): status_msg.result_ok() _project_dir, project_name = Common.locate_cabal_project_from_view( self.view) self.autocompleter.drop_completions_async(current_file_name) self.autocompleter.generate_completions_cache( project_name, current_file_name, contents=view_contents) def scan_err(_err, _details): status_msg.result_fail() BackendManager.active_backend().scan(files=[current_file_name], contents=view_contents, on_response=scan_resp, on_error=scan_err)
def do_load(self, view): filename = view.file_name() if not Common.view_is_haskell_source(view) or not filename: return if Settings.COMPONENT_DEBUG.event_viewer: print('{0}.on_load {1}.'.format(type(self).__name__, filename)) view_settings = view.settings() or {} if Settings.PLUGIN.use_improved_syntax and (filename.endswith(".hs") or filename.endswith(".hsc") or \ view_settings.get('syntax', '').endswith('.tmLanguage')): view_settings.set( 'syntax', 'Packages/SublimeHaskell/Syntaxes/Haskell-SublimeHaskell.sublime-syntax' ) EventCommon.assoc_to_project(view, self.backend_mgr, filename) _project_dir, project_name = Common.locate_cabal_project_from_view( view) if Settings.PLUGIN.enable_infer_types: BackendManager.active_backend().infer(files=[filename]) Utils.run_async('rescan source {0}/{1}'.format(project_name, filename), self.rescan_source, project_name, filename, {'drop_all': False})
def run(self, _edit, **kwargs): self.current_file_name = kwargs.get('filename') or self.view.file_name() self.status_msg = Common.status_message_process("Scanning docs for {0}".format(self.current_file_name), priority=3) self.status_msg.start() def run_infer(): self.status_msg = Common.status_message_process("Inferring types for {0}".format(self.current_file_name), priority=3) self.status_msg.start() def infer_on_resp(_resp): self.status_msg.result_ok() def infer_on_err(_err, _details): self.status_msg.result_fail() BackendManager.active_backend().infer(files=[self.current_file_name], on_response=infer_on_resp, on_error=infer_on_err) def on_resp(_resp): self.status_msg.result_ok() run_infer() def on_err(_err, _details): self.status_msg.result_fail() run_infer() BackendManager.active_backend().docs(files=[self.current_file_name], on_response=on_resp, on_error=on_err)
def get_type(view, project_name, filename, module_name, line, column): # line and column are 0-based buffer positions # file_types = query_file_types(project_name, [filename], module_name, line, column) or [] types = [] if SourceHaskellTypeCache().has(filename): types = SourceHaskellTypeCache().get(filename) else: def to_file_pos(rgn): return FilePosition(int(rgn['line']) - 1, int(rgn['column']) - 1) def to_region_type(resp): ## print('resp {0}'.format(pprint.pformat(resp))) rgn = resp['region'] return RegionType(resp['note']['type'], to_file_pos(rgn['from']), to_file_pos(rgn['to'])) contents = {} if view.is_dirty(): BackendManager.active_backend().set_file_contents(file=filename, contents=view.substr(sublime.Region(0, view.size()))) res = BackendManager.active_backend().types(project_name, [filename], module_name, line, column, ghc_flags=Settings.PLUGIN.ghc_opts) if res is not None: types = [to_region_type(r) for r in res] # SourceHaskellTypeCache().set(filename, types, False) return sorted_types(view, types, FilePosition(line, column).point(view))
def get_completions(self, view, locations): "Get all the completions related to the current file." current_file_name = view.file_name() if not current_file_name: return [] Logging.log('AutoCompleter.get_completions.', Logging.LOG_DEBUG) self.current_filename = current_file_name project_name = Common.locate_cabal_project_from_view(view)[1] line_contents = Common.get_line_contents(view, locations[0]) qsymbol = Common.get_qualified_symbol(line_contents) qualified_prefix = qsymbol.qualified_name() Logging.log('qsymbol {0}'.format(qsymbol), Logging.LOG_DEBUG) Logging.log('current_file_name {0} qualified_prefix {1}'.format(current_file_name, qualified_prefix), Logging.LOG_DEBUG) view_settings = view.settings() wide = view_settings.get('subhask_wide_completion') suggestions = [] completions = [] if qsymbol.module: if qsymbol.is_import_list: current_module = Utils.head_of(BackendManager.active_backend().module(project_name, current_file_name)) if current_module and current_module.location.project: # Search for declarations of qsymbol.module within current project q_module = Utils.head_of(BackendManager.active_backend().scope_modules(project_name, current_file_name, lookup=qsymbol.module, search_type='exact')) if q_module is not None: if q_module.by_source(): proj_module = BackendManager.active_backend().resolve(file=q_module.location.filename, exports=True) if proj_module: suggestions = proj_module.declarations.values() elif q_module.by_cabal(): cabal_module = Utils.head_of(BackendManager.active_backend().module(project_name, lookup=q_module.name, search_type='exact', package=q_module.location.package.name)) if cabal_module: suggestions = cabal_module.declarations.values() else: suggestions = BackendManager.active_backend().complete(qualified_prefix, current_file_name, wide=wide) completions = make_completions(suggestions) else: with self.cache as cache_: if wide: completions += cache_.global_completions() else: completions += cache_.files.get(current_file_name, cache_.global_completions()) completions += self.keyword_completions(qsymbol.name) sort_completions(completions) return completions
def next_in_chain(self, resp): self.msgs.extend(resp) ## Leave room to expand the error message cases... if any([msg.get('level', '') in ['error'] for msg in resp]): self.status_msg.result_fail() ## Paranoia: Ensure that mark_response() executes in the UI thread BackendMgr.active_backend().autofix_show(self.msgs, wait_complete=False, on_response=self.process_corrections) else: self.go_chain()
def go_chain(self): if self.commands: agent_func, modify_args, kwargs = self.commands[0] self.commands = self.commands[1:] agent_func(modify_args(self.filename), contents=self.contents, wait_complete=False, on_response=self.next_in_chain, on_error=self.chain_error, **kwargs) else: self.status_msg.result_ok() BackendMgr.active_backend().autofix_show(self.msgs, wait_complete=False, on_response=self.process_corrections)
def candidate_modules(self, project_name, module_name, scope, symdb): retval = None if scope is not None: retval = BackendManager.active_backend().scope_modules(project_name, scope, lookup=module_name, search_type='exact') elif self.current_file_name is not None: retval = BackendManager.active_backend().scope_modules(project_name, self.current_file_name, lookup=module_name, search_type='exact') else: retval = BackendManager.active_backend().list_modules(module=module_name, symdb=symbols.PackageDb.from_string(symdb) if symdb else None) return retval
def next_in_chain(self, resp): self.msgs.extend(resp) ## Leave room to expand the error message cases... if any([msg.get('level', '') in ['error'] for msg in resp]): self.status_msg.result_fail() ## Paranoia: Ensure that mark_response() executes in the UI thread BackendMgr.active_backend().autofix_show( self.msgs, wait_complete=False, on_response=self.process_corrections) else: self.go_chain()
def do_hover(self): if self.hover_zone == sublime.HOVER_TEXT: qsymbol = Common.get_qualified_symbol_at_point(self.view, self.point) ## print('hover: qualified symbol {0}'.format(qsymbol)) module_word = qsymbol.module ident = qsymbol.name if module_word is not None and ident is None: # TODO: Any ideas for popup about module? pass elif ident is not None: whois_name = qsymbol.qualified_name() full_name = qsymbol.full_name() # Try get type of hovered symbol typed_expr = None if types.SourceHaskellTypeCache().has(self.filename): typed_expr = self.get_type(types.SourceHaskellTypeCache().get(self.filename), whois_name) else: project_name = Common.locate_cabal_project_from_view(self.view)[1] point_rgn = sublime.Region(self.point, self.point) typed_expr = self.get_type(types.get_type_view(self.view, project_name, point_rgn), whois_name) # Try whois suggest_import = False decl = Utils.head_of(BackendManager.active_backend().whois(whois_name, self.filename)) if not decl: suggest_import = True decl = Utils.head_of(BackendManager.active_backend().lookup(full_name, self.filename)) self.create_symbol_popup(typed_expr, decl, suggest_import) elif self.hover_zone == sublime.HOVER_GUTTER: errs = [err for err in ParseOutput.MARKER_MANAGER.marks_for_view(self.view) if err.region.start.line == self.line] if errs: popup_parts = [self.STYLES.gen_style(self.view.settings().get('color_scheme'))] for err in errs: msg = UnicodeOpers.use_unicode_operators(symbols.escape_text(err.message)) # Decorate first word with style decors = { 'Error': 'error', 'Warning': 'warning', 'Hint': 'hint' } for dec, dec_style in decors.items(): msg = msg.replace(dec, u'<span class="{0}">{1}</span>'.format(dec_style, dec)) popup_parts.append(u'<p>{0}</p>'.format(msg)) if err.correction is not None: popup_parts.append(err.correction.popup()) popup_text = u''.join(popup_parts) self.shown = True self.view.show_popup(popup_text, sublime.HIDE_ON_MOUSE_MOVE_AWAY, self.point, 600, 600, self.on_navigate, self.on_hide)
def do_hover(self): if self.hover_zone == sublime.HOVER_TEXT: qsymbol = Common.get_qualified_symbol_at_point(self.view, self.point) ## print('hover: qualified symbol {0}'.format(qsymbol)) module_word = qsymbol.module ident = qsymbol.name if module_word is not None and ident is None: # TODO: Any ideas for popup about module? pass elif ident is not None: whois_name = qsymbol.qualified_name() full_name = qsymbol.full_name() # Try get type of hovered symbol typed_expr = None if types.SourceHaskellTypeCache().has(self.filename): typed_expr = self.get_type(types.SourceHaskellTypeCache().get(self.filename), whois_name) else: project_name = Common.locate_cabal_project_from_view(self.view)[1] point_rgn = sublime.Region(self.point, self.point) typed_expr = self.get_type(types.get_type_view(self.view, project_name, point_rgn), whois_name) # Try whois suggest_import = False decl = Utils.head_of(BackendManager.active_backend().whois(whois_name, self.filename)) if not decl: suggest_import = True decl = Utils.head_of(BackendManager.active_backend().lookup(full_name, self.filename)) self.create_symbol_popup(typed_expr, decl, suggest_import) elif self.hover_zone == sublime.HOVER_GUTTER: errs = [err for err in ParseOutput.errors_for_view(self.view) if err.region.start.line == self.line] if errs: popup_parts = [self.STYLES.gen_style(self.view.settings().get('color_scheme'))] for err in errs: msg = UnicodeOpers.use_unicode_operators(symbols.escape_text(err.message)) # Decorate first word with style decors = { 'Error': 'error', 'Warning': 'warning', 'Hint': 'hint' } for dec, dec_style in decors.items(): msg = msg.replace(dec, u'<span class="{0}">{1}</span>'.format(dec_style, dec)) popup_parts.append(u'<p>{0}</p>'.format(msg)) if err.correction is not None: popup_parts.append(err.correction.popup()) popup_text = u''.join(popup_parts) self.view.show_popup(popup_text, sublime.HIDE_ON_MOUSE_MOVE_AWAY, self.point, 600, 600, self.on_navigate, self.on_hide)
def on_done(self, fname): comma_delim_args = ", ".join(self.args) json_args = ", ".join([json.dumps(a) for a in self.args]) self.results = ghc_eval_x(BackendManager.active_backend().ghc_eval(['({0}) [{1}]'.format(fname, comma_delim_args)])) self.string_results = ghc_eval_x(BackendManager.active_backend().ghc_eval(['({0}) [{1}]'.format(fname, json_args)])) self.res = ghc_eval_merge_results(self.results, self.string_results) if self.res[0] is None: return else: result_list = json.loads(self.res[0]) self.view.run_command('sublime_haskell_eval_replace', {'results': result_list})
def run_infer(): self.status_msg = Common.status_message_process("Inferring types for {0}".format(self.current_file_name), priority=3) self.status_msg.start() def infer_on_resp(_resp): self.status_msg.result_ok() def infer_on_err(_err, _details): self.status_msg.result_fail() BackendManager.active_backend().infer(files=[self.current_file_name], on_response=infer_on_resp, on_error=infer_on_err)
def run(self, _edit, **kwargs): filename = kwargs.get('filename') module_name = kwargs.get('module_name') package_name = kwargs.get('package_name') symdb = kwargs.get('db') name = kwargs.get('name') qname = kwargs.get('qname') no_browse = kwargs.get('no_browse') or False if qname: self.full_name = qname self.current_file_name = self.view.file_name() # Try whois it, followed by file symbol and wider module searches self.candidates = self.collect_candidates(qname, name, filename, module_name, package_name, symdb) else: self.current_file_name = self.view.file_name() qsymbol = Common.get_qualified_symbol(qname) \ if qname \ else Common.get_qualified_symbol_at_region(self.view, self.view.sel()[0]) module_word = qsymbol.module ident = qsymbol.name if ident is None: # module if not no_browse: self.view.window().run_command('sublime_haskell_browse_module', {'module_name': module_word, 'scope': self.current_file_name}) return if not module_word and not ident: Common.sublime_status_message('No symbol selected') return self.whois_name = qsymbol.qualified_name() self.full_name = qsymbol.full_name() self.candidates = (BackendManager.active_backend().whois(self.whois_name, self.current_file_name) or [])[:1] if not self.candidates: self.candidates = BackendManager.active_backend().lookup(self.full_name, self.current_file_name) if not self.candidates: self.candidates = BackendManager.active_backend().symbol(lookup=self.full_name, search_type='exact') if not self.candidates: Common.sublime_status_message('Symbol {0} not found'.format(self.full_name)) elif len(self.candidates) == 1: self.show_symbol_info(self.candidates[0]) elif not no_browse: results = [[c.qualified_name(), c.defined_module().location.to_string()] for c in self.candidates] self.view.window().show_quick_panel(results, self.on_done)
def scan_contents(self, view): current_file_name = view.file_name() status_msg = Common.status_message_process("Scanning {0}".format(current_file_name), priority=3) status_msg.start() def scan_resp(_resp): status_msg.stop() self.update_completions_async([current_file_name]) def scan_err(_err, _details): status_msg.fail() status_msg.stop() scan_contents = {current_file_name: view.substr(sublime.Region(0, view.size()))} BackendManager.active_backend().scan(contents=scan_contents, on_response=scan_resp, on_error=scan_err)
def get_completions_async(self, project_name, file_name): def log_result(result): retval = result or [] Logging.log('completions: {0}'.format(len(retval)), Logging.LOG_TRACE) return retval comps = [] update_cabal = False update_sources = False with self.cache as cache_: if file_name in cache_.files: return log_result(cache_.files.get(file_name, [])) else: update_cabal = not cache_.cabal update_sources = not cache_.sources if update_cabal: self.update_cabal_completions() if update_sources: self.update_sources_completions() with self.cache as cache_: comps = cache_.global_completions() import_names = [] if file_name is None: return log_result(comps) else: Logging.log('preparing completions for {0}/{1}'.format(project_name, file_name), Logging.LOG_DEBUG) comps = make_completions(BackendManager.active_backend().complete('', file_name)) current_module = Utils.head_of(BackendManager.active_backend().module(project_name, file_name)) Logging.log('current_module {0}'.format(current_module)) if current_module: # Get import names # # Note, that if module imported with 'as', then it can be used only with its synonym # instead of full name import_names.extend([('{0}\tmodule {1}'.format(i.import_as, i.module), i.import_as) for i in current_module.imports if i.import_as]) import_names.extend([('{0}\tmodule'.format(i.module), i.module) for i in current_module.imports if not i.import_as]) comps.extend(import_names) sort_completions(comps) with self.cache as cache_: cache_.files[file_name] = comps return log_result(cache_.files[file_name])
def run(self, edit, **args): kw_module = args.get('module') self.backend = BackendManager.active_backend() if not kw_module: kw_decl = args.get('decl') if kw_decl is None: qsymbol = Common.get_qualified_symbol_at_region(self.view, self.view.sel()[0]) kw_decl = qsymbol.qualified_name() current_file_name = self.view.file_name() # Phase 1: Get the candidate import modules: the backend's query_import returns the (flag, list) tuple. # If successful (flag == True), then invoke add_import to add the import to the module's existing # modules. (status, self.candidates) = self.backend.query_import(kw_decl, current_file_name) if status: if len(self.candidates) == 1: self.add_import(edit, self.candidates[0].module.name) else: self.view.window().show_quick_panel([[c.module.name] for c in self.candidates], self.on_done) else: if len(self.candidates) == 1: Common.show_status_message(self.candidates[0]) else: sublime.message_dialog('\n'.join(self.candidates)) else: self.add_import(edit, kw_module)
def get_current_module_completions(self, project_name, current_dir): """ Get modules, that are in scope of file/project In case of file we just return 'scope modules' result In case of dir we look for a related project or sandbox: project - get dependent modules sandbox - get sandbox modules """ backend = BackendManager.active_backend() if self.current_filename: return set([ m.name for m in backend.scope_modules(project_name, self.current_filename) ]) elif current_dir: proj = backend.project(path=current_dir) if proj and 'path' in proj: return set( [m.name for m in backend.list_modules(deps=proj['path'])]) sbox = backend.sandbox(path=current_dir) if sbox and isinstance(sbox, dict) and 'sandbox' in sbox: sbox = sbox.get('sandbox') if sbox: mods = backend.list_modules(sandbox=sbox) or [] return set([m.name for m in mods]) else: mods = backend.list_modules(cabal=True) or [] return set([m.name for m in mods])
def is_in_project(self, view): file_shown_in_view = Common.window_view_and_file(view)[2] if file_shown_in_view is None: return False src_module = Utils.head_of(BackendManager.active_backend().module(file=file_shown_in_view)) return src_module is not None and src_module.location.project is not None
def get_type(view, project_name, filename, module_name, line, column): # line and column are 0-based buffer positions # file_types = query_file_types(project_name, [filename], module_name, line, column) or [] types = [] if SourceHaskellTypeCache().has(filename): types = SourceHaskellTypeCache().get(filename) else: def to_file_pos(rgn): return FilePosition(int(rgn['line']) - 1, int(rgn['column']) - 1) def to_region_type(resp): ## print('resp {0}'.format(pprint.pformat(resp))) rgn = resp['region'] return RegionType(resp['note']['type'], to_file_pos(rgn['from']), to_file_pos(rgn['to'])) contents = {} if view.is_dirty(): contents[filename] = view.substr(sublime.Region(0, view.size())) res = BackendManager.active_backend().types(project_name, [filename], module_name, line, column, contents=contents, ghc_flags=Settings.PLUGIN.ghc_opts) if res is not None: types = [to_region_type(r) for r in res] # SourceHaskellTypeCache().set(filename, types, False) return sorted_types(view, types, FilePosition(line, column).point(view))
def run(self, edit, **args): kw_module = args.get('module') self.backend = BackendManager.active_backend() if not kw_module: kw_decl = args.get('decl') if kw_decl is None: qsymbol = Common.get_qualified_symbol_at_region(self.view, self.view.sel()[0]) kw_decl = qsymbol.qualified_name() current_file_name = self.view.file_name() # Phase 1: Get the candidate import modules: the backend's query_import returns the (flag, list) tuple. # If successful (flag == True), then invoke add_import to add the import to the module's existing # modules. (status, self.candidates) = self.backend.query_import(kw_decl, current_file_name) if status: if len(self.candidates) == 1: self.add_import(edit, self.candidates[0].module.name) else: self.view.window().show_quick_panel([[c.module.name] for c in self.candidates], self.on_done) else: if len(self.candidates) == 1: Common.sublime_status_message(self.candidates[0]) else: sublime.message_dialog('\n'.join(self.candidates)) else: self.add_import(edit, kw_module)
def go_chain(self): if self.commands: agent_func, modify_args, kwargs = self.commands.pop() agent_func(modify_args(self.filename), contents=self.contents, wait_complete=False, on_response=self.next_in_chain, on_error=self.chain_error, **kwargs) else: self.status_msg.result_ok() BackendMgr.active_backend().autofix_show( self.msgs, wait_complete=False, on_response=lambda corr: sublime.set_timeout( self.show_autofixes(corr), 0))
def get_flag_completions(self, project_name): retval = [] if Settings.PLUGIN.auto_complete_language_pragmas: retval = [[c, c] for c in BackendManager.active_backend().flags(project_name)] sort_completions(retval) return retval
def go_chain(self): if self.commands: agent_func, modify_args, kwargs = self.commands[0] self.commands = self.commands[1:] agent_func(modify_args(self.filename), contents=self.contents, wait_complete=False, on_response=self.next_in_chain, on_error=self.chain_error, **kwargs) else: self.status_msg.result_ok() BackendMgr.active_backend().autofix_show( self.msgs, wait_complete=False, on_response=self.process_corrections)
def completions_for_module(self, project_name, module, filename): """ Returns completions for module """ retval = [] backend = BackendManager.active_backend() if module: mods = backend.scope_modules( project_name, filename, lookup=module, search_type='exact') if filename else [] mod_file = mods[0].location.filename if mods and mods[0].by_source( ) else None package = mods[0].location.package.name if mods and mods[ 0].by_cabal() else None mod_id = mods[0] if mods else None mod_decls = Utils.head_of( list( filter( lambda m: mod_id == m, backend.module(project_name, lookup=module, search_type='exact', file=mod_file, package=package)))) retval = make_completions(mod_decls.exports) if mod_decls else [] return retval
def run(self): self.view = self.window.active_view() if not self.view: Common.show_status_message("No file active", False) else: project_dir, project_name = Common.locate_cabal_project_from_view( self.view) if not project_dir: Common.show_status_message("Not in project", False) ## FIXME: proj_info = BackendManager.active_backend().project(project_name) self.project_name = project_name self.project_dir = project_dir self.names = ['lib:{0}'.format(project_name)] if proj_info: self.names.extend([ 'exe:{0}'.format(executable['name']) for executable in proj_info['description']['executables'] ]) self.names.extend([ 'test:{0}'.format(test['name']) for test in proj_info['description']['tests'] ]) if len(self.names) > 1: self.window.show_quick_panel(self.names, self.on_done) else: self.on_done(0)
def completions_for_module(self, project_name, module, filename): """ Returns completions for module """ retval = [] backend = BackendManager.active_backend() if module: mods = backend.scope_modules( project_name, filename, lookup=module, search_type='exact') if filename else [] mod_file = mods[0].location.filename if mods and mods[0].by_source( ) else None cache_db = mods[0].location.db if mods and mods[0].by_cabal( ) else None package = mods[0].location.package.name if mods and mods[ 0].by_cabal() else None mod_decls = Utils.head_of( backend.module(project_name, lookup=module, search_type='exact', file=mod_file, symdb=cache_db, package=package)) retval = make_completions( mod_decls.declarations.values()) if mod_decls else [] return retval
def run(self, edit, **kwargs): current_file_name = kwargs.get('filename', self.view.file_name()) project_name = Common.locate_cabal_project_from_view(self.view)[1] backend = BackendManager.active_backend() imp_module = Utils.head_of(backend.module(project_name, file=current_file_name)) if imp_module: imports = sorted(imp_module.imports, key=lambda i: i.position.line) supported, result = backend.clean_imports(current_file_name) print(result) if supported: if len(imports) == len(result): Logging.log('replacing imports for {0}'.format(current_file_name), Logging.LOG_TRACE) erased = 0 for imp, new_imp in zip(imports, result): point = self.view.text_point(imp.position.line - 1 - erased, 0) if new_imp.endswith('()'): self.view.erase(edit, self.view.full_line(point)) erased = erased + 1 else: self.view.replace(edit, self.view.line(point), new_imp) else: Common.sublime_status_message('different number of imports: {0} and {1}'.format(len(imports), len(result))) else: if len(result) == 1: Common.sublime_status_message(result[0]) else: sublime.message_dialog('\n'.join(result)) else: Common.sublime_status_message('Clean Imports failed: module not scanned')
def post_successful_check(self, view): if Settings.COMPONENT_DEBUG.event_viewer: print('{0}.post_successful_check invoked.'.format( type(self).__name__)) if Settings.PLUGIN.enable_infer_types: BackendManager.active_backend().infer(files=[view.file_name()]) if Settings.COMPONENT_DEBUG.event_viewer: print('{0}.post_successful_check: prettify_on_save {0}'.format( Settings.PLUGIN.prettify_on_save)) if Settings.PLUGIN.prettify_on_save: if Settings.PLUGIN.prettify_executable == 'stylish-haskell': view.run_command('sublime_haskell_stylish') elif Settings.PLUGIN.prettify_executable == 'hindent': view.run_command('sublime_haskell_hindent')
def collect_candidates(self, qualified_name, unqualified_name, filename, module_name, package_name, symdb): candidates = BackendManager.active_backend().whois(qualified_name, file=self.current_file_name) if not candidates: if filename: candidates = BackendManager.active_backend().symbol(lookup=unqualified_name, search_type='exact', file=filename) else: if module_name and package_name: symbol_db = symbols.PackageDb.from_string(symdb) if symdb else None candidates = BackendManager.active_backend().symbol(lookup=unqualified_name, search_type='exact', module=module_name, symdb=symbol_db, package=package_name) else: candidates = [] return candidates
def run(self, **_kwargs): if self.window.active_view().file_name(): def on_resp(msgs): self.status_msg.result_ok() if msgs: sublime.set_timeout(functools.partial(self.on_got_messages, msgs), 0) def on_err(err, _details): self.status_msg.result_fail() Common.sublime_status_message('Check & Lint: {0}'.format(err)) self.status_msg = Common.status_message_process('Autofix: ' + self.window.active_view().file_name(), priority=3) self.status_msg.start() BackendManager.active_backend().check_lint(files=[self.window.active_view().file_name()], ghc=Settings.PLUGIN.ghc_opts, on_response=on_resp, on_error=on_err)
def on_done(self, inp): self.packages = BackendMgr.active_backend().cabal_list(input) if not self.packages: Common.sublime_status_message("Package {0} not found".format(inp)) else: self.window.show_quick_panel( [([p.name] + ([p.synopsis] if p.synopsis else [])) for p in self.packages], self.on_select)
def generate_completions_cache(self, project_name, file_name, contents=None): def log_result(result): retval = result or [] if Settings.COMPONENT_DEBUG.completions: print('completions: {0}'.format(len(retval))) return retval comps = [] update_cabal = False update_sources = False with self.cache as cache_: if file_name in cache_.files: del cache_.files[file_name] else: update_cabal = not cache_.cabal update_sources = not cache_.sources ## Not sure what these were supposed to do -- the actual methods are no-ops. if update_cabal: self.update_cabal_completions() if update_sources: self.update_sources_completions() with self.cache as cache_: comps = cache_.global_completions() import_names = [] if file_name: if Settings.COMPONENT_DEBUG.completions: print('preparing completions for {0} ({1})'.format(project_name, file_name)) backend = BackendManager.active_backend() comps = make_completions(backend.complete(Common.QualifiedSymbol(''), file_name, contents=contents)) current_module = Utils.head_of(backend.module(project_name, file_name)) if Settings.COMPONENT_DEBUG.completions: print('current_module {0}'.format(current_module)) if current_module: # Get import names # # Note, that if module imported with 'as', then it can be used only with its synonym # instead of full name import_names.extend([('{0}\tmodule {1}'.format(i.import_as, i.module), i.import_as) for i in current_module.imports if i.import_as]) import_names.extend([('{0}\tmodule'.format(i.module), i.module) for i in current_module.imports if not i.import_as]) comps.extend(import_names) sort_completions(comps) with self.cache as cache_: cache_.files[file_name] = comps return log_result(cache_.files[file_name]) else: return log_result(comps)
def on_candidate_selected(self, idx): if idx >= 0: (module_name, ident_name) = self.candidates[idx] info = BackendManager.active_backend().whois('{0}.{1}'.format(module_name, ident_name), self.view.file_name()) if info: self.show_symbol_info(info[0]) else: Common.sublime_status_message("Can't get info for {0}.{1}".format(module_name, ident_name),)
def scan_contents(self): current_file_name = self.view.file_name() view_contents = {current_file_name: self.view.substr(sublime.Region(0, self.view.size()))} status_msg = Common.status_message_process("Scanning {0}".format(current_file_name)) status_msg.start() def scan_resp(_resp): status_msg.result_ok() _project_dir, project_name = Common.locate_cabal_project_from_view(self.view) self.autocompleter.drop_completions_async(current_file_name) self.autocompleter.generate_completions_cache(project_name, current_file_name, contents=view_contents) def scan_err(_err, _details): status_msg.result_fail() BackendManager.active_backend().scan(files=[current_file_name], contents=view_contents, on_response=scan_resp, on_error=scan_err)
def on_done(self, sym): self.decls = BackendManager.active_backend().symbol(lookup=sym, search_type='regex') self.decls.sort(key=lambda d: d.module.name) if self.decls: module_decls = [['{0}: {1}'.format(decl.module.name, decl.brief(use_unicode=True)), str(decl.defined_module().location)] for decl in self.decls] self.window.show_quick_panel(module_decls, self.on_select) else: Common.sublime_status_message("Nothing found for: {0}".format(sym))
def run(self, _edit, **kwargs): module_name = kwargs.get('module_name') filename = kwargs.get('filename') symdb = kwargs.get('db') scope = kwargs.get('scope') self.candidates = [] self.current_file_name = self.view.window().active_view().file_name() the_module = None project_name = Common.locate_cabal_project_from_view(self.view.window().active_view())[1] if filename: the_module = Utils.head_of(BackendManager.active_backend().module(project_name, file=filename)) if not the_module: Common.sublime_status_message('Module {0} not found'.format(filename)) return elif module_name: cand_mods = self.candidate_modules(project_name, module_name, scope, symdb) if not cand_mods: Common.sublime_status_message('Module {0} not found'.format(module_name)) return elif len(cand_mods) == 1: the_module = self.get_module_info(project_name, cand_mods[0], module_name) if the_module: the_module = Utils.head_of(the_module) else: self.candidates.extend([(m, [m.name, m.location.to_string()]) for m in cand_mods]) else: if self.current_file_name: cand_mods = BackendManager.active_backend().scope_modules(project_name, self.current_file_name) else: symbol_db = symbols.PackageDb.from_string(symdb) if symdb else None cand_mods = BackendManager.active_backend().list_modules(symdb=symbol_db) self.candidates.extend([(m, [m.name, m.location.to_string()]) for m in cand_mods]) if the_module: self.candidates = sorted(list(the_module.declarations.values()), key=lambda d: d.brief()) results = [[decl.brief(use_unicode=False), decl.docs.splitlines()[0] if decl.docs else ''] for decl in self.candidates] self.view.window().show_quick_panel(results, self.on_symbol_selected) else: self.candidates.sort(key=lambda c: c[1][0]) self.view.window().show_quick_panel([c[1] for c in self.candidates], self.on_done)
def run(self, _edit, **_kwargs): qsymbol = Common.get_qualified_symbol_at_region(self.view, self.view.sel()[0]) if Common.view_is_haskell_symbol_info(self.view): # Go to within symbol info window loc = self.view.settings().get('location') if loc: self.view.window().open_file(loc, sublime.ENCODED_POSITION) else: Common.sublime_status_message('Source location of {0} not found'.format(qsymbol.name)) else: backend = BackendManager.active_backend() whois_name = qsymbol.qualified_name() full_name = qsymbol.full_name() current_file_name = self.view.file_name() candidates = [] module_candidates = [] if not qsymbol.is_module(): candidates = [decl for decl in backend.whois(whois_name, current_file_name) if decl.by_source()] if candidates: if candidates[0].has_source_location(): self.view.window().open_file(candidates[0].get_source_location(), sublime.ENCODED_POSITION) else: cands = candidates[:] candidates = [] for cand in cands: for i in cand.imported: candidates = [sym for sym in backend.symbol(lookup=cand.name, search_type='exact', source=True) if sym.module.name == i.module] if candidates and candidates[0].has_source_location(): self.view.window().open_file(candidates[0].get_source_location(), sublime.ENCODED_POSITION) return else: candidates = backend.symbol(lookup=qsymbol.name, search_type='exact', source=True) else: module_candidates = [m for m in backend.list_modules(source=True, module=full_name) if m.name == full_name] if not candidates and not module_candidates: Common.sublime_status_message('Declaration {0} not found'.format(qsymbol.name)) else: candidates_len = len(candidates) if candidates is not None else 0 module_candidates_len = len(module_candidates) if module_candidates is not None else 0 if candidates_len + module_candidates_len == 1: if candidates_len == 1: self.view.window().open_file(candidates[0].get_source_location(), sublime.ENCODED_POSITION) elif module_candidates_len == 1: self.view.window().open_file(module_candidates[0].location.filename) return else: # many candidates self.select_candidates = [([c.brief(use_unicode=False), c.get_source_location()], True) for c in candidates] self.select_candidates += [([m.name, m.location.filename], False) for m in module_candidates] just_names = [c[0] for c in self.select_candidates] self.view.window().show_quick_panel(just_names, self.on_done, 0, 0, self.on_highlighted)
def run(self, _edit, **_kwargs): if Common.view_is_haskell_symbol_info(self.view): pack = self.view.settings().get('package') mod = self.view.settings().get('module') if pack and mod: webbrowser.open('http://hackage.haskell.org/package/{0}/docs/{1}.html'.format(pack, mod.replace('.', '-'))) else: project_name = Common.locate_cabal_project_from_view(self.view)[1] qsymbol = Common.get_qualified_symbol_at_region(self.view, self.view.sel()[0]) modules = [] if qsymbol.is_module(): # module scope = self.view.file_name() if scope: modules = [m for m in BackendManager.active_backend().scope_modules(project_name, scope, lookup=qsymbol.module, search_type='exact') if m.by_cabal()] else: modules = [m for m in BackendManager.active_backend().list_modules(symdb=m.location.db) if m.name == qsymbol.module and m.by_cabal()] else: # symbol scope = self.view.file_name() if scope: decls = BackendManager.active_backend().whois(qsymbol.qualified_name(), file=scope) or \ BackendManager.active_backend().lookup(qsymbol.full_name(), file=scope) or \ BackendManager.active_backend().symbol(lookup=qsymbol.full_name(), search_type='exact') if not decls: Common.sublime_status_message('Module for symbol {0} not found'.format(qsymbol.full_name())) return modules = [decl.defined_module() for decl in decls] if not modules: Common.sublime_status_message('Module {0} not found'.format(qsymbol.module)) elif len(modules) == 1: pkg_id = modules[0].location.package.package_id() pkg_name = modules[0].name.replace('.', '-') webbrowser.open('http://hackage.haskell.org/package/{0}/docs/{1}.html'.format(pkg_id, pkg_name)) else: self.candidates = modules[:] mod_strings = [[m.name, m.location.package.package_id()] for m in self.candidates] self.view.window().show_quick_panel(mod_strings, self.on_done)
def get_type_view(view, project_name, selection=None): filename = view.file_name() project_name = Common.locate_cabal_project_from_view(view)[1] if selection is None: selection = view.sel()[0] line, column = view.rowcol(selection.b) module_name = Utils.head_of(BackendManager.active_backend().module(project_name, file=filename)) return get_type(view, project_name, filename, module_name, line, column)
def get_module_info(self, project_name, module, module_name): args = None if module.by_source(): args = {'lookup': module_name, 'search_type': 'exact', 'file': module.location.filename} elif module.by_cabal(): args = {'lookup': module_name, 'search_type': 'exact', 'symdb': module.location.db, 'package': module.location.package.name} else: args = {'lookup': module_name, 'search_type': 'exact'} return BackendManager.active_backend().module(project_name, **args) if args is not None else None
def get_projects(self): win = self.view.window() folders = win.folders() view_files = [v.file_name() for v in win.views() if v.file_name() and (Common.view_is_haskell_source(v) or Common.view_is_cabal_source(v))] def childof(path, prefix): return Utils.normalize_path(path).startswith(Utils.normalize_path(prefix)) def relevant_project(proj): return any([childof(proj['path'], f) for f in folders]) or any([childof(src, proj['path']) for src in view_files]) projects = BackendMgr.active_backend().list_projects() or [] return dict((info['name'], info) for info in projects if relevant_project(info))
def run(self, **kwargs): project = kwargs.get('project') or False decls = [] if project: project_name = Common.locate_cabal_project_from_view(self.view)[1] modules = BackendManager.active_backend().module(project_name, file=self.current_filename) current_project = Utils.head_of(modules).location.project if not current_project: Common.sublime_status_message('File {0} is not in project'.format(self.current_filename)) return decls = self.sorted_decls_name(BackendManager.active_backend().symbol(project=current_project)) self.declarations = [[decl.brief(True, use_unicode=False), decl.module.name] for decl in decls] else: decls = self.sorted_decls_pos(BackendManager.active_backend().symbol(file=self.current_filename, local_names=True)) self.declarations = [[(decl.position.column * ' ') + decl.brief(True, use_unicode=False)] for decl in decls] self.decls = decls[:] if decls: self.window.show_quick_panel(self.declarations, self.on_done, 0, self.closest_idx(decls), self.on_highlighted if not project else None)
def fix_current(self): self.undo_history.append((self.corrections[:], self.selected)) self.redo_history.clear() (cur, corrs) = self.get_corrections() self.corrections = BackendManager.active_backend().autofix_fix(HsDevResultParse.encode_corrections([cur]), rest=HsDevResultParse.encode_corrections(corrs), pure=True) if not self.corrections: self.selected = 0 self.clear() return False if self.selected >= len(self.corrections): self.selected = 0 self.mark() return True
def completions_for_module(self, project_name, module, filename): """ Returns completions for module """ retval = [] backend = BackendManager.active_backend() if module: mods = backend.scope_modules(project_name, filename, lookup=module, search_type='exact') if filename else [] mod_file = mods[0].location.filename if mods and mods[0].by_source() else None cache_db = mods[0].location.db if mods and mods[0].by_cabal() else None package = mods[0].location.package.name if mods and mods[0].by_cabal() else None mod_decls = Utils.head_of(backend.module(project_name, lookup=module, search_type='exact', file=mod_file, symdb=cache_db, package=package)) retval = make_completions(mod_decls.declarations.values()) if mod_decls else [] return retval
def get_current_module_completions(self, project_name, current_dir): """ Get modules, that are in scope of file/project In case of file we just return 'scope modules' result In case of dir we look for a related project or sandbox: project - get dependent modules sandbox - get sandbox modules """ backend = BackendManager.active_backend() if self.current_filename: return set([m.name for m in backend.scope_modules(project_name, self.current_filename)]) elif current_dir: proj = backend.project(path=current_dir) if proj and 'path' in proj: return set([m.name for m in backend.list_modules(deps=proj['path'])]) sbox = backend.sandbox(path=current_dir) if sbox and isinstance(sbox, dict) and 'sandbox' in sbox: sbox = sbox.get('sandbox') if sbox: mods = backend.list_modules(sandbox=sbox) or [] return set([m.name for m in mods]) else: mods = backend.list_modules(cabal=True) or [] return set([m.name for m in mods])