Beispiel #1
0
    def run(self, edit, **_kwargs):
        selections = list(self.view.sel())

        if not self.is_infos_valid(selections):
            SublimeHaskellExpandSelectionExpression.Infos = [
                ExpandSelectionInfo(self.view, s) for s in selections
            ]

        if not self.is_infos_valid(selections):
            Common.sublime_status_message(
                'Unable to retrieve expand selection info')
            return

        selinfo = [i.expand() for i in self.Infos]
        self.view.sel().clear()
        self.view.sel().add_all([sel.region for sel in selinfo])

        Common.output_panel(
            self.view.window(),
            '\n'.join([
                UnicodeOpers.use_unicode_operators(sel.typename)
                for sel in selinfo
            ]),
            panel_name='sublime_haskell_expand_selection_expression',
            syntax='Haskell-SublimeHaskell')
Beispiel #2
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:
                self.unique_candidates = set(self.candidates)
                self.select_candidate()
            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)
Beispiel #3
0
    def show_types(self, types):
        if not types:
            Common.sublime_status_message("Can't infer type")
            return

        view_sel = self.view.sel()[0]
        types = sorted(filter(lambda t: t.region(self.view).contains(view_sel),
                              types),
                       key=lambda t: t.region(self.view).size())
        self.output_view = Common.output_panel(self.view.window(),
                                               '',
                                               panel_name=TYPES_PANEL_NAME,
                                               syntax='Haskell-SublimeHaskell',
                                               panel_display=False)

        regions = []
        for typ in types:
            Common.output_text(self.output_view,
                               '{0}\n'.format(typ.show(self.view)),
                               clear=False)
            regions.append(
                sublime.Region(
                    self.output_view.size() - 1 -
                    len(UnicodeOpers.use_unicode_operators(typ.typename)),
                    self.output_view.size() - 1))
        self.output_view.add_regions('types', regions, 'comment', '',
                                     sublime.DRAW_OUTLINED)
        Common.show_panel(self.view.window(), panel_name=TYPES_PANEL_NAME)
Beispiel #4
0
    def run(self, **_args):
        self.executables = []
        projs = []
        builder = Builder(self.window.active_view())
        projects = builder.get_projects()
        for proj, info in projects.items():
            if 'description' in info:
                for exes in info['description']['executables']:
                    projs.append((proj + ': ' + exes['name'], {'dir': info['path'], 'name': exes['name']}))
        print('SublimeHaskellRunCommand: projects {0}'.format(projects))

        if not projs:
            Common.sublime_status_message('No project or nothing to run')
        elif len(projs) == 1:
            # One project
            proj_info = projs[0][1]
            self.exec_name = proj_info['name']
            self.exec_base_dir = proj_info['dir']
            self.prompt_prog_args()
        else:
            # Multiple choices
            _, cabal_project_name = Common.locate_cabal_project_from_view(self.window.active_view())

            # Show current project first
            projs.sort(key=lambda s: (not s[0].startswith(cabal_project_name + ': '), s[0]))

            self.executables = [p[1] for p in projs]
            self.window.show_quick_panel([p[0] for p in projs], self.on_project_selected)
Beispiel #5
0
    def select_project(self, on_selected, filter_project):
        '''Select a project from a generated project list. Execution flow continues into the :py:function:`on_selected`
        function with the project's name and the project's base directory. The :py:function:`filter_project` filters
        projects before they are shown (see :py:method:`get_projects`.)
        '''
        projs = [(name, info) for (name, info) in self.get_projects().items()
                 if not filter_project or filter_project(name, info)]

        def run_selected(psel):
            on_selected(psel[0], psel[1]['path'])

        if not projs:
            Common.sublime_status_message("No active projects found.")
        elif len(projs) == 1:
            # There's only one project, build it
            run_selected(projs[0])
        else:
            _, cabal_project_name = Common.locate_cabal_project_from_view(self.view)
            Logging.log('Current project: {0}'.format(cabal_project_name))

            # Sort by name
            projs.sort(key=lambda p: p[0])

            current_project_idx = next((i for i, p in enumerate(projs) if p[0] == cabal_project_name), -1)

            def on_done(idx):
                if idx != -1:
                    run_selected(projs[idx])

            self.view.window().show_quick_panel([[m[0], m[1].get('path', '??')] for m in projs], on_done, 0,
                                                current_project_idx)
