Beispiel #1
0
class EditorContext(object):
    search_id_lock = threading.Lock()

    # FIXME(guillermooo): This is utterly wrong. This needs to be a singleton.
    def __init__(self):
        self._search_id = None
        self.results_panel = None

    @property
    def search_id(self):
        with EditorContext.search_id_lock:
            return self._search_id

    @search_id.setter
    def search_id(self, value):
        with EditorContext.search_id_lock:
            if self._search_id == value:
                return
            self.results_panel = OutputPanel('dart.search.results')
            self.results_panel.set('result_file_regex',
                                   r'^\w+\s+-\s+(.*?):(\d+):(\d+)')
            self._search_id = value

    @search_id.deleter
    def search_id(self):
        with EditorContext.search_id_lock:
            self._search_id = None

    def check_token(self, action, token):
        if action == 'search':
            if self.search_id is None:
                return
            return (token == self.search_id)

    def append_search_results(self, items):
        items = list(items)
        with EditorContext.search_id_lock:
            if not self.results_panel:
                return

            for item in items:
                self.results_panel.write(item.to_encoded_pos())

            self.results_panel.show()
class EditorContext(object):
    search_id_lock = threading.Lock()

    # FIXME(guillermooo): This is utterly wrong. This needs to be a singleton.
    def __init__(self):
        self._search_id = None
        self.results_panel = None

    @property
    def search_id(self):
        with EditorContext.search_id_lock:
            return self._search_id

    @search_id.setter
    def search_id(self, value):
        with EditorContext.search_id_lock:
            if self._search_id == value:
                return
            self.results_panel = OutputPanel('dart.search.results')
            self.results_panel.set('result_file_regex', r'^\w+\s+-\s+(.*?):(\d+):(\d+)')
            self._search_id = value

    @search_id.deleter
    def search_id(self):
        with EditorContext.search_id_lock:
            self._search_id = None

    def check_token(self, action, token):
        if action == 'search':
            if self.search_id is None:
                return
            return (token == self.search_id)

    def append_search_results(self, items):
        items = list(items)
        with EditorContext.search_id_lock:
            if not self.results_panel:
                return

            for item in items:
                self.results_panel.write(item.to_encoded_pos())

            self.results_panel.show()
def show_errors(errors):
    '''Show errors in the ui.

    @errors
      An instance of `ErrorInfoCollection`.
    '''
    v = sublime.active_window().active_view()
    # TODO(guillermooo): Use tokens to identify requests:file.
    if errors.file != v.file_name():
        _logger.debug('different view active - aborting')
        return

    if len(errors) == 0:
        clear_ui()
        return

    _logger.debug('displaying errors to the user')

    v.add_regions('dart.infos',
                  list(errors.infos_to_regions(v)),
                  scope='dartlint.mark.info',
                  icon="Packages/Dart/gutter/dartlint-simple-info.png",
                  flags=_flags)

    v.add_regions('dart.warnings',
                  list(errors.warnings_to_regions(v)),
                  scope='dartlint.mark.warning',
                  icon="Packages/Dart/gutter/dartlint-simple-warning.png",
                  flags=_flags)

    v.add_regions('dart.errors',
                  list(errors.errors_to_regions(v)),
                  scope='dartlint.mark.error',
                  icon='Packages/Dart/gutter/dartlint-simple-error.png',
                  flags=_flags)

    # TODO(guillermooo): Add a logger attrib to the OutputPanel.
    panel = OutputPanel('dart.analyzer')
    errors_pattern = r'^\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|(.+)$'
    panel.set('result_file_regex', errors_pattern)
    panel.write('\n'.join(set(errors.to_compact_text())))
Beispiel #4
0
def show_errors(errors):
    '''Show errors in the ui.

    @errors
      An instance of `ErrorInfoCollection`.
    '''
    v = sublime.active_window().active_view()
    # TODO(guillermooo): Use tokens to identify requests:file.
    if errors.file != v.file_name():
        _logger.debug('different view active - aborting')
        return

    if len(errors) == 0:
        clear_ui()
        return

    _logger.debug('displaying errors to the user')

    v.add_regions('dart.infos', list(errors.infos_to_regions(v)),
        scope='dartlint.mark.info',
        icon="Packages/Dart/gutter/dartlint-simple-info.png",
        flags=_flags)

    v.add_regions('dart.warnings', list(errors.warnings_to_regions(v)),
        scope='dartlint.mark.warning',
        icon="Packages/Dart/gutter/dartlint-simple-warning.png",
        flags=_flags)

    v.add_regions('dart.errors', list(errors.errors_to_regions(v)),
        scope='dartlint.mark.error',
        icon='Packages/Dart/gutter/dartlint-simple-error.png',
        flags=_flags)

    # TODO(guillermooo): Add a logger attrib to the OutputPanel.
    panel = OutputPanel('dart.analyzer')
    errors_pattern = r'^\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|(.+)$'
    panel.set('result_file_regex', errors_pattern)
    panel.write('\n'.join(set(errors.to_compact_text())))
