 : score-1 ( i full -- n )
     {
         { [ over zero? ] [ 2drop 10 ] }
-        { [ 2dup length 1 - number= ] [ 2drop 4 ] }
+        { [ 2dup length 1 - = ] [ 2drop 4 ] }
         { [ 2dup [ 1 - ] dip nth-unsafe Letter? not ] [ 2drop 10 ] }
         { [ 2dup [ 1 + ] dip nth-unsafe Letter? not ] [ 2drop 4 ] }
         [ 2drop 1 ]

        drop vocabs-matching keys [
            [ vocab-words ] [ vocab-name ] bi ":" append
            [ over name>> append ] curry { } map>assoc
        ] map! concat
    ] [ drop f ] if* ;

: words-matching ( str -- seq )
    [ all-words named ]
    [ qualified-named [ append ] unless-empty ] bi
    completions ;

: chars-matching ( str -- seq )
    name-map keys dup zip completions ;

PRIVATE>

: score ( full fuzzy -- n )
    [
        [ [ length ] bi@ - 15 swap [-] 3 /f ] 2keep
        runs [
            [ 0 [ pick score-1 max ] reduce nip ] keep
            length * +
        ] with each
    ] [
        drop 0
    ] if* ;

: rank-completions ( results -- newresults )
    dup length 25 > [
        [ [ first ] [ max ] map-reduce 4 /f ] keep
        [ first < ] with filter
    ] when sort-keys <reversed> values ;

: complete ( full short -- score )
    [ dupd fuzzy score ] 2keep pick 0 > [
        [ <reversed> ] bi@ dupd fuzzy score max
    ] [ 2drop ] if ;

: completion ( short candidate -- score result )
    [ second swap complete ] keep ; inline

: completion, ( short candidate -- )
    completion over 0 > [ 2array , ] [ 2drop ] if ;

: completions ( short candidates -- seq )
    [ ] [
