Beispiel #1
0
    def do_inspection(self):
        self.busy = True
        try:
            projects = []
            files = []
            files_contents = {}

            if not self.cabal_scanned:
                self.cabal_scanned = True
                self.inspect_user_db()

            with self.dirty_files as dirty_files:
                if Settings.COMPONENT_DEBUG.inspection:
                    print('do_inspection: dirty_files: {0}'.format(dirty_files))

                for finspect in dirty_files.keys() or []:
                    projdir = Common.get_cabal_project_dir_of_file(finspect)
                    if projdir is not None:
                        projects.append(projdir)

                    files.append(finspect)

                projects = list(set(projects))
                files = list(set(files))

                files_contents = dict((file, content) for file, content in dirty_files.items() if content)
                dirty_files.clear()

            cand_cabals = []
            with self.cabal_to_load as cabals_to_load:
                cand_cabals = cabals_to_load
                del cabals_to_load[:]

            for cabal in cand_cabals:
                projdir = Common.get_cabal_project_dir_of_file(cabal)
                if projdir is not None:
                    projects.append(projdir)

            files = list(set(files))
            projects = list(set(projects))

            self.inspect(
                paths=[],
                files=list(set(files)),
                projects=list(set(projects)),
                contents=files_contents,
            )
        finally:
            self.busy = False
Beispiel #2
0
    def on_autofix(self, corrections):
        output_messages = [
            ParseOutput.OutputMessage(
                m['source']['file'],
                HsResultParse.parse_region(m['region']).to_zero_based(),
                m['level'].capitalize() + ': ' +
                m['note']['message'].replace('\n', '\n  '), m['level'])
            for m in self.messages
        ]

        self.corrections = corrections
        for corr in self.corrections:
            corr.message_region.to_zero_based()
        self.corrections_dict = dict(
            ((os.path.normpath(c.file), c.message_region.start.line,
              c.message_region.start.column), c) for c in self.corrections)

        for omsg in output_messages:
            okey = (os.path.normpath(omsg.filename), omsg.region.start.line,
                    omsg.region.start.column)
            if okey in self.corrections_dict:
                omsg.correction = self.corrections_dict[okey]

        ParseOutput.set_global_error_messages(output_messages)
        output_text = ParseOutput.format_output_messages(output_messages)
        if Settings.PLUGIN.show_error_window:
            sublime.set_timeout(lambda: ParseOutput.write_output(self.view,
                                                                 output_text,
                                                                 Common.get_cabal_project_dir_of_file(self.filename) or \
                                                                     os.path.dirname(self.filename),
                                                                 panel_display=not self.fly_mode and len(output_messages)),
                                0)
        sublime.set_timeout(
            lambda: ParseOutput.mark_messages_in_views(output_messages), 0)
Beispiel #3
0
    def run(self):
        if not Settings.PLUGIN.enable_hsdev:
            return

        Settings.PLUGIN.add_change_callback('enable_hsdev',
                                            self.on_hsdev_enabled)
        Settings.PLUGIN.add_change_callback('inspect_modules',
                                            self.on_inspect_modules_changed)

        self.start_hsdev()

        while True:
            if Settings.PLUGIN.enable_hsdev and not self.client.ping():
                Logging.log('hsdev ping: no pong', Logging.LOG_WARNING)

            scan_paths = []
            with self.dirty_paths as dirty_paths:
                scan_paths = dirty_paths[:]
                dirty_paths[:] = []

            files_to_reinspect = []
            with self.dirty_files as dirty_files:
                files_to_reinspect = dirty_files[:]
                dirty_files[:] = []

            projects = []
            files = []

            if len(files_to_reinspect) > 0:
                projects = []
                files = []
                for finspect in files_to_reinspect:
                    projdir = Common.get_cabal_project_dir_of_file(finspect)
                    if projdir is not None:
                        projects.append(projdir)
                    else:
                        files.append(finspect)

            projects = list(set(projects))
            files = list(set(files))

            self.inspect(paths=scan_paths, projects=projects, files=files)

            load_cabal = []
            with self.cabal_to_load as cabal_to_load:
                load_cabal = cabal_to_load[:]
                cabal_to_load[:] = []

            for cabal in load_cabal:
                Worker.run_async('inspect cabal {0}'.format(cabal),
                                 self.inspect_cabal, cabal)

            if files_to_reinspect and Settings.PLUGIN.enable_hdocs:
                self.client_back.docs(files=files_to_reinspect)

            self.reinspect_event.wait(HsDevLocalAgent.sleep_timeout)
            self.reinspect_event.clear()