class EditorContext(object):
    write_lock = threading.Lock()
    search_id_lock = threading.Lock()

    # FIXME(guillermooo): This is utterly wrong. This needs to be a singleton.
    def __init__(self):
        self._search_id = None
        self.results_panel = None
        self._navigation = None
        self._errors = []
        self._errors_index = -1

    @property
    def search_id(self):
        with EditorContext.search_id_lock:
            return self._search_id

    @search_id.setter
    def search_id(self, value):
        with EditorContext.search_id_lock:
            if self._search_id == value:
                return
            self.results_panel = OutputPanel('dart.search.results')
            self.results_panel.set('result_file_regex',
                                   r'^\w+\s+-\s+(.*?):(\d+):(\d+)')
            self._search_id = value

    @search_id.deleter
    def search_id(self):
        with EditorContext.search_id_lock:
            self._search_id = None

    @property
    def navigation(self):
        with EditorContext.write_lock:
            return self._navigation

    @navigation.setter
    def navigation(self, value):
        # TODO(guillermooo): store this data by file
        with EditorContext.write_lock:
            self._navigation = value

    @property
    def errors(self):
        with EditorContext.write_lock:
            return self._errors

    @errors.setter
    def errors(self, values):
        with EditorContext.write_lock:
            self._errors_index = -1
            self._errors = list(values)

    @property
    def errors_index(self):
        with EditorContext.write_lock:
            return self._errors_index

    def increment_error_index(self):
        with EditorContext.write_lock:
            if self._errors_index == len(self._errors) - 1:
                raise IndexError('end of errors list')
            self._errors_index += 1

    def decrement_error_index(self):
        with EditorContext.write_lock:
            if self._errors_index == 0:
                raise IndexError('start of errors list')
            self._errors_index -= 1

    def get_current_error(self):
        return self.errors[self.errors_index]

    def check_token(self, action, token):
        if action == 'search':
            if self.search_id is None:
                return
            return (token == self.search_id)

    def append_search_results(self, items):
        items = list(items)
        with EditorContext.search_id_lock:
            if not self.results_panel:
                return

            for item in items:
                self.results_panel.write(item.to_encoded_pos())

            self.results_panel.show()
Beispiel #6
0
def show_errors(errors):
    '''Show errors in the ui.

    @errors
      An instance of `ErrorInfoCollection`.
    '''
    v = sublime.active_window().active_view()
    # TODO(guillermooo): Use tokens to identify requests:file.
    # todo (pp): notifications don't have id; process all
    if os.path.realpath(errors.file) != os.path.realpath(v.file_name()):
        _logger.debug('different view active - aborting')
        return

    analysis_errors = list(errors.errors)
    if analysis_errors == 0:
        clear_ui()
        return

    infos = [
        ae for ae in analysis_errors
        if (ae.severity == AnalysisErrorSeverity.INFO)
    ]
    warns = [
        ae for ae in analysis_errors
        if (ae.severity == AnalysisErrorSeverity.WARNING)
    ]
    erros = [
        ae for ae in analysis_errors
        if (ae.severity == AnalysisErrorSeverity.ERROR)
    ]

    def error_to_region(view, error):
        '''Converts location data to region data.
        '''
        loc = error.location
        pt = view.text_point(loc.startLine - 1, loc.startColumn - 1)
        return sublime.Region(pt, pt + loc.length)

    info_regs = [error_to_region(v, item) for item in infos]
    warn_regs = [error_to_region(v, item) for item in warns]
    errs_regs = [error_to_region(v, item) for item in erros]

    _logger.debug('displaying errors to the user')

    v.add_regions(DAS_UI_REGIONS_INFOS,
                  info_regs,
                  scope=DAS_SCOPE_INFO,
                  icon="Packages/Dart/gutter/dartlint-simple-info.png",
                  flags=_flags)

    v.add_regions(DAS_UI_REGIONS_WARNINGS,
                  warn_regs,
                  scope=DAS_SCOPE_WARNING,
                  icon="Packages/Dart/gutter/dartlint-simple-warning.png",
                  flags=_flags)

    v.add_regions(DAS_UI_REGIONS_ERRORS,
                  errs_regs,
                  scope=DAS_SCOPE_ERROR,
                  icon='Packages/Dart/gutter/dartlint-simple-error.png',
                  flags=_flags)

    def to_compact_text(error):
        return ("{error.severity}|{error.type}|{loc.file}|"
                "{loc.startLine}|{loc.startColumn}|{error.message}").format(
                    error=error, loc=error.location)

    info_patts = [to_compact_text(item) for item in infos]
    warn_patts = [to_compact_text(item) for item in warns]
    errs_patts = [to_compact_text(item) for item in erros]

    all_errs = set(errs_patts + warn_patts + info_patts)

    panel = OutputPanel('dart.analyzer')
    errors_pattern = r'^\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|(.+)$'
    panel.set('result_file_regex', errors_pattern)
    panel.write('\n'.join(all_errs))
Beispiel #7
0
    def __call__(self, errors):
        '''Show errors in the ui.

        @errors
          An instance of `ErrorInfoCollection`.
        '''
        view = get_active_view()

        # TODO(guillermooo): Use tokens to identify requests:file.
        if not self.compare_paths(errors.file, view.file_name()):
            _logger.debug('different view active - aborting')
            return

        panel = OutputPanel('dart.analyzer')

        analysis_errors = list(errors.errors)
        infos, warns, erros = self.group(analysis_errors)

        if len(infos + warns + erros) == 0:
            clear_ui()
            panel.hide()
            return

        info_regs = [self.error_to_region(view, item) for item in infos]
        warn_regs = [self.error_to_region(view, item) for item in warns]
        errs_regs = [self.error_to_region(view, item) for item in erros]

        _logger.debug('displaying errors to the user')

        self.add_regions(view, info_regs, warn_regs, errs_regs)

        all_sorted = sorted(infos + warns + erros,
                            key=lambda x: x.location.offset)
        all_errs = (self.to_compact_text(item) for item in all_sorted)

        # TODO(guillermooo): abstract out the panel stuff into a DartErrorPanel class.
        panel = OutputPanel('dart.analyzer')

        # Tried to use .sublime-settings for this, but it won't work well.
        errors_pattern = r'^\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|(.+)$'
        panel.set('result_file_regex', errors_pattern)
        all_errs = list(all_errs)
        # Overwrite any previous text in the panel.

        # We get errors sometimes when writing error lines here.
        panel.write('\n'.join(all_errs))

        # TODO(guillermooo): remove this when .sublime-syntax has been fully
        # adopted.
        if sublime.version() >= '3084':
            panel.view.set_syntax_file(
                'Packages/Dart/Support/Analyzer Output.sublime-syntax')
        else:
            panel.view.set_syntax_file(
                'Packages/Dart/Support/Analyzer Output.tmLanguage')

        editor_context.errors = all_errs
        panel.show()

        try:
            view.show(view.sel()[0])
        except IndexError:
            pass

        sublime.status_message("Dart: Errors found")
