Four of the five top hotspots in wezterm are in the ‘fire’ quadrant: structurally complex and recently changed, so they are live regression risks for anyone shipping code this week. I would start with render_to in termwiz/src/render/terminfo.rs: an activity-weighted risk score of 19.38, a cyclomatic complexity of 121, a nesting depth of 8, and a last change 22 days ago. The analysis covers 5,712 functions at commit 3725482, of which 407 land in the critical band and 500 are in the ‘fire’ quadrant.
The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).
Top 5 Hotspots
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
render_to | termwiz/src/render/terminfo.rs | 19.4 | 121 | 8 | 14 |
run_ls_fonts | wezterm-gui/src/main.rs | 19.1 | 39 | 8 | 34 |
do_shape | wezterm-font/src/shaper/harfbuzz.rs | 18.1 | 36 | 7 | 35 |
render_screen_line | wezterm-gui/src/termwindow/render/screen_line.rs | 17.8 | 58 | 5 | 39 |
key | window/src/os/windows/window.rs | 17.6 | 52 | 6 | 24 |
Large Repo Analysis
wezterm is a large repository. To stay within memory constraints, this analysis used hybrid touch mode: structural complexity — CC, ND, FO — is measured precisely for every function. Git activity is tracked at the function level (via git log -L) only for files with 5 or more commits in the touch window (365 days by default); other files use a file-level approximation. Rankings therefore surface functions that are both structurally complex and in the most actively-changing parts of the codebase. Dormant code with high structural complexity will rank lower than it would under a full per-function analysis — to surface it, run hotspots analyze . --per-function-touches on a machine with sufficient memory.
5,712 functions analyzed
Of the 5,712 functions I analyzed, 500 are ‘fire’ (complex and active) and 601 are ‘debt’ (complex and quiet). I would review the ‘fire’ group first, because any change landing there this week passes through code that is already hard to reason about. My top five share the same structural patterns, so what separates them is where each one lives and how recently it moved.
High cyclomatic complexity — many independent execution paths, each a potential bug surface and required test case.Exit Heavy×10Exit Heavy
Multiple return or throw paths dispersed through the body — each exit needs separate test coverage.God Function×10God Function
Calls an unusually large number of distinct functions (high fan-out), making it the structural centre of gravity for a subsystem.Long Function×10Long Function
Function body is too long to review in a single pass; likely contains multiple distinct responsibilities.Deeply Nested×9Deeply Nested
Control structures nested 4+ levels deep, making it hard to reason about the full execution state at inner branches.
All ten of the top functions carry the complex branching, exit-heavy, god function, and long function patterns, and nine of the ten are also deeply nested. That uniformity matters: the problem is a recurring style of large, multi-purpose functions, not a single outlier. None of this says the code is wrong, and the historical signals I have are thin, so I treat these as maintainability and review-priority findings.
render_to — terminfo.rs
This is the top-ranked function, and I would put it first. From the excerpt, it takes a slice of Change values and writes terminal output, with a large match over variants such as ClearScreen, ClearLine, and ClearToEndOfLine. An #[allow(clippy::cyclomatic_complexity, clippy::cognitive_complexity)] attribute sits on the function, so the source already acknowledges the complexity. A cyclomatic complexity of 121 means 121 independent paths, each a potential test case, and a nesting depth of 8 is a strong refactoring signal on its own.
Several arms repeat the same preamble: build default attributes with a background color, compare against the current attributes, flush pending attributes, then clear the pending state. That repetition suggests an extractable helper. The file has two commits in total, no bug-linked commits, no reverts, a bug-fix rate of 0%, and one distinct author in the last 90 days, so the history gives me no reason to read this as a defect cluster. I would extract the per-variant arms into methods, starting with the repeated attribute-reset sequence, and keep the outer match as a thin dispatcher. It was touched twice in the last year and last changed 22 days ago, so the context is fresh and now is a reasonable time to do it.
run_ls_fonts — main.rs
This function implements a font-listing subcommand and lives in the GUI crate’s main.rs. The excerpt shows a long sequence of jobs: checking configuration errors, building a font configuration and render metrics, resolving text from either a text argument or a comma-separated list of hex codepoints, then shaping clusters and resolving fallback fonts. A fan-out of 34 means it directly calls 34 distinct functions, so a change to any of those collaborators can surface here. Cyclomatic complexity is 39, but the nesting depth of 8 is the more striking number.
It was touched three times in the last year and last changed 37 days ago. The file has three commits in total, a bug-fix rate of 0%, and no reverts, so I read this as a maintainability concern rather than a stability one. Input parsing (text versus codepoints) and the shaping-and-reporting loop are natural seams. I would move the codepoint parsing into a function that returns the text, and give the per-cluster shaping and output their own function, which should cut the nesting depth substantially.
do_shape — harfbuzz.rs
Unlike the two above, this one is in the ‘debt’ quadrant, not ‘fire’: it was touched once in the last year and hasn’t changed in 91 days. I would frame it as structural debt with a high blast radius when it is next touched, not as live churn. From the name and the excerpt, it runs text through HarfBuzz shaping with a fallback-font loop, skipping fonts whose presentation doesn’t match the wanted one and recomputing font metrics when size or DPI changes. A fan-out of 35 and a nesting depth of 7 give it broad coupling.
Comments in the excerpt reference two GitHub issues about script inference for Hangul, which tells me some of the branching exists for specific shaping edge cases. I would pin those cases with tests before any refactor. The file has one commit in total and no distinct authors in the last 90 days. I would separate the metrics-recompute block (guarded by the size-and-DPI comparison) from the fallback-iteration loop so each can be tested in isolation. Because the function is quiet right now, this refactor is cheapest before the next feature push.
render_screen_line — screen_line.rs
According to its own doc comment, this function renders one line of the terminal screen into a vertex buffer, and its fan-out of 39 is the highest in my top five. The excerpt shows an early return for double-height bottom lines, scale calculations for double-width and double-height lines, cursor-position logic, and handling for text being composed through dead keys. Cyclomatic complexity is 58 with a nesting depth of 5, so the branching is wide rather than deep.
It is the only one of the five with a non-zero bug-fix rate: 67% across its three commits in the file, with two distinct authors in the last 90 days. The sample is small and none of the commits are tagged as bug-linked or reverted, so I would not read it as proof of a defect. Still, it is the strongest historical signal in my top five, and it comes with three touches in the last year and a last change 19 days ago. That combination gives it the strongest review priority after render_to. I would extract the cursor and composition calculations into a helper that returns a small struct, which removes a chunk of the early-function branching without touching the rendering loop.
key — window.rs
This unsafe fn in the Windows backend handles keyboard messages: the excerpt matches on messages such as WM_KEYDOWN, WM_CHAR, and WM_DEADCHAR, handles IME activity, reads the keyboard state, and builds up a modifiers value. Because it is unsafe and calls into the Win32 API, the complexity numbers likely understate the risk: a cyclomatic complexity of 52 tells me about branching, not about whether every raw call is sound. A comment in the excerpt explains that a RefCell borrow is deliberately dropped before calling translate_message to avoid a borrow conflict, exactly the sort of subtle ordering constraint that makes a function like this fragile to edit.
Pull-request review comment density on the file is 6.5, the highest of my five, so reviewers have clearly spent attention here. The file has two commits, a bug-fix rate of 0%, and one distinct author in the last 90 days. It was touched twice in the last year and last changed 38 days ago. I would split out the modifier-gathering block (the long run of key-state checks that set modifier flags), since it is pure with respect to the message handling, and document the borrow-release ordering with a test or an explicit comment at the call site.
What I would do with this list
The input path keeps surfacing beyond the top five, in keyboard handling across platforms and layers. If I were planning refactoring time, I would treat input handling as one theme and rendering as another, rather than fixing five functions in isolation.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
complex_branching | 10 |
exit_heavy | 10 |
god_function | 10 |
long_function | 10 |
deeply_nested | 9 |
These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.
See more analyses with these patterns: complex_branching, deeply_nested, exit_heavy, god_function, long_function.
Reproduce This Analysis
git clone https://github.com/wez/wezterm
cd wezterm
git checkout 372548295b0b25c9a5400f0ea56f0e89f47e0524
hotspots analyze . --mode snapshot --explain-patterns --force --hybrid-touches 5
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
I use Hotspots to highlight structural and activity risk — not “bad code.” I treat these findings as a prioritization aid, not a bug predictor. Editorial policy →