Beispiel #4
0
    def mark_response(self, view, msgs, corrections, fly_mode):
        '''Generate a list of :py:class:`OutputMessage` objects from a backend response.
        '''
        self.clear_error_marks()

        def to_output_message(msg):
            filename = msg.get('source',
                               {}).get('file',
                                       '<no file/command line/OPTIONS_GHC>')
            file_view = view.window().find_open_file(filename)
            if msg.get('region'):
                region = HsResultParse.parse_region(
                    msg.get('region')).to_zero_based()
            else:
                region = Symbols.Region(0)
            level = msg.get('level', 'uncategorized')
            caption = level.capitalize() + ': ' + msg.get('note', {}).get(
                'message', '')
            caption.replace('\n', '\n  ')

            return OutputMessage(file_view, filename, region, caption, level)

        self.messages = [to_output_message(msg) for msg in msgs]
        self.limit_messages(view)

        # Hack alert: Region and Position.to_zero_based() return the original object (self) after updating it.
        # 'and' returns the right hand side, which is never None or a false value.
        #
        # Bascially, a Pythonic way to make side effects happen and still get a list of things we want.
        corrections_dict = dict(
            ((os.path.normpath(c.file), c.message_region.start.line,
              c.message_region.start.column), c) for c in [
                  corr.message_region.to_zero_based() and corr
                  for corr in corrections or []
              ])

        for omsg in self.messages:
            okey = (os.path.normpath(omsg.filename), omsg.region.start.line,
                    omsg.region.start.column)
            if okey in corrections_dict:
                omsg.correction = corrections_dict[okey]

        self.error_marks.extend(self.messages)

        if Settings.PLUGIN.show_error_window:
            filename = view.file_name()
            cabal_proj_dir = Common.get_cabal_project_dir_of_file(
                filename) or os.path.dirname(filename)
            show_panel = not fly_mode and self.messages
            output_text = self.format_output_messages()
            sublime.set_timeout(
                lambda: self.make_message_panel(view, output_text,
                                                cabal_proj_dir, show_panel), 0)

        sublime.set_timeout(self.update_markers_across_views, 0)
Beispiel #5
0
    def do_inspection(self):
        self.busy = True
        try:
            scan_paths = []
            files_to_reinspect = []
            projects = []
            files = []

            with self.dirty_paths as dirty_paths:
                if Settings.COMPONENT_DEBUG.inspection:
                    print(
                        'do_inspection: dirty_paths: {0}'.format(dirty_paths))

                scan_paths = dirty_paths[:]
                del dirty_paths[:]

            with self.dirty_files as dirty_files:
                if Settings.COMPONENT_DEBUG.inspection:
                    print(
                        'do_inspection: dirty_files: {0}'.format(dirty_files))

                projects = []
                files = []
                for finspect in dirty_files.keys() or []:
                    projdir = Common.get_cabal_project_dir_of_file(finspect)
                    if projdir is not None:
                        projects.append(projdir)

                    files.append(finspect)

                projects = list(set(projects))
                files = list(set(files))

                file_contents = dict([(file, content)
                                      for file, content in dirty_files.items()
                                      if content])
                dirty_files.clear()

                self.inspect(scan_paths, projects, files, file_contents)

            cand_cabals = []
            with self.cabal_to_load as cabals_to_load:
                cand_cabals = cabals_to_load
                del cabals_to_load[:]

            for cabal in cand_cabals:
                Utils.run_async('inspect cabal {0}'.format(cabal),
                                self.inspect_cabal, cabal)

            if files_to_reinspect and Settings.PLUGIN.enable_hdocs:
                self.backend.docs(files=files_to_reinspect)
        finally:
            self.busy = False
    def do_inspection(self):
        self.busy = True
        try:
            scan_paths = []
            files_to_reinspect = []
            projects = []
            files = []

            with self.dirty_paths as dirty_paths:
                if Settings.COMPONENT_DEBUG.inspection:
                    print('do_inspection: dirty_paths: {0}'.format(dirty_paths))

                scan_paths = dirty_paths[:]
                del dirty_paths[:]

            with self.dirty_files as dirty_files:
                if Settings.COMPONENT_DEBUG.inspection:
                    print('do_inspection: dirty_files: {0}'.format(dirty_files))

                projects = []
                files = []
                for finspect in dirty_files.keys() or []:
                    projdir = Common.get_cabal_project_dir_of_file(finspect)
                    if projdir is not None:
                        projects.append(projdir)

                    files.append(finspect)

                projects = list(set(projects))
                files = list(set(files))

                file_contents = dict([(file, content) for file, content in dirty_files.items() if content])
                dirty_files.clear()

                self.inspect(scan_paths, projects, files, file_contents)

            cand_cabals = []
            with self.cabal_to_load as cabals_to_load:
                cand_cabals = cabals_to_load
                del cabals_to_load[:]

            for cabal in cand_cabals:
                Utils.run_async('inspect cabal {0}'.format(cabal), self.inspect_cabal, cabal)

            if files_to_reinspect and Settings.PLUGIN.enable_hdocs:
                self.backend.docs(files=files_to_reinspect)
        finally:
            self.busy = False