class EditorContext(object):
    write_lock = threading.Lock()
    search_id_lock = threading.Lock()

    # FIXME(guillermooo): This is utterly wrong. This needs to be a singleton.
    def __init__(self):
        self._search_id = None
        self.results_panel = None
        self._navigation = None
        self._errors = []
        self._errors_index = -1

    @property
    def search_id(self):
        with EditorContext.search_id_lock:
            return self._search_id

    @search_id.setter
    def search_id(self, value):
        with EditorContext.search_id_lock:
            if self._search_id == value:
                return
            self.results_panel = OutputPanel('dart.search.results')
            self.results_panel.set('result_file_regex', r'^\w+\s+-\s+(.*?):(\d+):(\d+)')
            self._search_id = value

    @search_id.deleter
    def search_id(self):
        with EditorContext.search_id_lock:
            self._search_id = None

    @property
    def navigation(self):
        with EditorContext.write_lock:
            return self._navigation

    @navigation.setter
    def navigation(self, value):
        # TODO(guillermooo): store this data by file
        with EditorContext.write_lock:
            self._navigation = value

    @property
    def errors(self):
        with EditorContext.write_lock:
            return self._errors

    @errors.setter
    def errors(self, values):
        with EditorContext.write_lock:
            self._errors_index = -1
            self._errors = list(values)

    @property
    def errors_index(self):
        with EditorContext.write_lock:
            return self._errors_index

    def increment_error_index(self):
        with EditorContext.write_lock:
            if self._errors_index == len(self._errors) - 1:
                raise IndexError('end of errors list')
            self._errors_index += 1

    def decrement_error_index(self):
        with EditorContext.write_lock:
            if self._errors_index == 0:
                raise IndexError('start of errors list')
            self._errors_index -= 1

    def get_current_error(self):
        return self.errors[self.errors_index]

    def check_token(self, action, token):
        if action == 'search':
            if self.search_id is None:
                return
            return (token == self.search_id)

    def append_search_results(self, items):
        items = list(items)
        with EditorContext.search_id_lock:
            if not self.results_panel:
                return

            for item in items:
                self.results_panel.write(item.to_encoded_pos())

            self.results_panel.show()
    def run(self):
        """Runs forever checking for new linter results and displaying them
        to the user.
        """
        while True:
            # Run at intervals.
            time.sleep(0.250)

            # We've got results for this buffer. Reset its version count so
            # the linting cycle can start again.
            # TODO(guillermooo): It's possible that we'll miss some edits (?).
            with g_edits_lock:
                DartLint.edits[self.view.buffer_id()] = 0

            lines = self.get_data()
            if lines is None:
                continue

            # TODO(guillermooo): Compose a DartLintOutputPanel from a plain
            # OutputPanel to abstract all of this away.
            # Show errors in output panel and enable error navigation via F4.
            panel = OutputPanel('dart.analyzer')
            # Capture file name, rowcol and error message information.
            errors_pattern = r'^\w+\|\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|\d+\|(.+)'
            panel.set('result_file_regex', errors_pattern)
            panel.write('\n'.join(lines))
            panel.show()

            pattern = (r'^(?P<severity>\w+)\|(?P<type>\w+)\|(?P<code>\w+)\|' +
                r'(?P<file_name>.+)\|(?P<line>\d+)\|(?P<col>\d+)\|' +
                r'(?P<err_length>\d+)\|(?P<message>.+)')
            msg_pattern_machine = re.compile(pattern)

            # Collect data needed to generate error messages
            lint_data = []
            lines_out = ''
            err_count = 0
            culp_regions = {}
            for line in lines:
                line_out = ''
                line_data = {}
                line_groups = msg_pattern_machine.match(line)
                if line_groups is not None:
                    if line_groups.group('file_name') != self.fileName:
                        # output is for a different file
                        continue
                    line_out = '%s: %s on line %s, col %s: %s\n' % \
                        (line_groups.group('severity'),
                         line_groups.group('code'),
                         line_groups.group('line'),
                         line_groups.group('col'),
                         line_groups.group('message'))

                    line_data['severity'] = line_groups.group('severity')
                    line_data['col'] = line_groups.group('col')
                    line_data['line'] = line_groups.group('line')
                    line_data['msg'] = line_groups.group('message')
                    line_data['code'] = line_groups.group('code')
                    line_data['type'] = line_groups.group('type')
                    line_data['err_length'] = line_groups.group('err_length')
                    line_data['lint_out'] = line_out
                    line_data['line_pt'] = self.view.text_point(
                        int(line_data['line']) - 1, 0)
                    line_data['point'] = self.view.text_point(
                        int(line_data['line']) - 1, int(line_data['col']))
                    next_line = self.view.text_point(int(line_data['line']), 0)

                    # Add a region (gutter mark and underline)
                    if int(line_data['err_length']) > 0 and \
                            int(line_data['point']) + \
                            (int(line_data['err_length']) - 1) < next_line:
                        # Set the error region
                        line_data['culp_region'] = sublime.Region(
                            int(line_data['point']) - 1,
                            int(line_data['point']) +
                            (int(line_data['err_length']) - 1))
                    else:
                        # Set the line as the error region
                        line_data['culp_region'] = self.view.line(
                            line_data['line_pt'])
                    # Add the region to the apropriate region collection
                    if ('dartlint_' + line_data['severity']) not in \
                            culp_regions.keys():
                        culp_regions['dartlint_%s' % line_data['severity']] = []
                    culp_regions['dartlint_%s' % line_data['severity']].append(
                        line_data['culp_region'])
                    lines_out += line_out
                    lint_data.append(line_data)
                    err_count += 1
            for reg_id in culp_regions.keys():
                # set the scope name
                reg_list = culp_regions[reg_id]
                this_scope = 'dartlint.mark.warning'
                if reg_id.endswith('ERROR') is True:
                    this_scope = 'dartlint.mark.error'
                if reg_id.endswith('INFO') is True:
                    this_scope = 'dartlint.mark.info'
                # Seperate gutter and underline regions
                gutter_reg = []
                for reg in reg_list:
                    gutter_reg.append(self.view.line(reg.begin()))
                self.view.add_regions(
                    reg_id + '_gutter',
                    gutter_reg,
                    # set this to this_scope for tinted gutter icons
                    'dartlint.mark.gutter',
                    icon=GUTTER_Icon[reg_id],
                    flags=SCOPES_Dartlint['dartlint.mark.gutter']['flags'])
                self.view.add_regions(
                    reg_id,
                    reg_list,
                    this_scope,
                    flags=SCOPES_Dartlint[this_scope]['flags'])
                # Set icon presidence?
            if lines_out is '':
                self.output = None
                print('No errors.')
                self.view.set_status('dartlint', 'Dartlint: No errors')
            else:
                # Sort list
                idx = 0
                err_keys = []
                for entry in lint_data:
                    line_val = '{0:{fill}{align}16}'.format(
                        entry['line'], fill='0', align='>')
                    col_val = '{0:{fill}{align}16}'.format(
                        entry['col'], fill='0', align='>')
                    list_val = '%s-%s-%s' % (line_val, col_val, str(idx))
                    err_keys.append(list_val)
                    idx += 1
                new_err_list = []
                err_keys.sort()
                for ek in err_keys:
                    new_err_list.append(lint_data[int(ek.split('-')[2])])
                self.output = new_err_list
                # Out to console
                print('\n' + lines_out)
