Skip to content

feat(editor): rank suggestions and make targets by frecency (#140) - #188

Merged
qwO-Owp merged 1 commit into
developfrom
feat/suggest-frecency
Oct 18, 2026
Merged

qwO-Owp merged 1 commit into
developfrom
feat/suggest-frecency

Conversation

@qwO-Owp

@qwO-Owp qwO-Owp commented Oct 18, 2026

Copy link
Copy Markdown
Member

Part of #140 (PR3c, the last part). It implements the issue's example: with make re run 3 times and make clean most recent, make suggests re.

Ranking

  • Each distinct history line scores Σ 2^16 >> (age/64) over its occurrences in the HELLISH_SUGGEST_MAX window. Ties go to the newest.
  • The ranking drives the ghost, Alt-N/Alt-P order, and make <TAB>: run targets first, the rest alphabetical.
  • HELLISH_SUGGEST_STRATEGY=recent gives the old newest-first order. It's read at every prompt.

Design

  • One primitive (rl_suggest_rank), built by sorting a reused buffer: no hash table, no allocation per key.
  • The per-keystroke fast path is unchanged. A score doesn't depend on the prefix, so a winner that still matches stays the best.
  • readline's match sort is off only for make's own answer, and every completion attempt starts with it on.

Perf fix found in review: ft_qsort (last-element pivot) is O(n²) on runs of identical entries: 6.76 s for one key over 20,000 copies. libc qsort brings it under 1.5 s. Test F13 covers it.

Tests

  • autosuggest F1–F13, plus a randomized model-vs-shell cycle check, on both readers.
  • case_cycle_dupes is the only existing case whose order changes. It's pinned to recent, and a frecent twin is added.
  • make cases 25–29: order, sort-flag restore, recent, user complete spec, -C/-f.
  • frontend budget: 1000 distinct entries plus Backspace gives 6.0 syscalls and 1.1 writes per key (budget 9 and 3). strace ran on the debug and OPT=1 builds.

Mutants: MF1–MF11 (age, frequency, tie, direction, strategy ×2, window, sort flag, make history, cycle order, clean filter) each turn cases red. Every mutant build was checked to compile.

Local gates

Gate Result
make re / OPT=1 / OPT=1 SAFE=1 rc 0
norminette 0 errors
golden suite 5363/5363
pty suite 123 ok / 0 failed / 6 skipped
scripts 129/129
hard corpus 17/17
verify_alloc identical on both heaps
make help-test 0 failed
HELLISH_ALLOC_STATS live bytes flat over 60 rounds

Caveats (in code):

  • H=64 counts entries, not time.
  • make ranking reads words, so make a && make b over-credits, and sudo make x isn't counted.

🤖 Generated with Claude Code

The ghost, Alt-N/Alt-P and `make <TAB>` now prefer what is run often and
lately: each distinct line scores the sum of 2^16 >> (age / 64) over its
occurrences in the HELLISH_SUGGEST_MAX window, ties to the newest.
HELLISH_SUGGEST_STRATEGY=recent restores newest-first; read every prompt.

One ranking primitive (rl_suggest_rank) feeds the ghost and the cycle; it
groups by sort over a reused scratch buffer instead of libft's t_hash,
which strdups every key (per-key malloc churn). The fast path is kept: a
score does not depend on the prefix, so a winner that still matches a
longer line stays the best of the smaller set. make TAB turns readline's
match sort off only for its own answer; every attempt starts with it on.

libc qsort, not ft_qsort: ft_qsort pivots on the last element and is
O(n^2) on runs of identical entries, which arrive already in ranking
order: 6.76 s for one key over 20000 copies (F13 red), under 1.5 s with
qsort.

Tests: autosuggest F1-F13 plus a randomized model-vs-shell cycle check,
case_cycle_dupes pinned to `recent` with a frecent twin (the only existing
case whose order changes), make cases 25-29 (order, sort-flag restore,
recent, user complete spec, -C/-f), frontend budget with 1000 distinct
entries and Backspace: 6.0 syscalls / 1.1 writes per key. Mutants MF1-MF11
(age, frequency, tie, direction, strategy x2, window, sort flag, make
history, cycle order, clean filter) each turn cases red.
@qwO-Owp
qwO-Owp merged commit 7959415 into develop Oct 18, 2026
80 of 81 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant