+
    Ej0                     ^    R t R tR tRR ltR tRR ltRRR	R
RR/tR tR tR t	R t
R tR# )u   sshj.fuzzy — subsequence matching + query ranking (leaf).

B2 step 2: moved verbatim from sshj_cli.py (single-file era) — no
behavior change. Pure functions over host dicts; no intra-project
imports.
c                   a \        V4      o\        ;QJ d    V3R lV  4       F  '       d   K   R# 	  R# ! V3R lV  4       4      # )zASubsequence match: every char of needle appears in hay, in order.c              3   ,   <"   T F	  qS9   x  K  	  R # 5iN ).0cits   & src/sshj/fuzzy.py	<genexpr>fuzzy.<locals>.<genexpr>   s     '1Bws   FT)iterall)needlehayr   s   &&@r	   fuzzyr      s5    	cB3''33'3'3''''    c                (   a \        V V3R lRR7      # )zCNewest last-called first (atuin-style); unrecorded keep file order.c                 6   < SP                  V R ,          ^ 4      # aliasget)h	last_useds   &r	   <lambda>#sort_by_last_used.<locals>.<lambda>   s    IMM!G*a$@r   Tkeyreversesorted)hsr   s   &fr	   sort_by_last_usedr"      s    "@   r   Nc                D   aa S;'       g    / o\        V VV3R lRR7      # )u  Newest last SUCCESSFUL connection first (2026-09-21). A host never
successfully connected falls back to its last-used time, then 0 — so a
tried-but-failed host still surfaces in the order it was tried, while a
host that genuinely succeeded last sorts above it.c                 v   < SP                  V R ,          4      ;'       g    SP                  V R ,          ^ 4      # r   r   )r   last_successr   s   &r	   r   &sort_by_last_success.<locals>.<lambda>   s5    L$4$4QwZ$@ %2 %2]]1W:q1%2r   Tr   r   )r!   r%   r   s   &ffr	   sort_by_last_successr'      s)    
 RI" 2;?A Ar   c                    \        V R R7      # )z;Case-insensitive alphabetical by the displayed name (disp).c                 P    V P                  R V R,          4      P                  4       # )dispr   )r   lower)r   s   &r	   r   sort_alpha.<locals>.<lambda>    s    AEE&!G*$=$C$C$Er   r   r   )r!   s   &r	   
sort_alphar.      s    "EFFr   c                v    VR8X  d   \        V 4      # VR8X  d   \        Y;'       g    / V4      # \        W4      # )zThe mode-dispatching base order for the grid's pre-filter list.
'last' (default) = last-called; 'last_success' = last successful
connection; 'alpha' = alphabetical. Unknown modes fall back to 'last'.alphar%   )r.   r'   r"   )r!   moder   r%   s   &&&&r	   
sort_hostsr2   #   s=     w"~~#B(:(:IFFR++r   lastrecentr%   zlast successr0   c                T   V '       g   ^# V P                  4       pVP                  4       p. p^ pV FA  pVR8X  d   K  VP                  We4      pV^ 8  d    ^ # VP                  V4       V^,          pKC  	  V'       g   ^# Rp\        V4       Fj  w  rV^
,          pV^ 8X  d   V	^ 8X  d
   V^,          pV^ 8  d%   WV^,
          ,          ^,           8X  d
   V^,          pV\	        V	^(4      R,          ,          pKl  	  VR,          V^ ,          ,
          ^,           p
WzR,          ,          pV# )a  atuin-style subsequence score. 0 = no match; higher = better.

Rewards prefix hits, contiguous runs, earlier matches and tight
spans. Subsumes fuzzy() (a match is fuzzy_score(n,h) > 0).

Whitespace in the QUERY is ignored (2026-09-21): the space-disables-
keybindings rule means a leading space is common (" j" types a space
then the j), and a space is a perfectly good separator when searching
"user host". Matching on the non-space characters keeps those working.
         g?g?)r+   findappend	enumeratemin)r   r   nlhlposir   scorekpspans   &&         r	   fuzzy_scorerE   2   s    	B	B
C	A8GGAMq5

1	Q  E#6a1fRKEq5Qa!e*q.(QJEQc!!  r7SVaD	CZELr   c           	     n   \        WP                  RR4      4      R,          .pV P                  R4      '       d)   VP                  \        WR,          4      R,          4       V P                  R4      '       d)   VP                  \        WR,          4      R,          4       VP                  \        WP                  RR4      4      R,          4       V Uu. uF  q3^ 8  g   K  VNK  	  ppV'       g   R	# VP                  R
R7       V^ ,          pVR,           F  pWCR,          ,          pK  	  V# u upi )zScore a host against q across name / username / address (B9).

The name (alias) weighs most, then username, then address; a host
whose query hits several fields gets a small additive on top of its
best field. 0 = no field matches.r*    g      @userg       @hostnametargetg      ?r7   T)r   :   NNg      ?)rE   r   r:   sort)r   qcandsr   totals   &&   r	   best_field_scorerP   Z   s     EE&"-.45EuuV}}[fI.45uuZ[jM2S89	LLQh 34s:;'1QQQE'	JJtJ!HE2YYT L (s   D2$D2c                    V  Uu. uF  p\        W!4      V3NK  	  ppV UUu. uF  w  rBV^ 8  g   K  WB3NK  	  pppVP                  R R7       V# u upi u uppi )z(score, host) pairs matching `query`, best first.

Stable on ties, so the caller's input order (last-used) is kept for
equal scores. Empty if nothing matches.c                     V ^ ,          ) # )    r   )ts   &r	   r   query_rank.<locals>.<lambda>w   s
    qter   r-   )rP   rL   )hostsqueryr   scoredss   &&   r	   
query_rankrZ   p   s^    
 8==u!)1-uF=!'11q5fqfF1
KKOK$M >1s   AAAc                d    V'       g   V # \        W4      pV UUu. uF  w  r4VNK	  	  upp# u uppi )zHosts matching the live filter, ranked best-match first (B9).

No query -> unchanged order (already last-used sorted). A query that
matches nothing returns [] (the caller falls back to the full list).)rZ   )rV   rW   ranked_r   s   &&   r	   visible_hostsr^   {   s0    
 %F !&$!A&!!!s   ,c                    VR8X  d   V '       d
   V ^ ,          MR\        V 4      3# \        W4      pV'       d   V^ ,          ^,          MRV UUu. uF  w  rEVNK	  	  upp3# u uppi )a,  B8/B9 direct execution. q == "1" -> the first host (pool must be
last-used sorted: row 1 of the grid = the last connection). Any other
q -> best fuzzy match across name / username / address.

Returns (chosen or None, all matching candidates). Empty candidates =
no match (main() reports and exits 2).1N)listrZ   )poolrM   r   r\   r]   r   s   &&&   r	   direct_selectrc      sW     	CxQTDJ66 F"F1IaLf/Efdaf/EEE/Es   A!r   )__doc__r   r"   r'   r.   r2   SORT_LABELSrE   rP   rZ   r^   rc   r   r   r	   <module>rf      sW   ( AG
, x!%P,"
Fr   