Beispiel #10
0
class DartExecCommand(sublime_plugin.WindowCommand, ProcessListener):
    def run(self,
            cmd=None,
            shell_cmd=None,
            file_regex="",
            line_regex="",
            working_dir="",
            encoding="utf-8",
            env={},
            quiet=False,
            kill=False,
            word_wrap=True,
            syntax="Packages/Text/Plain text.tmLanguage",
            preamble='',
            panel_name='dart.out',
            # Catches "path" and "shell"
            **kwargs):

        if kill:
            if hasattr(self, 'proc') and self.proc:
                self.proc.kill()
                self.proc = None
                self.append_string(None, "[Cancelled]")
            return

        # TODO(guillermooo): We cannot have multiple processes running at the
        # same time, or processes that use separate output panels.
        if not hasattr(self, 'out_panel'):
            # Try not to call get_output_panel until the regexes are assigned
            self.out_panel = OutputPanel(panel_name)

        # Default to the current files directory if no working directory was given
        if (not working_dir and
            self.window.active_view() and
            self.window.active_view().file_name()):
                working_dir = os.path.dirname(
                                        self.window.active_view().file_name())

        self.out_panel.set("result_file_regex", file_regex)
        self.out_panel.set("result_line_regex", line_regex)
        self.out_panel.set("result_base_dir", working_dir)
        self.out_panel.set("word_wrap", word_wrap)
        self.out_panel.set("line_numbers", False)
        self.out_panel.set("gutter", False)
        self.out_panel.set("scroll_past_end", False)
        self.out_panel.view.assign_syntax(syntax)

        self.encoding = encoding
        self.quiet = quiet

        self.proc = None
        if not self.quiet:
            if shell_cmd:
                print("Running " + shell_cmd)
            else:
                print("Running " + " ".join(cmd))
            sublime.status_message("Building")

        if preamble:
            self.append_string(self.proc, preamble)

        show_panel_on_build = sublime.load_settings(
              "Dart - Plugin Settings.sublime-settings").get("show_panel_on_build", True)
        if show_panel_on_build:
            self.out_panel.show()

        merged_env = env.copy()
        if self.window.active_view():
            user_env = self.window.active_view().settings().get('build_env')
            if user_env:
                merged_env.update(user_env)

        # Change to the working dir, rather than spawning the process with it,
        # so that emitted working dir relative path names make sense
        if working_dir:
            os.chdir(working_dir)

        self.debug_text = ""
        if shell_cmd:
            self.debug_text += "[shell_cmd: " + shell_cmd + "]\n"
        else:
            self.debug_text += "[cmd: " + str(cmd) + "]\n"
        self.debug_text += "[dir: " + str(os.getcwd()) + "]\n"
        if "PATH" in merged_env:
            self.debug_text += "[path: " + str(merged_env["PATH"]) + "]"
        else:
            self.debug_text += "[path: " + str(os.environ["PATH"]) + "]"

        try:
            # Forward kwargs to AsyncProcess
            self.proc = AsyncProcess(cmd, shell_cmd, merged_env, self,
                                     **kwargs)
        except Exception as e:
            self.append_string(None, str(e) + "\n")
            self.append_string(None, self.debug_text + "\n")
            if not self.quiet:
                self.append_string(None, "[Finished]")

    def append_data(self, proc, data):
        if proc != self.proc:
            # a second call to exec has been made before the first one
            # finished, ignore it instead of intermingling the output.
            if proc:
                proc.kill()
            return

        try:
            str_ = data.decode(self.encoding)
        except UnicodeEncodeError:
            str_ = "[Decode error - output not " + self.encoding + "]\n"
            proc = None
            return

        # Normalize newlines, Sublime Text always uses a single \n separator
        # in memory.
        str_ = str_.replace('\r\n', '\n').replace('\r', '\n')

        self.out_panel.write(str_)

    def append_string(self, proc, str):
        self.append_data(proc, str.encode(self.encoding))

    def finish(self, proc):
        if not self.quiet:
            elapsed = time.time() - proc.start_time
            exit_code = proc.exit_code()
            if (exit_code == 0) or (exit_code == None):
                self.append_string(proc, "[Finished in %.1fs]" % (elapsed))
            else:
                self.append_string(proc,
                    "[Finished in %.1fs with exit code %d]\n" %
                                                        (elapsed, exit_code))
                self.append_string(proc, self.debug_text)

        if proc != self.proc:
            return

        # XXX: What's this for?
        errs = self.out_panel.view.find_all_results()
        if len(errs) == 0:
            sublime.status_message("Build finished")
        else:
            sublime.status_message(("Build finished with %d errors") % len(errs))

    def on_data(self, proc, data):
        after(0, functools.partial(self.append_data, proc, data))

    def on_finished(self, proc):
        after(0, functools.partial(self.finish, proc))