Beispiel #6
0
    def run(self):
        self.executables = []
        projs = []
        projects = self.get_projects()
        for proj, info in projects.items():
            if 'description' in info:
                for exes in info['description']['executables']:
                    projs.append((proj + ": " + exes['name'], {
                        'dir': info['path'],
                        'dist': project_dist_path(info['path']),
                        'name': exes['name']
                    }))

        # Nothing to run
        if not projs:
            _, cabal_project_name = Common.locate_cabal_project_from_view(
                self.window.active_view())

            # Show current project first
            projs.sort(
                key=lambda s: (not s[0].startswith(cabal_project_name), s[0]))

            self.executables = list(map(lambda m: m[1], projs))
            self.window.show_quick_panel(list(map(lambda m: m[0], projs)),
                                         self.on_done)
        else:
            Common.sublime_status_message('Nothing to run')
Beispiel #7
0
    def run(self, **_args):
        self.executables = []
        projs = []
        builder = Builder(self.window.active_view())
        projects = builder.get_projects()
        for proj, info in projects.items():
            if 'description' in info:
                for exes in info['description']['executables']:
                    projs.append((proj + ': ' + exes['name'], {'dir': info['path'], 'name': exes['name']}))
        print('SublimeHaskellRunCommand: projects {0}'.format(projects))

        if not projs:
            Common.sublime_status_message('No project or nothing to run')
        elif len(projs) == 1:
            # One project
            proj_info = projs[0][1]
            self.exec_name = proj_info['name']
            self.exec_base_dir = proj_info['dir']
            self.prompt_prog_args()
        else:
            # Multiple choices
            _, cabal_project_name = Common.locate_cabal_project_from_view(self.window.active_view())

            # Show current project first
            projs.sort(key=lambda s: (not s[0].startswith(cabal_project_name + ': '), s[0]))

            self.executables = [p[1] for p in projs]
            self.window.show_quick_panel([p[0] for p in projs], self.on_project_selected)
    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)
Beispiel #9
0
    def select_project(self, on_selected, filter_project):
        '''Select a project from a generated project list. Execution flow continues into the :py:function:`on_selected`
        function with the project's name and the project's base directory. The :py:function:`filter_project` filters
        projects before they are shown (see :py:method:`get_projects`.)
        '''
        projs = [(name, info) for (name, info) in self.get_projects().items()
                 if not filter_project or filter_project(name, info)]

        def run_selected(psel):
            on_selected(psel[0], psel[1]['path'])

        if not projs:
            Common.sublime_status_message("No active projects found.")
        elif len(projs) == 1:
            # There's only one project, build it
            run_selected(projs[0])
        else:
            _, cabal_project_name = Common.locate_cabal_project_from_view(self.view)
            Logging.log('Current project: {0}'.format(cabal_project_name))

            # Sort by name
            projs.sort(key=lambda p: p[0])

            current_project_idx = next((i for i, p in enumerate(projs) if p[0] == cabal_project_name), -1)

            def on_done(idx):
                if idx != -1:
                    run_selected(projs[idx])

            self.view.window().show_quick_panel([[m[0], m[1].get('path', '??')] for m in projs], on_done, 0,
                                                current_project_idx)
Beispiel #10
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)
Beispiel #11
0
 def show_types(self, types):
     if types:
         self.types = types
         self.output_view = Common.output_panel(self.view.window(), '',
                                                panel_name=TYPES_PANEL_NAME,
                                                syntax='Haskell-SublimeHaskell')
         self.view.window().show_quick_panel([t.typename for t in self.types], self.on_done, 0, -1, self.on_changed)
     else:
         Common.sublime_status_message("Can't infer type")
Beispiel #12
0
 def on_resp(self, resp):
     self.status_msg.result_ok()
     self.decls = resp
     if not self.decls:
         Common.sublime_status_message("Hayoo '{0}': not found".format(self.search_str))
         return
     brief_decls = [[decl.module.name + ': ' + decl.brief(use_unicode=False),
                     decl.defined_module().location] for decl in self.decls]
     self.window.show_quick_panel(brief_decls, self.on_select)
