Esempio n. 1
0
 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()
Esempio n. 2
0
    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)})
Esempio n. 3
0
    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)
Esempio n. 4
0
    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})
Esempio n. 5
0
    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)
Esempio n. 6
0
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))
Esempio n. 7
0
    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)
Esempio n. 10
0
 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
Esempio n. 11
0
 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()
Esempio n. 12
0
    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)
Esempio n. 13
0
    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)
Esempio n. 14
0
    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})
Esempio n. 15
0
        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)
Esempio n. 16
0
    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)
Esempio n. 17
0
    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)
Esempio n. 18
0
    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])
Esempio n. 19
0
    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)
Esempio n. 20
0
 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])
Esempio n. 21
0
    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
Esempio n. 22
0
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))
Esempio n. 23
0
    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)
Esempio n. 24
0
 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))
Esempio n. 25
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
Esempio n. 26
0
 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)
Esempio n. 27
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
            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
Esempio n. 28
0
 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)
Esempio n. 29
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
Esempio n. 30
0
    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')
Esempio n. 31
0
    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')
Esempio n. 32
0
    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
Esempio n. 33
0
    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)
Esempio n. 34
0
 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)
Esempio n. 36
0
    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),)
Esempio n. 37
0
    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)
Esempio n. 38
0
 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))
Esempio n. 39
0
    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)
Esempio n. 40
0
    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)
Esempio n. 41
0
    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)
Esempio n. 42
0
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)
Esempio n. 43
0
    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
Esempio n. 44
0
    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))
Esempio n. 45
0
    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)
Esempio n. 46
0
 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])