Beispiel #11
0
def show_errors(errors):
    '''Show errors in the ui.

    @errors
      An instance of `ErrorInfoCollection`.
    '''
    v = sublime.active_window().active_view()
    # TODO(guillermooo): Use tokens to identify requests:file.
    # todo (pp): notifications don't have id; process all
    if os.path.realpath(errors.file) != os.path.realpath(v.file_name()):
        _logger.debug('different view active - aborting')
        return

    analysis_errs = list(errors.errors)
    if analysis_errs == 0:
        clear_ui()
        return

    infos = [ae for ae in analysis_errs if (ae.severity == AnalysisErrorSeverity.INFO)]
    warns = [ae for ae in analysis_errs if (ae.severity == AnalysisErrorSeverity.WARNING)]
    erros = [ae for ae in analysis_errs if (ae.severity == AnalysisErrorSeverity.ERROR)]

    def error_to_region(view, error):
        '''Converts location data to region data.
        '''
        loc = Location(error.location)
        pt = view.text_point(loc.startLine - 1,
                             loc.startColumn - 1)
        return sublime.Region(pt, pt + loc.length)

    info_regs = [error_to_region(v, item) for item in infos]
    warn_regs = [error_to_region(v, item) for item in warns]
    errs_regs = [error_to_region(v, item) for item in erros]

    _logger.debug('displaying errors to the user')

    v.add_regions('dart.infos', info_regs,
        scope='dartlint.mark.info',
        icon="Packages/Dart/gutter/dartlint-simple-info.png",
        flags=_flags)

    v.add_regions('dart.warnings', warn_regs,
        scope='dartlint.mark.warning',
        icon="Packages/Dart/gutter/dartlint-simple-warning.png",
        flags=_flags)

    v.add_regions('dart.errors', errs_regs,
        scope='dartlint.mark.error',
        icon='Packages/Dart/gutter/dartlint-simple-error.png',
        flags=_flags)

    def to_compact_text(error):
        return ("{error.severity}|{error.type}|{loc.file}|"
                "{loc.startLine}|{loc.startColumn}|{error.message}").format(
                                                error=error, loc=Location(error.location))

    info_patts = [to_compact_text(item) for item in infos]
    warn_patts = [to_compact_text(item) for item in warns]
    errs_patts = [to_compact_text(item) for item in erros]

    all_errs = set(errs_patts + warn_patts + info_patts)

    panel = OutputPanel('dart.analyzer')
    errors_pattern = r'^\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|(.+)$'
    panel.set('result_file_regex', errors_pattern)
    panel.write('\n'.join(all_errs))
