summaryrefslogtreecommitdiffstats
path: root/python/mozlint/mozlint/formatters/stylish.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /python/mozlint/mozlint/formatters/stylish.py
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'python/mozlint/mozlint/formatters/stylish.py')
-rw-r--r--python/mozlint/mozlint/formatters/stylish.py156
1 files changed, 156 insertions, 0 deletions
diff --git a/python/mozlint/mozlint/formatters/stylish.py b/python/mozlint/mozlint/formatters/stylish.py
new file mode 100644
index 0000000000..3f80bc7ad2
--- /dev/null
+++ b/python/mozlint/mozlint/formatters/stylish.py
@@ -0,0 +1,156 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from mozterm import Terminal
+
+from ..result import Issue
+from ..util.string import pluralize
+
+
+class StylishFormatter(object):
+ """Formatter based on the eslint default."""
+
+ _indent_ = " "
+
+ # Colors later on in the list are fallbacks in case the terminal
+ # doesn't support colors earlier in the list.
+ # See http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html
+ _colors = {
+ "grey": [247, 8, 7],
+ "red": [1],
+ "green": [2],
+ "yellow": [3],
+ "brightred": [9, 1],
+ "brightyellow": [11, 3],
+ }
+
+ fmt = """
+ {c1}{lineno}{column} {c2}{level}{normal} {message} {c1}{rule}({linter}){normal}
+{diff}""".lstrip(
+ "\n"
+ )
+ fmt_summary = (
+ "{t.bold}{c}\u2716 {problem} ({error}, {warning}{failure}, {fixed}){t.normal}"
+ )
+
+ def __init__(self, disable_colors=False):
+ self.term = Terminal(disable_styling=disable_colors)
+ self.num_colors = self.term.number_of_colors
+
+ def color(self, color):
+ for num in self._colors[color]:
+ if num < self.num_colors:
+ return self.term.color(num)
+ return ""
+
+ def _reset_max(self):
+ self.max_lineno = 0
+ self.max_column = 0
+ self.max_level = 0
+ self.max_message = 0
+
+ def _update_max(self, err):
+ """Calculates the longest length of each token for spacing."""
+ self.max_lineno = max(self.max_lineno, len(str(err.lineno)))
+ if err.column:
+ self.max_column = max(self.max_column, len(str(err.column)))
+ self.max_level = max(self.max_level, len(str(err.level)))
+ self.max_message = max(self.max_message, len(err.message))
+
+ def _get_colored_diff(self, diff):
+ if not diff:
+ return ""
+
+ new_diff = ""
+ for line in diff.split("\n"):
+ if line.startswith("+"):
+ new_diff += self.color("green")
+ elif line.startswith("-"):
+ new_diff += self.color("red")
+ else:
+ new_diff += self.term.normal
+ new_diff += self._indent_ + line + "\n"
+ return new_diff
+
+ def __call__(self, result):
+ message = []
+ failed = result.failed
+
+ num_errors = 0
+ num_warnings = 0
+ num_fixed = result.fixed
+ for path, errors in sorted(result.issues.items()):
+ self._reset_max()
+
+ message.append(self.term.underline(path))
+ # Do a first pass to calculate required padding
+ for err in errors:
+ assert isinstance(err, Issue)
+ self._update_max(err)
+ if err.level == "error":
+ num_errors += 1
+ else:
+ num_warnings += 1
+
+ for err in sorted(
+ errors, key=lambda e: (int(e.lineno), int(e.column or 0))
+ ):
+ if err.column:
+ col = ":" + str(err.column).ljust(self.max_column)
+ else:
+ col = "".ljust(self.max_column + 1)
+
+ args = {
+ "normal": self.term.normal,
+ "c1": self.color("grey"),
+ "c2": self.color("red")
+ if err.level == "error"
+ else self.color("yellow"),
+ "lineno": str(err.lineno).rjust(self.max_lineno),
+ "column": col,
+ "level": err.level.ljust(self.max_level),
+ "rule": "{} ".format(err.rule) if err.rule else "",
+ "linter": err.linter.lower(),
+ "message": err.message.ljust(self.max_message),
+ "diff": self._get_colored_diff(err.diff).ljust(self.max_message),
+ }
+ message.append(self.fmt.format(**args).rstrip().rstrip("\n"))
+
+ message.append("") # newline
+
+ # If there were failures, make it clear which linters failed
+ for fail in failed:
+ message.append(
+ "{c}A failure occurred in the {name} linter.".format(
+ c=self.color("brightred"), name=fail
+ )
+ )
+
+ # Print a summary
+ message.append(
+ self.fmt_summary.format(
+ t=self.term,
+ c=self.color("brightred")
+ if num_errors or failed
+ else self.color("brightyellow"),
+ problem=pluralize("problem", num_errors + num_warnings + len(failed)),
+ error=pluralize("error", num_errors),
+ warning=pluralize(
+ "warning", num_warnings or result.total_suppressed_warnings
+ ),
+ failure=", {}".format(pluralize("failure", len(failed)))
+ if failed
+ else "",
+ fixed="{} fixed".format(num_fixed),
+ )
+ )
+
+ if result.total_suppressed_warnings > 0 and num_errors == 0:
+ message.append(
+ "(pass {c1}-W/--warnings{c2} to see warnings.)".format(
+ c1=self.color("grey"), c2=self.term.normal
+ )
+ )
+
+ return "\n".join(message)