Beispiel #13
0
 def show_types(self, types):
     if types:
         self.types = types
         self.output_view = Common.output_panel(self.view.window(), '',
                                                panel_name=TYPES_PANEL_NAME,
                                                syntax='Haskell-SublimeHaskell')
         self.view.window().show_quick_panel([t.typename for t in self.types], self.on_done, 0, -1, self.on_changed)
     else:
         Common.sublime_status_message("Can't infer type")
Beispiel #14
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),)
Beispiel #15
0
 def on_resp(self, resp):
     self.status_msg.result_ok()
     self.decls.extend(resp)
     if not self.decls:
         Common.sublime_status_message("Search '{0}' not found".format(self.search_str))
     else:
         hayoo_results = [[decl.module.name + ': ' + decl.brief(use_unicode=False),
                           decl.defined_module().location] for decl in self.decls]
         self.window.show_quick_panel(hayoo_results, self.on_select)
Beispiel #16
0
 def run(self, **_kwargs):
     view = self.window.active_view()
     if not view:
         Common.sublime_status_message("No file active")
     else:
         opts = Settings.PLUGIN.ghci_opts or []
         self.window.run_command("repl_open", repl_args(cmd=repl_command() + ["$file"] + opts,
                                                        loaded=view.file_name(),
                                                        caption="ghci: {0}".format(os.path.basename(view.file_name()))))
Beispiel #17
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))
Beispiel #18
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)
Beispiel #19
0
 def run(self, **_kwargs):
     view = self.window.active_view()
     if not view:
         Common.sublime_status_message("No file active")
     else:
         project_dir = Common.locate_cabal_project_from_view(view)[0]
         if not project_dir:
             self.window.run_command("sublime_haskell_repl_ghci_current_file", {})
         else:
             self.window.run_command("sublime_haskell_repl_cabal", {})
 def run(self, _edit, **_kwargs):
     errs = MARKER_MANAGER.marks_for_view(self.view)
     if not errs:
         Common.sublime_status_message("No errors or warnings!")
     else:
         cur_point = Symbols.Region.from_region(self.view, self.view.sel()[0])
         prev_err = next(filter(lambda e: e.region < cur_point, reversed(errs)), None)
         # Cycle around to the last error if we run off the first
         if prev_err is None:
             prev_err = errs[-1]
         self.view.sel().clear()
         self.view.sel().add(prev_err.region.to_region(self.view))
         goto_error(self.view, prev_err)
Beispiel #21
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)
Beispiel #22
0
 def run(self, _edit, **_kwargs):
     errs = MARKER_MANAGER.marks_for_view(self.view)
     if not errs:
         Common.sublime_status_message("No errors or warnings!")
     else:
         cur_point = Symbols.Region.from_region(self.view,
                                                self.view.sel()[0])
         prev_err = next(
             filter(lambda e: e.region < cur_point, reversed(errs)), None)
         # Cycle around to the last error if we run off the first
         if prev_err is None:
             prev_err = errs[-1]
         self.view.sel().clear()
         self.view.sel().add(prev_err.region.to_region(self.view))
         goto_error(self.view, prev_err)
Beispiel #23
0
    def add_import(self, edit, module_name):
        contents = self.view.substr(sublime.Region(0, self.view.size()))

        # Phase 2: Ask the backend to turn the contents into a list of Module objects:
        imp_module = self.backend.contents_to_module(self.view.file_name(),
                                                     contents)
        if imp_module is not None:
            imports = sorted(imp_module.imports, key=lambda i: i.position.line)
            after = [imp for imp in imports if imp.module > module_name]

            insert_line = 0
            insert_gap = False

            if after:
                # Insert before after[0]
                insert_line = after[0].position.line - 1
            elif imports:
                # Insert after all imports
                insert_line = imports[-1].position.line
            else:
                declarations = self.backend.symbol(file=self.view.file_name())
                if declarations:
                    # Insert before first declaration
                    # HOWTO: Detect signature?
                    insert_line = min([d.position.line
                                       for d in declarations]) - 2
                    insert_gap = True
                else:
                    # Try to add the import just after the "where" of the module declaration
                    contents = self.view.substr(
                        sublime.Region(0, self.view.size()))
                    mod_decl = re.search('module.*where', contents,
                                         re.MULTILINE)
                    if mod_decl is not None:
                        insert_line = self.view.rowcol(mod_decl.end())[0]
                        insert_gap = True
                    else:
                        # Punt! Insert at the end of the file
                        insert_line = self.view.rowcol(self.view.size())[0]

            insert_text = 'import {0}\n'.format(module_name) + (
                '\n' if insert_gap else '')

            point = self.view.text_point(insert_line, 0)
            self.view.insert(edit, point, insert_text)

            Common.sublime_status_message(
                'Import {0} added'.format(module_name))