class DartExecCommand(sublime_plugin.WindowCommand, ProcessListener):
    def run(
            self,
            cmd=None,
            shell_cmd=None,
            file_regex="",
            line_regex="",
            working_dir="",
            encoding="utf-8",
            env={},
            quiet=False,
            kill=False,
            word_wrap=True,
            syntax="Packages/Text/Plain text.tmLanguage",
            preamble='',
            panel_name='dart.out',
            # Catches "path" and "shell"
            **kwargs):

        if kill:
            if hasattr(self, 'proc') and self.proc:
                self.proc.kill()
                self.proc = None
                self.append_string(None, "[Cancelled]")
            return

        # TODO(guillermooo): We cannot have multiple processes running at the
        # same time, or processes that use separate output panels.
        if not hasattr(self, 'out_panel'):
            # Try not to call get_output_panel until the regexes are assigned
            self.out_panel = OutputPanel(panel_name)

        # Default to the current files directory if no working directory was given
        if (not working_dir and self.window.active_view()
                and self.window.active_view().file_name()):
            working_dir = os.path.dirname(
                self.window.active_view().file_name())

        self.out_panel.set("result_file_regex", file_regex)
        self.out_panel.set("result_line_regex", line_regex)
        self.out_panel.set("result_base_dir", working_dir)
        self.out_panel.set("word_wrap", word_wrap)
        self.out_panel.set("line_numbers", False)
        self.out_panel.set("gutter", False)
        self.out_panel.set("scroll_past_end", False)
        self.out_panel.view.assign_syntax(syntax)

        self.encoding = encoding
        self.quiet = quiet

        self.proc = None
        if not self.quiet:
            if shell_cmd:
                print("Running " + shell_cmd)
            else:
                print("Running " + " ".join(cmd))
            sublime.status_message("Building")

        if preamble:
            self.append_string(self.proc, preamble)

        show_panel_on_build = sublime.load_settings(
            "Dart - Plugin Settings.sublime-settings").get(
                "show_panel_on_build", True)
        if show_panel_on_build:
            self.out_panel.show()

        merged_env = env.copy()
        if self.window.active_view():
            user_env = self.window.active_view().settings().get('build_env')
            if user_env:
                merged_env.update(user_env)

        # Change to the working dir, rather than spawning the process with it,
        # so that emitted working dir relative path names make sense
        if working_dir:
            os.chdir(working_dir)

        self.debug_text = ""
        if shell_cmd:
            self.debug_text += "[shell_cmd: " + shell_cmd + "]\n"
        else:
            self.debug_text += "[cmd: " + str(cmd) + "]\n"
        self.debug_text += "[dir: " + str(os.getcwd()) + "]\n"
        if "PATH" in merged_env:
            self.debug_text += "[path: " + str(merged_env["PATH"]) + "]"
        else:
            self.debug_text += "[path: " + str(os.environ["PATH"]) + "]"

        try:
            # Forward kwargs to AsyncProcess
            self.proc = AsyncProcess(cmd, shell_cmd, merged_env, self,
                                     **kwargs)
        except Exception as e:
            self.append_string(None, str(e) + "\n")
            self.append_string(None, self.debug_text + "\n")
            if not self.quiet:
                self.append_string(None, "[Finished]")

    def append_data(self, proc, data):
        if proc != self.proc:
            # a second call to exec has been made before the first one
            # finished, ignore it instead of intermingling the output.
            if proc:
                proc.kill()
            return

        try:
            str_ = data.decode(self.encoding)
        except UnicodeEncodeError:
            str_ = "[Decode error - output not " + self.encoding + "]\n"
            proc = None
            return

        # Normalize newlines, Sublime Text always uses a single \n separator
        # in memory.
        str_ = str_.replace('\r\n', '\n').replace('\r', '\n')

        self.out_panel.write(str_)

    def append_string(self, proc, str):
        self.append_data(proc, str.encode(self.encoding))

    def finish(self, proc):
        if not self.quiet:
            elapsed = time.time() - proc.start_time
            exit_code = proc.exit_code()
            if (exit_code == 0) or (exit_code == None):
                self.append_string(proc, "[Finished in %.1fs]" % (elapsed))
            else:
                self.append_string(
                    proc, "[Finished in %.1fs with exit code %d]\n" %
                    (elapsed, exit_code))
                self.append_string(proc, self.debug_text)

        if proc != self.proc:
            return

        # XXX: What's this for?
        errs = self.out_panel.view.find_all_results()
        if len(errs) == 0:
            sublime.status_message("Build finished")
        else:
            sublime.status_message(
                ("Build finished with %d errors") % len(errs))

    def on_data(self, proc, data):
        after(0, functools.partial(self.append_data, proc, data))

    def on_finished(self, proc):
        after(0, functools.partial(self.finish, proc))