Beispiel #7
0
    def do_inspection(self):
        self.busy = True
        try:
            scan_paths = []
            with self.dirty_paths as dirty_paths:
                scan_paths = dirty_paths[:]
                dirty_paths[:] = []

            files_to_reinspect = []
            with self.dirty_files as dirty_files:
                files_to_reinspect = dirty_files[:]
                dirty_files[:] = []

            projects = []
            files = []

            if len(files_to_reinspect) > 0:
                projects = []
                files = []
                for finspect in files_to_reinspect:
                    projdir = Common.get_cabal_project_dir_of_file(finspect)
                    if projdir is not None:
                        projects.append(projdir)
                    else:
                        files.append(finspect)

            projects = list(set(projects))
            files = list(set(files))

            self.inspect(paths=scan_paths, projects=projects, files=files)

            load_cabal = []
            with self.cabal_to_load as cabal_to_load:
                load_cabal = cabal_to_load[:]
                cabal_to_load[:] = []

            for cabal in load_cabal:
                Utils.run_async('inspect cabal {0}'.format(cabal),
                                self.inspect_cabal, cabal)

            if files_to_reinspect and Settings.PLUGIN.enable_hdocs:
                self.backend.docs(files=files_to_reinspect)
        finally:
            self.busy = False
    def mark_response(self, view, msgs, corrections, fly_mode):
        '''Generate a list of :py:class:`OutputMessage` objects from a backend response.
        '''
        self.clear_error_marks()

        def to_output_message(msg):
            filename = msg.get('source', {}).get('file', '<no file/command line/OPTIONS_GHC>')
            file_view = view.window().find_open_file(filename)
            if msg.get('region'):
                region = HsResultParse.parse_region(msg.get('region')).to_zero_based()
            else:
                region = Symbols.Region(0)
            level = msg.get('level', 'uncategorized')
            caption = level.capitalize() + ': ' + msg.get('note', {}).get('message', '')
            caption.replace('\n', '\n  ')

            return OutputMessage(file_view, filename, region, caption, level)

        self.messages = [to_output_message(msg) for msg in msgs]
        self.limit_messages(view)

        # Hack alert: Region and Position.to_zero_based() return the original object (self) after updating it.
        # 'and' returns the right hand side, which is never None or a false value.
        #
        # Bascially, a Pythonic way to make side effects happen and still get a list of things we want.
        corrections_dict = dict(((os.path.normpath(c.file), c.message_region.start.line, c.message_region.start.column), c)
                                for c in [corr.message_region.to_zero_based() and corr for corr in corrections or []])

        for omsg in self.messages:
            okey = (os.path.normpath(omsg.filename), omsg.region.start.line, omsg.region.start.column)
            if okey in corrections_dict:
                omsg.correction = corrections_dict[okey]

        self.error_marks.extend(self.messages)

        if Settings.PLUGIN.show_error_window:
            filename = view.file_name()
            cabal_proj_dir = Common.get_cabal_project_dir_of_file(filename) or os.path.dirname(filename)
            show_panel = not fly_mode and self.messages
            output_text = self.format_output_messages()
            sublime.set_timeout(functools.partial(self.make_message_panel, view, output_text, cabal_proj_dir, show_panel), 0)

        sublime.set_timeout(self.update_markers_across_views, 0)