Beispiel #24
0
    def run_build(self, project_name, project_dir, config):
        # Don't build if a build is already running for this project
        # We compare the project_name for simplicity (projects with same
        # names are of course possible, but unlikely, so we let them wait)
        if project_name in self.PROJECTS_BEING_BUILT:
            Logging.log("Waiting for build action on '%s' to complete." % project_name, Logging.LOG_WARNING)
            Common.sublime_status_message('Already building {0}'.format(project_name))
            return

        # Set project as building
        self.PROJECTS_BEING_BUILT.add(project_name)

        Logging.log('project build tool: {0}'.format(Settings.get_project_setting(self.view, 'haskell_build_tool')),
                    Logging.LOG_DEBUG)
        Logging.log('settings build tool: {0}'.format(Settings.PLUGIN.haskell_build_tool), Logging.LOG_DEBUG)

        build_tool_name = Settings.get_project_setting(self.view, 'haskell_build_tool', Settings.PLUGIN.haskell_build_tool)
        if build_tool_name == 'stack' and not self.is_stack_project(project_dir):  # rollback to cabal
            build_tool_name = 'cabal'

        tool = self.BUILD_TOOL[build_tool_name]

        # Title of tool: Cabal, Stack
        tool_title = tool['name']
        # Title of action: Cleaning, Building, etc.
        action_title = config['message']
        # Tool name: cabal
        tool_name = tool['command']
        # Tool arguments (commands): build, clean, etc.
        tool_steps = config['steps'][build_tool_name]

        # Config override
        override_args = []
        override_config = Settings.get_project_setting(self.view, 'active_stack_config') if tool_name == 'stack' else ''
        if override_config:
            override_args = ['--stack-yaml', override_config]
        # Assemble command lines to run (possibly multiple steps)
        commands = [[tool_name] + override_args + step if isinstance(step, list) else step for step in tool_steps]

        Logging.log('running build commands: {0}'.format(commands), Logging.LOG_TRACE)

        # Run them
        ## banner = '{0} {1} with {2}\ncommands:\n{3}'.format(action_title, project_name, tool_title, commands)
        banner = '{0} {1} with {2}'.format(action_title, project_name, tool_title)
        Logging.log(banner, Logging.LOG_DEBUG)
        Utils.run_async('wait_for_chain_to_complete', self.wait_for_chain_to_complete, self.view, project_name, project_dir,
                        banner, commands)
Beispiel #25
0
    def run_build(self, project_name, project_dir, config):
        # Don't build if a build is already running for this project
        # We compare the project_name for simplicity (projects with same
        # names are of course possible, but unlikely, so we let them wait)
        if project_name in self.PROJECTS_BEING_BUILT:
            Logging.log("Waiting for build action on '%s' to complete." % project_name, Logging.LOG_WARNING)
            Common.sublime_status_message('Already building {0}'.format(project_name))
            return

        # Set project as building
        self.PROJECTS_BEING_BUILT.add(project_name)

        Logging.log('project build tool: {0}'.format(Settings.get_project_setting(self.view, 'haskell_build_tool')),
                    Logging.LOG_DEBUG)
        Logging.log('settings build tool: {0}'.format(Settings.PLUGIN.haskell_build_tool), Logging.LOG_DEBUG)

        build_tool_name = Settings.get_project_setting(self.view, 'haskell_build_tool', Settings.PLUGIN.haskell_build_tool)
        if build_tool_name == 'stack' and not self.is_stack_project(project_dir):  # rollback to cabal
            build_tool_name = 'cabal'

        tool = self.BUILD_TOOL[build_tool_name]

        # Title of tool: Cabal, Stack
        tool_title = tool['name']
        # Title of action: Cleaning, Building, etc.
        action_title = config['message']
        # Tool name: cabal
        tool_name = tool['command']
        # Tool arguments (commands): build, clean, etc.
        tool_steps = config['steps'][build_tool_name]

        # Config override
        override_args = []
        override_config = Settings.get_project_setting(self.view, 'active_stack_config') if tool_name == 'stack' else ''
        if override_config:
            override_args = ['--stack-yaml', override_config]
        # Assemble command lines to run (possibly multiple steps)
        commands = [[tool_name] + override_args + step if isinstance(step, list) else step for step in tool_steps]

        Logging.log('running build commands: {0}'.format(commands), Logging.LOG_TRACE)

        # Run them
        ## banner = '{0} {1} with {2}\ncommands:\n{3}'.format(action_title, project_name, tool_title, commands)
        banner = '{0} {1} with {2}'.format(action_title, project_name, tool_title)
        Logging.log(banner, Logging.LOG_DEBUG)
        Utils.run_async('wait_for_chain_to_complete', self.wait_for_chain_to_complete, self.view, project_name, project_dir,
                        banner, commands)