def show_errors(errors):
    '''Show errors in the ui.

    @errors
      An instance of `ErrorInfoCollection`.
    '''
    v = sublime.active_window().active_view()
    # TODO(guillermooo): Use tokens to identify requests:file.
    # todo (pp): notifications don't have id; process all
    if os.path.realpath(errors.file) != os.path.realpath(v.file_name()):
        _logger.debug('different view active - aborting')
        return

    analysis_errors = list(errors.errors)
    if analysis_errors == 0:
        clear_ui()
        return

    infos = [
        ae for ae in analysis_errors
        if (ae.severity == AnalysisErrorSeverity.INFO) and (
            ae.type != AnalysisErrorType.TODO)
    ]
    warns = [
        ae for ae in analysis_errors
        if (ae.severity == AnalysisErrorSeverity.WARNING)
    ]
    erros = [
        ae for ae in analysis_errors
        if (ae.severity == AnalysisErrorSeverity.ERROR)
    ]

    def error_to_region(view, error):
        '''Converts location data to region data.
        '''
        pass
        loc = error.location
        pt = view.text_point(loc.startLine - 1, loc.startColumn - 1)
        return sublime.Region(pt, pt + loc.length)

    info_regs = [error_to_region(v, item) for item in infos]
    warn_regs = [error_to_region(v, item) for item in warns]
    errs_regs = [error_to_region(v, item) for item in erros]

    _logger.debug('displaying errors to the user')

    v.add_regions(DAS_UI_REGIONS_INFOS,
                  info_regs,
                  scope=DAS_SCOPE_INFO,
                  icon="Packages/Dart/gutter/dartlint-simple-info.png",
                  flags=_flags)

    v.add_regions(DAS_UI_REGIONS_WARNINGS,
                  warn_regs,
                  scope=DAS_SCOPE_WARNING,
                  icon="Packages/Dart/gutter/dartlint-simple-warning.png",
                  flags=_flags)

    v.add_regions(DAS_UI_REGIONS_ERRORS,
                  errs_regs,
                  scope=DAS_SCOPE_ERROR,
                  icon='Packages/Dart/gutter/dartlint-simple-error.png',
                  flags=_flags)

    def to_compact_text(error):
        return ("{error.severity}|{error.type}|{loc.file}|"
                "{loc.startLine}|{loc.startColumn}|{error.message}").format(
                    error=error, loc=error.location)

    info_patts = [to_compact_text(item) for item in infos]
    warn_patts = [to_compact_text(item) for item in warns]
    errs_patts = [to_compact_text(item) for item in erros]

    all_errs = set(errs_patts + warn_patts + info_patts)

    panel = OutputPanel('dart.analyzer')

    if not all_errs:
        editor_context.errors = []
        panel.hide()
        return

    errors_pattern = r'^\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|(.+)$'
    panel.set('result_file_regex', errors_pattern)
    # This will overwrite any previous text.
    panel.write('\n' + '\n'.join(all_errs))

    # FIXME: It appears that if ST dev find a .sublime-syntax and a .tmLanguage
    # file, it will load # the first one. But how do we refer to the file then?
    if sublime.version() >= '3084':
        panel.view.set_syntax_file(
            'Packages/Dart/Support/Analyzer Output.sublime-syntax')
    else:
        panel.view.set_syntax_file(
            'Packages/Dart/Support/Analyzer Output.tmLanguage')

    panel.view.settings().set('rulers', [])
    panel.show()
    sublime.status_message("Dart: Errors found")

    editor_context.errors = all_errs
    def run(self):
        """Runs forever checking for new linter results and displaying them
        to the user.
        """
        while True:
            # Run at intervals.
            time.sleep(0.250)

            # We've got results for this buffer. Reset its version count so
            # the linting cycle can start again.
            # TODO(guillermooo): It's possible that we'll miss some edits (?).
            with g_edits_lock:
                DartLint.edits[self.view.buffer_id()] = 0

            lines = self.get_data()
            if lines is None:
                continue

            # TODO(guillermooo): Compose a DartLintOutputPanel from a plain
            # OutputPanel to abstract all of this away.
            # Show errors in output panel and enable error navigation via F4.
            panel = OutputPanel('dart.analyzer')
            # Capture file name, rowcol and error message information.
            errors_pattern = r'^\w+\|\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|\d+\|(.+)'
            panel.set('result_file_regex', errors_pattern)
            panel.write('\n'.join(lines))
            panel.show()

            pattern = (r'^(?P<severity>\w+)\|(?P<type>\w+)\|(?P<code>\w+)\|' +
                       r'(?P<file_name>.+)\|(?P<line>\d+)\|(?P<col>\d+)\|' +
                       r'(?P<err_length>\d+)\|(?P<message>.+)')
            msg_pattern_machine = re.compile(pattern)

            # Collect data needed to generate error messages
            lint_data = []
            lines_out = ''
            err_count = 0
            culp_regions = {}
            for line in lines:
                line_out = ''
                line_data = {}
                line_groups = msg_pattern_machine.match(line)
                if line_groups is not None:
                    if line_groups.group('file_name') != self.fileName:
                        # output is for a different file
                        continue
                    line_out = '%s: %s on line %s, col %s: %s\n' % \
                        (line_groups.group('severity'),
                         line_groups.group('code'),
                         line_groups.group('line'),
                         line_groups.group('col'),
                         line_groups.group('message'))

                    line_data['severity'] = line_groups.group('severity')
                    line_data['col'] = line_groups.group('col')
                    line_data['line'] = line_groups.group('line')
                    line_data['msg'] = line_groups.group('message')
                    line_data['code'] = line_groups.group('code')
                    line_data['type'] = line_groups.group('type')
                    line_data['err_length'] = line_groups.group('err_length')
                    line_data['lint_out'] = line_out
                    line_data['line_pt'] = self.view.text_point(
                        int(line_data['line']) - 1, 0)
                    line_data['point'] = self.view.text_point(
                        int(line_data['line']) - 1, int(line_data['col']))
                    next_line = self.view.text_point(int(line_data['line']), 0)

                    # Add a region (gutter mark and underline)
                    if int(line_data['err_length']) > 0 and \
                            int(line_data['point']) + \
                            (int(line_data['err_length']) - 1) < next_line:
                        # Set the error region
                        line_data['culp_region'] = sublime.Region(
                            int(line_data['point']) - 1,
                            int(line_data['point']) +
                            (int(line_data['err_length']) - 1))
                    else:
                        # Set the line as the error region
                        line_data['culp_region'] = self.view.line(
                            line_data['line_pt'])
                    # Add the region to the apropriate region collection
                    if ('dartlint_' + line_data['severity']) not in \
                            culp_regions.keys():
                        culp_regions['dartlint_%s' %
                                     line_data['severity']] = []
                    culp_regions['dartlint_%s' % line_data['severity']].append(
                        line_data['culp_region'])
                    lines_out += line_out
                    lint_data.append(line_data)
                    err_count += 1
            for reg_id in culp_regions.keys():
                # set the scope name
                reg_list = culp_regions[reg_id]
                this_scope = 'dartlint.mark.warning'
                if reg_id.endswith('ERROR') is True:
                    this_scope = 'dartlint.mark.error'
                if reg_id.endswith('INFO') is True:
                    this_scope = 'dartlint.mark.info'
                # Seperate gutter and underline regions
                gutter_reg = []
                for reg in reg_list:
                    gutter_reg.append(self.view.line(reg.begin()))
                self.view.add_regions(
                    reg_id + '_gutter',
                    gutter_reg,
                    # set this to this_scope for tinted gutter icons
                    'dartlint.mark.gutter',
                    icon=GUTTER_Icon[reg_id],
                    flags=SCOPES_Dartlint['dartlint.mark.gutter']['flags'])
                self.view.add_regions(
                    reg_id,
                    reg_list,
                    this_scope,
                    flags=SCOPES_Dartlint[this_scope]['flags'])
                # Set icon presidence?
            if lines_out is '':
                self.output = None
                print('No errors.')
                self.view.set_status('dartlint', 'Dartlint: No errors')
            else:
                # Sort list
                idx = 0
                err_keys = []
                for entry in lint_data:
                    line_val = '{0:{fill}{align}16}'.format(entry['line'],
                                                            fill='0',
                                                            align='>')
                    col_val = '{0:{fill}{align}16}'.format(entry['col'],
                                                           fill='0',
                                                           align='>')
                    list_val = '%s-%s-%s' % (line_val, col_val, str(idx))
                    err_keys.append(list_val)
                    idx += 1
                new_err_list = []
                err_keys.sort()
                for ek in err_keys:
                    new_err_list.append(lint_data[int(ek.split('-')[2])])
                self.output = new_err_list
                # Out to console
                print('\n' + lines_out)
