@@ -0,0 +1,101 @@
3+import subprocess as sp
6+# Threshold speed in chars per second
7+THRESHOLD_SPEED = 20000
9+# Maximum time we allow `bat` to run
12+# Maximum number of files to measure
15+# Root folder for the search
16+SEARCH_ROOT = os.getenv("HOME")
19+def find_slow_files(startup_time, language, glob_pattern):
20+ out = sp.check_output(
34+ paths = out.split(b"\n")[:-1]
35+ print(f"Language: {language}, glob pattern: {glob_pattern} ({len(paths)} matches)")
38+ num_chars = int(sp.check_output(["wc", "-c", path]).split(b" ")[0].decode())
41+ # It is hard to measure the exact speed for short files
46+ sp.check_output(["bat", "--color=always", path], timeout=BAT_TIMEOUT_SEC)
47+ duration = time.time() - start - startup_time
52+ highlighting_speed = num_chars / duration
54+ if highlighting_speed < THRESHOLD_SPEED:
55+ print(f" {highlighting_speed:10.0f} chars/s: {path.decode()}")
57+ except sp.CalledProcessError:
58+ print(f" Error while highlighting file '{path.decode()}'.")
60+ except sp.TimeoutExpired:
61+ if num_chars < THRESHOLD_SPEED * BAT_TIMEOUT_SEC:
62+ print(f" Error: bat timed out on file '{path.decode()}'.")
65+ f" Warning: bat timed out on file '{path.decode()} (but the file is large)."
69+def measure_bat_startup_speed():
74+ ["bat", "--color=always", "--language=py"], stdin=sp.PIPE, stdout=sp.PIPE
76+ p.communicate(input=b"test")
77+ duration = time.time() - start
79+ if not min_duration or duration < min_duration:
80+ min_duration = duration
86+ print("Measuring 'bat' startup speed ... ", flush=True, end="")
87+ startup_time = measure_bat_startup_speed()
88+ print(f"{startup_time * 1000:.1f} ms")
90+ output = sp.check_output(["bat", "--list-languages"]).decode()
92+ for line in output.strip().split("\n"):
93+ language, extensions = line.split(":")
94+ for ext in extensions.split(","):
95+ find_slow_files(startup_time, language, ext)
96+ if not ext.startswith("."):
97+ find_slow_files(startup_time, language, f"*.{ext}")
100+if __name__ == "__main__":