Beispiel #26
0
    def show_types(self, types):
        if not types:
            Common.sublime_status_message("Can't infer type")
            return

        self.types = types
        self.output_view = Common.output_panel(self.view.window(), '',
                                               panel_name=TYPES_PANEL_NAME,
                                               syntax='Haskell-SublimeHaskell',
                                               panel_display=False)
        regions = []
        for typ in self.types:
            Common.output_text(self.output_view, '{0}\n'.format(typ.show(self.view)), clear=False)
            regions.append(sublime.Region(self.output_view.size() - 1 - len(UnicodeOpers.use_unicode_operators(typ.typename)),
                                          self.output_view.size() - 1))
        self.output_view.add_regions('types', regions, 'comment', '', sublime.DRAW_OUTLINED)
        Common.show_panel(self.view.window(), panel_name=TYPES_PANEL_NAME)
Beispiel #27
0
    def run(self, edit, **_kwargs):
        selections = list(self.view.sel())

        if not self.is_infos_valid(selections):
            SublimeHaskellExpandSelectionExpression.Infos = [ExpandSelectionInfo(self.view, s) for s in selections]

        if not self.is_infos_valid(selections):
            Common.sublime_status_message('Unable to retrieve expand selection info')
            return

        selinfo = [i.expand() for i in self.Infos]
        self.view.sel().clear()
        self.view.sel().add_all([sel.region for sel in selinfo])

        Common.output_panel(self.view.window(),
                            '\n'.join([UnicodeOpers.use_unicode_operators(sel.typename) for sel in selinfo]),
                            panel_name='sublime_haskell_expand_selection_expression',
                            syntax='Haskell-SublimeHaskell')
    def add_import(self, edit, module_name):
        contents = self.view.substr(sublime.Region(0, self.view.size()))

        # Truncate contents to the module declaration and the imports list, if present.
        imports_list = list(re.finditer('^import.*$', contents, re.MULTILINE))
        if imports_list:
            contents = contents[0:imports_list[-1].end()]

        # Phase 2: Ask the backend to turn the contents into a list of Module objects:
        imp_module = self.backend.contents_to_module(contents)
        if imp_module is not None:
            imports = sorted(imp_module.imports, key=lambda i: i.position.line)
            after = [imp for imp in imports if imp.module > module_name]

            insert_line = 0
            insert_gap = False

            if after:
                # Insert before after[0]
                insert_line = after[0].position.line - 1
            elif imports:
                # Insert after all imports
                insert_line = imports[-1].position.line
            elif imp_module.declarations:
                # Insert before first declaration
                insert_line = min([d.position.line for d in imp_module.declarations.values()]) - 1
                insert_gap = True
            else:
                # Try to add the import just after the "where" of the module declaration
                contents = self.view.substr(sublime.Region(0, self.view.size()))
                mod_decl = re.search('module.*where', contents, re.MULTILINE)
                if mod_decl is not None:
                    insert_line = mod_decl.end()
                    insert_gap = True
                else:
                    # Punt! Insert at the end of the file
                    insert_line = self.view.rowcol(self.view.size())[0]

            insert_text = 'import {0}\n'.format(module_name) + ('\n' if insert_gap else '')

            point = self.view.text_point(insert_line, 0)
            self.view.insert(edit, point, insert_text)

            Common.sublime_status_message('Import {0} added'.format(module_name))