Beispiel #15
0
    def __call__(self, errors):
        '''Show errors in the ui.

        @errors
          An instance of `ErrorInfoCollection`.
        '''
        view = get_active_view()

        # TODO(guillermooo): Use tokens to identify requests:file.
        if not self.compare_paths(errors.file, view.file_name()):
            _logger.debug('different view active - aborting')
            return

        panel = OutputPanel('dart.errors')

        analysis_errors = list(errors.errors)
        infos, warns, erros = self.group(analysis_errors)

        if len(infos + warns + erros) == 0:
            clear_ui()
            panel.hide()
            return

        info_regs = [self.error_to_region(view, item) for item in infos]
        warn_regs = [self.error_to_region(view, item) for item in warns]
        errs_regs = [self.error_to_region(view, item) for item in erros]

        _logger.debug('displaying errors to the user')

        self.add_regions(view, info_regs, warn_regs, errs_regs)

        all_sorted = sorted(infos + warns + erros, key=lambda x: x.location.offset)
        all_errs = (self.to_compact_text(item) for item in all_sorted)

        # TODO(guillermooo): abstract out the panel stuff into a DartErrorPanel class.
        panel = OutputPanel('dart.errors')

        # Tried to use .sublime-settings for this, but it won't work well.
        errors_pattern = r'^\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|(.+)$'
        panel.set('result_file_regex', errors_pattern)
        all_errs = list(all_errs)
        # Overwrite any previous text in the panel.

        # We get errors sometimes when writing error lines here.
        panel.write('\n'.join(all_errs))

        # TODO(guillermooo): remove this when .sublime-syntax has been fully
        # adopted.
        if sublime.version() >= '3084':
            panel.view.set_syntax_file('Packages/Dart/Support/Analyzer Output.sublime-syntax')
        else:
            panel.view.set_syntax_file('Packages/Dart/Support/Analyzer Output.tmLanguage')

        editor_context.errors = all_errs
        # To show the panel, use the Command Palette or the key binding.
        # panel.show()

        try:
            view.show(view.sel()[0])
        except IndexError:
            pass

        sublime.status_message("Dart: Errors found")
def show_errors(errors):
    '''Show errors in the ui.

    @errors
      An instance of `ErrorInfoCollection`.
    '''
    v = sublime.active_window().active_view()
    # TODO(guillermooo): Use tokens to identify requests:file.
    # todo (pp): notifications don't have id; process all
    if os.path.realpath(errors.file) != os.path.realpath(v.file_name()):
        _logger.debug('different view active - aborting')
        return
    
    analysis_errors = list(errors.errors)
    if analysis_errors == 0:
        clear_ui()
        return

    infos = [ae for ae in analysis_errors if
                (ae.severity == AnalysisErrorSeverity.INFO)
                and (ae.type != AnalysisErrorType.TODO)]
    warns = [ae for ae in analysis_errors if (ae.severity == AnalysisErrorSeverity.WARNING)]
    erros = [ae for ae in analysis_errors if (ae.severity == AnalysisErrorSeverity.ERROR)]

    def error_to_region(view, error):
        '''Converts location data to region data.
        '''
        pass
        loc = error.location
        pt = view.text_point(loc.startLine - 1,
                             loc.startColumn - 1)
        return sublime.Region(pt, pt + loc.length)

    info_regs = [error_to_region(v, item) for item in infos]
    warn_regs = [error_to_region(v, item) for item in warns]
    errs_regs = [error_to_region(v, item) for item in erros]

    _logger.debug('displaying errors to the user')

    v.add_regions(DAS_UI_REGIONS_INFOS, info_regs,
        scope=DAS_SCOPE_INFO,
        icon="Packages/Dart/gutter/dartlint-simple-info.png",
        flags=_flags)

    v.add_regions(DAS_UI_REGIONS_WARNINGS, warn_regs,
        scope=DAS_SCOPE_WARNING,
        icon="Packages/Dart/gutter/dartlint-simple-warning.png",
        flags=_flags)

    v.add_regions(DAS_UI_REGIONS_ERRORS, errs_regs,
        scope=DAS_SCOPE_ERROR,
        icon='Packages/Dart/gutter/dartlint-simple-error.png',
        flags=_flags)

    def to_compact_text(error):
        return ("{error.severity}|{error.type}|{loc.file}|"
                "{loc.startLine}|{loc.startColumn}|{error.message}").format(
                                                error=error, loc=error.location)


    info_patts = [to_compact_text(item) for item in infos]
    warn_patts = [to_compact_text(item) for item in warns]
    errs_patts = [to_compact_text(item) for item in erros]

    all_errs = set(errs_patts + warn_patts + info_patts)

    panel = OutputPanel('dart.analyzer')

    if not all_errs:
        editor_context.errors = []
        panel.hide()
        return

    errors_pattern = r'^\w+\|\w+\|(.+)\|(\d+)\|(\d+)\|(.+)$'
    panel.set('result_file_regex', errors_pattern)
    # This will overwrite any previous text.
    panel.write('\n' + '\n'.join(all_errs))
    panel.view.set_syntax_file('Packages/Dart/Support/Analyzer Output.sublime-syntax')
    panel.view.settings().set('rulers', [])
    panel.show()
    sublime.status_message("Dart: Errors found")

    editor_context.errors = all_errs