mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-05-06 12:38:06 +02:00
It's a bit annoying to only find those during a CI pipeline run, so let's add a hook for it. Pre-commit doesn't seem to have something useful for duplicate line detection so let's hack up a quick script that can do this for us, together with the other whitespace checks in the CI so we're consistent. Excluded from the duplicate line checks are anything "Not C" and the "include/" directory since we don't control those files. Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1154>
107 lines
2.8 KiB
Python
Executable file
107 lines
2.8 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
from pathlib import Path
|
|
from dataclasses import dataclass
|
|
|
|
import argparse
|
|
import itertools
|
|
import os
|
|
import sys
|
|
|
|
|
|
@dataclass
|
|
class WhitespaceError:
|
|
message: str
|
|
lineno: int
|
|
nlines: int = 1
|
|
column: None | int = None
|
|
ncolumns: int = 1
|
|
|
|
|
|
def test_duplicate_empty_lines(lines: list[str]) -> list[WhitespaceError]:
|
|
errors = []
|
|
for idx, (l1, l2) in enumerate(itertools.pairwise(lines)):
|
|
if not l1 and not l2:
|
|
errors.append(WhitespaceError("Duplicated empty lines", idx, nlines=2))
|
|
return errors
|
|
|
|
|
|
def test_tab_after_space(lines: list[str]) -> list[WhitespaceError]:
|
|
errors = []
|
|
for idx, l in enumerate(lines):
|
|
index = l.find(" \t")
|
|
if index > -1:
|
|
errors.append(
|
|
WhitespaceError(
|
|
"Tab after space", idx, nlines=index, column=index, ncolumns=2
|
|
)
|
|
)
|
|
return errors
|
|
|
|
|
|
def test_trailing_whitespace(lines: list[str]) -> list[WhitespaceError]:
|
|
errors = []
|
|
for idx, l in enumerate(lines):
|
|
if l.rstrip() != l:
|
|
errors.append(WhitespaceError("Trailing whitespace", idx))
|
|
return errors
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Whitespace checker script")
|
|
parser.add_argument(
|
|
"files",
|
|
metavar="FILES",
|
|
type=Path,
|
|
nargs="+",
|
|
help="The files to check",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
have_errors: bool = False
|
|
|
|
if os.isatty(sys.stderr.fileno()):
|
|
red = "\x1b[0;31m"
|
|
reset = "\x1b[0m"
|
|
else:
|
|
red = ""
|
|
reset = ""
|
|
|
|
for file in args.files:
|
|
lines = [l.rstrip("\n") for l in file.open().readlines()]
|
|
|
|
errors = []
|
|
errors.extend(test_tab_after_space(lines))
|
|
errors.extend(test_trailing_whitespace(lines))
|
|
if any(file.name.endswith(suffix) for suffix in [".c", ".h"]):
|
|
if not file.parts[0] == "include":
|
|
errors.extend(test_duplicate_empty_lines(lines))
|
|
|
|
for e in errors:
|
|
print(f"{red}ERROR: {e.message} in {file}:{reset}", file=sys.stderr)
|
|
print(f"{'-' * 72}", file=sys.stderr)
|
|
lineno = max(0, e.lineno - 5)
|
|
for idx, l in enumerate(lines[lineno : lineno + 10]):
|
|
if e.lineno <= lineno + idx < e.lineno + e.nlines:
|
|
prefix = "->"
|
|
hl = red
|
|
nohl = reset
|
|
else:
|
|
prefix = " "
|
|
hl = ""
|
|
nohl = ""
|
|
print(f"{hl}{lineno + idx:3d}: {prefix} {l.rstrip()}{nohl}")
|
|
|
|
print(f"{'-' * 72}", file=sys.stderr)
|
|
|
|
if errors:
|
|
have_errors = True
|
|
|
|
if have_errors:
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|