Beispiel #29
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)
Beispiel #30
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)
 def run(self, _edit, **_kwargs):
     errs = MARKER_MANAGER.marks_for_view(self.view)
     if not errs:
         Common.sublime_status_message('No errors or warnings!')
     else:
         view_pt = self.view.sel()[0]
         # Bump just past the view's point, just in case we're sitting on top of the current
         cur_point = Symbols.Region.from_region(self.view, view_pt)
         err_iter = filter(lambda e: e.region > cur_point, errs)
         next_err = next(err_iter, None)
         # If the view's point is really on top of the start of an error, move to the next, otherwise,
         # we'll just keep sitting on top of the current error and never move.
         if next_err is not None and next_err.region.start == cur_point.start:
             next_err = next(err_iter, None)
         # Cycle around to the first error if we run off the end of the list.
         if next_err is None:
             next_err = errs[0]
         self.view.sel().clear()
         self.view.sel().add(next_err.region.to_region(self.view))
         goto_error(self.view, next_err)
Beispiel #32
0
 def run(self, _edit, **_kwargs):
     errs = MARKER_MANAGER.marks_for_view(self.view)
     if not errs:
         Common.sublime_status_message('No errors or warnings!')
     else:
         view_pt = self.view.sel()[0]
         # Bump just past the view's point, just in case we're sitting on top of the current
         cur_point = Symbols.Region.from_region(self.view, view_pt)
         err_iter = filter(lambda e: e.region > cur_point, errs)
         next_err = next(err_iter, None)
         # If the view's point is really on top of the start of an error, move to the next, otherwise,
         # we'll just keep sitting on top of the current error and never move.
         if next_err is not None and next_err.region.start == cur_point.start:
             next_err = next(err_iter, None)
         # Cycle around to the first error if we run off the end of the list.
         if next_err is None:
             next_err = errs[0]
         self.view.sel().clear()
         self.view.sel().add(next_err.region.to_region(self.view))
         goto_error(self.view, next_err)
Beispiel #33
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')
Beispiel #34
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)
Beispiel #35
0
    def run(self, **_kwargs):
        self.view = self.window.active_view()
        if self.view:
            self.targets = []
            self.args = {}

            project_dir, project_name = Common.locate_cabal_project_from_view(
                self.view)
            Logging.log(
                'repl: project_dir {0} project_name {1}'.format(
                    project_dir, project_name), Logging.LOG_DEBUG)
            if project_dir:
                proj_info = BackendManager.active_backend().project(
                    project_name)
                self.project_name = project_name
                self.project_dir = project_dir

                if proj_info:
                    descrip = proj_info.get('description', {})
                    if descrip.get('library'):
                        target = '{0} library'.format(project_name)
                        self.targets.append(target)
                        self.args[target] = (project_name, 'lib', '')

                    for exe in descrip.get('executables', []):
                        target = '{0} ({1} executable)'.format(
                            exe['name'], project_name)
                        self.targets.append(target)
                        self.args[target] = (project_name, 'exe', exe['name'])

                    for test in descrip.get('tests', []):
                        target = '{0} ({1} test)'.format(
                            test['name'], project_name)
                        self.targets.append(target)
                        self.args[target] = (project_name, 'test',
                                             test['name'])

                len_targets = len(self.targets)
                if len_targets == 1:
                    self.on_done(0)
                elif len_targets > 1:
                    self.window.show_quick_panel(self.targets, self.on_done)
                else:
                    Common.sublime_status_message('No target found for REPL.')
            else:
                Common.sublime_status_message("Not in project")
        else:
            Common.sublime_status_message("No file active")
Beispiel #36
0
 def on_err(err, _details):
     self.status_msg.result_fail()
     Common.sublime_status_message('Check & Lint: {0}'.format(err))
Beispiel #37
0
 def run(self, **_kwargs):
     global TOGGLE_SYMBOL_INFO
     TOGGLE_SYMBOL_INFO = not TOGGLE_SYMBOL_INFO
     Common.sublime_status_message('continuous symbol info: {0}'.format('on' if TOGGLE_SYMBOL_INFO else 'off'))
Beispiel #38
0
 def on_err(self, err, _details):
     self.status_msg.result_fail()
     Common.sublime_status_message("Search '{0}': {1}".format(self.search_str, err))
Beispiel #39
0
 def on_err(self, err, _details):
     Common.sublime_status_message('Browse declarations: {0}'.format(err))