Beispiel #9
0
def call_ghcmod_and_wait(arg_list, filename=None, cabal=None):
    """
    Calls ghc-mod with the given arguments.
    Shows a sublime error message if ghc-mod is not available.
    """

    ghc_opts_args = get_ghc_opts_args(filename, add_package_db=False, cabal=cabal)

    try:
        command = ['ghc-mod'] + ghc_opts_args + arg_list

        # Logging.log('running ghc-mod: {0}'.format(command))

        # Set cwd to user directory
        # Otherwise ghc-mod will fail with 'cannot satisfy package...'
        # Seems, that user directory works well
        # Current source directory is set with -i argument in get_ghc_opts_args
        #
        # When cabal project is available current directory is set to the project root
        # to avoid troubles with possible template haskell openFile calls
        ghc_mod_current_dir = ProcHelper.get_source_dir(filename)
        if filename:
            cabal_project_dir = Common.get_cabal_project_dir_of_file(filename)
            if cabal_project_dir:
                ghc_mod_current_dir = cabal_project_dir
        exit_code, out, err = ProcHelper.ProcHelper.run_process(command, cwd=ghc_mod_current_dir)

        if exit_code != 0:
            raise Exception("%s exited with status %d and stderr: %s" % (' '.join(command), exit_code, err))

        # return crlf2lf(out)
        return out

    except OSError as os_exc:
        if os_exc.errno == errno.ENOENT:
            Common.output_error_async(sublime.active_window(),
                                      "SublimeHaskell: ghc-mod was not found!\n"
                                      "It is used for LANGUAGE and import autocompletions and type inference.\n"
                                      "Try adjusting the 'add_to_PATH' setting.\n"
                                      "You can also turn this off using the 'enable_ghc_mod' setting.")
        # Re-raise so that calling code doesn't try to work on the `None` return value
        raise os_exc
Beispiel #10
0
    def on_autofix(self, corrections):
        # Oh, this looks pretty ugly. But, list comprehensions are supposedly faster than loops. And since this is
        # is supporting Haskell, why not use the functional approach? :-)
        output_messages = [ParseOutput.OutputMessage(msg.get('source', {}).get('file', '<no file/command line/OPTIONS_GHC>'),
                                                     HsResultParse.parse_region(msg.get('region')).to_zero_based() \
                                                       if msg.get('region') is not None else Symbols.Region(0),
                                                     msg.get('level', 'uncategorized').capitalize() + ': ' + \
                                                       msg.get('note', {}).get('message', '').replace('\n', '\n  '),
                                                     msg.get('level', 'uncategorized'))
                           for msg in self.msgs]

        # Hack alert: Region and Position.to_zero_based() return the original object (self) after updating it. 'and' returns the
        # right hand side, which is never None or a false value.
        self.corrections_dict = dict(
            ((os.path.normpath(c.file), c.message_region.start.line,
              c.message_region.start.column), c) for c in [
                  corr.message_region.to_zero_based() and corr
                  for corr in corrections or []
              ])

        for omsg in output_messages:
            okey = (os.path.normpath(omsg.filename), omsg.region.start.line,
                    omsg.region.start.column)
            if okey in self.corrections_dict:
                omsg.correction = self.corrections_dict[okey]

        ParseOutput.set_global_error_messages(output_messages)
        output_text = ParseOutput.format_output_messages(output_messages)
        if Settings.PLUGIN.show_error_window:
            cabal_proj_dir = Common.get_cabal_project_dir_of_file(
                self.filename) or os.path.dirname(self.filename)
            panel_display = not self.fly_mode and output_messages
            sublime.set_timeout(
                lambda: ParseOutput.write_output(
                    self.view, output_text, cabal_proj_dir, panel_display), 0)
        sublime.set_timeout(
            lambda: ParseOutput.mark_messages_in_views(output_messages), 0)